Skip to content

Commit 6b83ec2

Browse files
ci(lint): run check:liveness in the required source-gates lane on every change (#31559)
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} --> _Requested by **Steedos** · [project thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9UbbGJxVR6gZPrpPRHctVZA2h9)_ Part of #31518 Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么**:在必跑的 `Type Check · source gates` 检查里加了一步 `pnpm --filter @objectstack/spec check:liveness`,每个 PR 和每个合并队列条目都会跑,不再按路径过滤。 - **为什么改**:spec 的属性台账会引用全仓库的源码文件。只改了被引用文件(比如 objectql 的 engine.ts)的 PR,原来的检查要么没被触发,要么从 turbo 缓存直接回放成绿色;上周 #30341 带着红色的台账检查合进了 main,#30716 在队列里红了两次。 - **风险与回滚**:风险低。这一步只读源码,不需要 build,约 4 秒;判定逻辑一行没改。回滚就是删掉这一个 step。 - **先看**:`.github/workflows/lint.yml` 里新增的 step 和它上面的注释。 - **两分钟验证**:在当前 main 上跑 `pnpm --filter @objectstack/spec check:liveness`,应该退出 0;再看下面"Verification"里 #30341 和 #30716 的树上它退出 1 的记录。 - **需要你做的**:这是 Tier H 的 workflow 改动,请你手动合并;`spec-liveness-check.yml` 的去留留给 seat 决定(见下方 Follow-ups)。 ## What changes One step is added to the `typecheck-source-gates` job (`Type Check · source gates`) in `.github/workflows/lint.yml`: ```yaml - name: Check every spec liveness citation still names its property id: check-spec-liveness-citations continue-on-error: true run: pnpm --filter @objectstack/spec check:liveness ``` It follows the lane's existing shape. The step carries `continue-on-error: true` and an `id:`, and the job's `Lane verdict` step reads its outcome from `toJSON(steps)`, so a red here reds the lane. The lane has no `paths:` filter. Its only `if:` skips a scheduled run that a green push run already covers, so the step runs on every `pull_request` and every `merge_group`. The required `TypeScript Type Check` aggregate already depends on this job, so no required context is added or dropped. The command and its logic are unchanged. `spec-liveness-check.yml` is untouched. ## Why Step 1 on #31518 classed 68 red merge-queue roots from 2026-11-01..07. Class (b), "not selected on the PR", had 6 roots and 23 cascades. Four of those roots are this one shape: the spec property-liveness ledger (`packages/spec/liveness/`) cites evidence files across the whole tree, and a PR that only moves code in a cited file makes a citation stale without either existing runner catching it. - `Spec property liveness` (`spec-liveness-check.yml`) is scoped by `paths:` to the spec side on `pull_request` and is not a required context. Its red `merge_group` run does not stop the entry from landing. In the window, #30341, #30353, #30351 and #30298 landed with that run red, and #30341 left main failing the command until #30368. - `check-liveness.test.ts` runs inside `@objectstack/spec:test`, whose turbo hash covers spec inputs only. #30716's PR run replayed `spec:test` from the cache (hash `09ab3604`) and went green; its queue entry missed the cache (`86ebed7f`) and went red, twice. The command reads source through tsx and needs no build. At the current head it exits 0 in about 4 s with `dist/` absent. ## Verification Proof method: **reproduction on scratch detached worktrees**. For each tree, a detached worktree was checked out, `pnpm install --frozen-lockfile` was run, and the lane's exact command was run. Each red tree is paired with its parent as a CONTROL. | Tree | What it is | Exit | Stale citation | |---|---|---|---| | `f672e0dc5` | #30341's landed tree | 1 | `query/searchFields` → `packages/objectql/src/engine.ts` | | `8589756a` | its parent (CONTROL) | 0 | none | | `198d1125` | #30716's queue entry | 1 | `manifest/contributes.kinds` → `packages/objectql/src/engine.ts` | | `dc5217d8` | that entry's queue parent (CONTROL) | 0 | none | | `3e387e33` | #30716's PR head | 1 | `manifest/contributes.kinds` | The last row is the card's CONTROL shape. #30716's PR head fails the command, while its PR run was green because `spec:test` was a cache hit and `Spec property liveness` was not scheduled. With this step, that PR run would have gone red on the PR instead of in the queue. <details><summary>Failing output (all three red trees print the same shape)</summary> ``` ✗ 1 'live' / 'planned' / 'experimental' / 'live-elsewhere' citation(s) name a file that never names the property: manifest/contributes.kinds → packages/objectql/src/engine.ts ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL @objectstack/spec@18.3.0 check:liveness: `tsx scripts/liveness/check-liveness.mts` Exit status 1 ``` </details> <details><summary>Current head: green with no build</summary> ``` ✓ every governed-type property, at every depth the ledger drills, is classified, … ✓ packages/spec/liveness/state-counts/ is current — one shard per governed type, the same 44 row(s) as the README, no count column left in the README. ``` </details> **Derived gates.** `node scripts/pm/dispatch-gates.mjs --commands` derives 42 families for this diff. All 42 were run and exited 0, and `--ran` reconciles them: 42 derived, 42 run, 0 NOT-MEASURED. `node scripts/ci/lane-verdict.mjs --self-test` (31 cases) and the lane command itself were also run green. After main was merged, the derivation is unchanged; the merge brought in no workflow file. **Family row.** None is added to `dispatch-gates.data.mjs`. `check:liveness` is already a discovered family (a change to `packages/spec/scripts/liveness/check-liveness.mts` derives `pnpm --filter @objectstack/spec run check:liveness`), and the derivation's own roster gates (`check:pm-dispatch-gates`, `check-step-collectors`, `check:aggregator-roster`, `check:required-contexts`) are green with the new step in place. ## Other classes from step 1 - **(a) stale base**: 21 roots and 122 cascades, the largest class. It is not a CI-side fix. It is filed as #31548 (domain:skills), an enqueue-time refresh. - **(b) dogfood**: the 2 remaining (b) roots are the ruled two-speed design, so there is no change there. - **(c) flake**: 36 roots and 5 cascades. These are covered by #30785, #30555, #31284, #31312, #22034/#31429, #31213 and #31195. - **(d) genuine**: 0 roots. ## Follow-ups - **For the seat: retire or keep `spec-liveness-check.yml`.** Its `check:liveness` step is now a duplicate of this one. The workflow also runs `check:empty-state`, `check:variant-docs` and `check:strictness-ledger`, which this PR does not move. This diff leaves it as it is. - A local derivation gap remains. `dispatch-gates` derives `check:liveness` for a change under `packages/spec/` but not for a change that touches only a cited file, such as `packages/objectql/src/engine.ts`. CI now catches that case on the PR, so a dev who skips it locally gets a red on the PR rather than in the queue. ## Re-reading (7 days after this lands) Repeat step 1's method over the 7 days after this merges. Expect class (b) liveness roots to drop to 0. When classing, count a red as a **cascade, not a root, if its nearest red ancestor failed the same test**. A `merge_group` entry selects Test Core and Test UI by `git diff base_sha HEAD`, and `base_sha` is the entry directly ahead, so an entry behind a red one does not re-run the red one's test. A one-hop rule therefore labels some transitive cascades as roots (5 roots and 7 cascades in step 1). ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (No schema is touched.) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran. (Only a workflow file changes, so there is no source for `pnpm lint` to judge.) - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. (Nothing publishes: `skip-changeset`.) - [x] 6. `packages/spec` touched: its generated artifacts are regenerated and committed. (Not touched.) - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English. - [x] The *Before Submitting* list in CONTRIBUTING.md is done. --- _Generated by [Claude Code](https://claude.ai/code/session_01QsR2jVWeBc5ThsX5K8ymDr)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 02996c1 commit 6b83ec2

1 file changed

Lines changed: 22 additions & 0 deletions

File tree

‎.github/workflows/lint.yml‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5210,6 +5210,28 @@ jobs:
52105210
continue-on-error: true
52115211
run: pnpm --filter @objectstack/spec check:meta-url-spelling
52125212

5213+
# [#31518] The spec property-liveness ledger (packages/spec/liveness/)
5214+
# cites evidence files across the whole tree — packages/objectql,
5215+
# packages/runtime, ui/ and more — so a change that touches only a cited
5216+
# file can make a row stale. The two other places this command runs did
5217+
# not stop that from landing. `Spec property liveness`
5218+
# (spec-liveness-check.yml) is scoped by `paths:` to the spec side on
5219+
# pull_request and is not a required context, so its red merge_group run
5220+
# rides through the queue. The `local` vitest project's
5221+
# check-liveness.test.ts runs under `@objectstack/spec:test`, whose turbo
5222+
# hash does not cover the cited files, so a pull request that only moves
5223+
# code in a cited file replays it from the cache. Measured 2026-11-01..07:
5224+
# #30341 landed with its `Spec property liveness` queue run red, and
5225+
# main's tree failed this command until #30368; #30716's PR run replayed
5226+
# `spec:test` from the cache and its queue entry went red twice. This
5227+
# lane is unfiltered and required, so the same command now runs on every
5228+
# pull_request and merge_group. It reads source via tsx, needs no build,
5229+
# and takes about 4 s.
5230+
- name: Check every spec liveness citation still names its property
5231+
id: check-spec-liveness-citations
5232+
continue-on-error: true
5233+
run: pnpm --filter @objectstack/spec check:liveness
5234+
52135235
# The two ADR-0087 D4 projections, under the #22449 B′ ruling. They are
52145236
# generated where they ship — at publish, by scripts/release-spec-changes.sh,
52155237
# which also verifies the packed copies against a fresh generation — so

0 commit comments

Comments
 (0)