Skip to content

Commit c91544a

Browse files
ci: gate steps run their root check:* alias, every check alias has a caller, and check-changeset-fixed gets a --self-test (#26482)
<!-- claude-projects-attribution: {"github_login":"os-steve"} --> _Requested by **Steve** · [project thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi95YovdFSHTxz132KjPG4TAa)_ Fixes #26091 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:`lint.yml` 顶部的 GATE INVOCATION IDIOM 说明改成新规则:门禁步骤跑根 `package.json` 里的 `check:*` 别名。有 7 个门禁的自测原来钉着「`lint.yml` 直接 `node` 调用」,现在改钉两半:步骤调别名,别名的值是先 `--self-test` 再跑门禁。原来没有调用方的 4 个别名,接上了 3 个,删了 1 个。`check-changeset-fixed.mjs` 补了 `--self-test`。 - 为什么改:#26091 Wanted 2 要的是「CI 只有一种调用拼法,`package.json` 是唯一的命令表」。原来的说明写的正好相反,还有 7 个自测把相反的写法钉死了。 - 风险与回滚:门禁一个没删,也没有变弱:每个改动的步骤跑的还是同样的几段命令,只是写进了别名。只有 symbol-anchor 一处换了形状:原来一个收集器步骤跑 4 个自测、后面再跟 3 个扫描步骤,现在是 4 个独立步骤,每步都带 `continue-on-error`,一个红了不会挡住别的。回滚就是 revert。 - 先看:`lint.yml` 第 109 行起的新说明、symbol-anchor 那几步,以及 7 个自测里的 WIRING 断言。 - 两分钟验证:本地跑 `pnpm check:aggregator-roster`、`pnpm check:changeset-fixed`、`pnpm check:adr-symbol-anchors`,都是 exit 0;把 `package.json` 里任一别名的 `--self-test` 去掉,对应的自测就会红。 - 需要你做的:Tier H(改了 `.github/workflows/**`,含 `release.yml`),要 GOVERNED_APPROVERS(os-zhuang 或 hotlong)批准。 ## What changes **The rule (lint.yml's `GATE INVOCATION IDIOM` note, rewritten).** A gate step runs its root `check:*` alias, so `package.json` holds the one definition of the command. A new gate, or one whose step is being rewired, gets a key and CI calls it. A step still runs `node scripts/…` directly in three cases only: - it runs a different invocation from any alias (other arguments, or one leg only); - its job sets up no pnpm; - it predates the rule and has no alias yet. These are not swept (#25919), and each gets an alias when its step is next rewired. The #9465 scope paragraph is kept verbatim, because `check-platform-checklist.mjs` points readers at it. **The pins move, they are not removed.** These seven gates asserted that `lint.yml` invokes `node <self>`. Each now asserts both halves: the `run: pnpm check:<name>` line in `lint.yml`, and the alias value in root `package.json`. Deleting a leg from either side still reds. | Gate | Alias | Step now | |---|---|---| | `check-aggregator-roster` | `check:aggregator-roster` (new) | `pnpm check:aggregator-roster` | | `check-ci-filter-parity` | `check:ci-filter-parity` (new) | `pnpm check:ci-filter-parity` | | `check-doc-frontmatter` | `check:doc-frontmatter` (new) | `pnpm check:doc-frontmatter` | | `check-docs-nav-label` | `check:docs-nav-label` (new) | `pnpm check:docs-nav-label` | | `check-adr-symbol-anchors` | `check:adr-symbol-anchors` | `pnpm check:adr-symbol-anchors` | | `check-scripts-symbol-anchors` | `check:scripts-symbol-anchors` | `pnpm check:scripts-symbol-anchors` | | `check-spec-docblock-symbol-anchors` | `check:spec-docblock-symbol-anchors` | `pnpm check:spec-docblock-symbol-anchors` | The seat named three gates. The census found four with the same `node <self>` pin (`check-docs-nav-label` is the fourth), plus the three symbol-anchor corpora, which pin their lines the same way. **The four aliases with no caller (Wanted 2's second half).** - `check:adr-symbol-anchors`, `check:scripts-symbol-anchors`, `check:spec-docblock-symbol-anchors` are now called. The `run_self_test` collector that ran four self-tests, followed by three bare sweep steps, becomes four steps. Each has its own `id:` and `continue-on-error`, so a red one still hides none of the others. The steps are `pnpm check:symbol-anchors` (new alias: the shared resolver's `--self-test`), then one `pnpm check:<corpus>-symbol-anchors` per corpus (that corpus's self-test, then its sweep). - The three corpus aliases no longer prefix the resolver's self-test. With it bundled in, the resolver's `no-path-population` marker became each corpus family's declaration while the corpus names paths. `dispatch-gates --self-test` reds on exactly that contradiction, and it did in the first gate round. - `check:pm-closed-card-sweep` is **removed**. Its only CI run is in `half-state-patrol.yml`, whose job deliberately sets up no pnpm, and which already runs the same `--self-test` before the sweep. That inline line is now the one definition, and the step's comment says so. No gate goes: the self-test and the sweep both still run. **`check-changeset-fixed.mjs` gets a `--self-test`, the leftover from Wanted 3.** Its 12 cases cover the pure `judge()`: every missing, stale and declared-private rule, red and green. They include the `privatePackages.version` rule and the shipped `PRIVATE_FIXED_MEMBERS` rows. The shape matches `check-node-version.mjs`: a roster floored per row, a pinned roster size, and a verdict handshake. It runs through a new `check:changeset-fixed` alias in `validate-deps.yml` and in both `release.yml` lanes, and both lanes already install pnpm. With every caller on the alias, the script has one gate family, reached on `pull_request` from validate-deps. The first gate round showed that a direct `node` call left behind in `release.yml` becomes a second family, reached only by push or schedule. **Prose that the touched steps made false, and only that:** - the symbol-anchor block comment; - the docs-nav-label pointer; - the route-spelling pointer, which said "same as the frontmatter step above"; - the "Wiring" docblocks of `check-ci-filter-parity.mjs` and `check-doc-frontmatter.mjs`; - the half-state-patrol comment that named the removed alias; - one example in the issue-citations comment that named the removed alias. The other pointer comments ("invoked as `node` rather than through a `pnpm check:*` alias: see the GATE INVOCATION IDIOM note") sit on steps whose scripts have no alias. They stay accurate under the new note, which names that case, so they are left as they are (#25919). ## Tests - **#26091 acceptance.** - Root `check:*` keys with no caller in any workflow, hook, `scripts/` file or other `package.json` script: 4 on `main`, **0** here. - `for f in scripts/check-*.mjs; do grep -q -- --self-test $f || echo $f; done` prints `scripts/check-changeset-fixed.mjs` on `main`, and **nothing** here. - **Every touched alias, run locally the way CI runs it:** `check:aggregator-roster`, `check:ci-filter-parity`, `check:doc-frontmatter`, `check:docs-nav-label`, `check:symbol-anchors`, `check:adr-symbol-anchors`, `check:scripts-symbol-anchors`, `check:spec-docblock-symbol-anchors`, `check:changeset-fixed`. All exit 0. - **Negative controls.** - With `--self-test` removed from `check:doc-frontmatter`, its self-test fails on `wiring: root package.json's check:doc-frontmatter runs the --self-test leg, then the gate`. - With the `check:adr-symbol-anchors` alias changed, its self-test fails with the alias named. - In `check-changeset-fixed`, disabling the `privatePackages.version` rule reds its case, and emptying `stale` reds 3 cases. - **The step census.** It counts steps whose inline `node` lines equal a root alias byte for byte. The result is 2 on `main` and 2 here: the two install-free jobs, which the note names. - **Gate run, standard order.** `dispatch-gates --commands` derived 77 commands for this diff on the merged tree (`44a3660e`, after `main` at `67461403`, which includes #26419). All 77 exit 0. `dispatch-gates --ran` reports 77 derived, 77 run, 0 NOT-MEASURED, 0 UNRUN. The first round on the pre-fix tree reded `check:pm-dispatch-gates` (2 of 1901 cases). The two causes are the ones described under the symbol-anchor and changeset-fixed bullets above, and both are fixed here. <details><summary>Gate log (77 commands, exit code and seconds)</summary> ``` 0 2s node scripts/check-closing-keyword-parity.mjs 0 5s node scripts/check-closing-keyword-parity.mjs --self-test 0 193s node scripts/check-comment-mask-corpus.mjs 0 0s node scripts/check-declaration-mirrors.mjs 0 0s node scripts/check-declaration-mirrors.mjs --self-test 0 0s node scripts/check-dts-emitted.mjs --self-test 0 1s node scripts/check-merged-branch-reaper-outcome.mjs 0 0s node scripts/check-merged-branch-reaper-outcome.mjs --self-test 0 0s node scripts/check-osv-exemptions.mjs 0 0s node scripts/check-osv-exemptions.mjs --self-test 0 2s node scripts/check-self-test-wired.mjs 0 5s node scripts/check-self-test-wired.mjs --self-test 0 125s node scripts/check-self-test-workflow-commands.mjs 0 4s node scripts/check-self-test-workflow-commands.mjs --self-test 0 0s node scripts/check-step-collectors.mjs 0 5s node scripts/check-step-collectors.mjs --self-test 0 2s node scripts/check-whole-set-label-write.mjs 0 0s node scripts/check-whole-set-label-write.mjs --self-test 0 0s node scripts/ci/assert-turbo-remote-cache.mjs --self-test 0 0s node scripts/ci/plan-test-core-shards.mjs --self-test 0 0s node scripts/ci/prune-turbo-cache.mjs --self-test 0 1s node scripts/ci/scheduled-full-run.mjs --self-test 0 1s node scripts/docs-audit/check-drift-comment.mjs 0 0s node scripts/osv-base-relative.mjs --self-test 0 30s node scripts/pm/bare-root-worklist.mjs --self-test 0 0s node scripts/pm/ci-failure.mjs --self-test 0 0s node scripts/pm/sweep-closed-cards.mjs --self-test 0 1s node scripts/release-dist-tags.mjs --self-test 0 7s node scripts/release-verify-npm.mjs --self-test 0 8s pnpm check:adr-symbol-anchors 0 3s pnpm check:agent-test-spelling 0 3s pnpm check:aggregator-roster 0 2s pnpm check:bash32-floor 0 1s pnpm check:changeset-fixed 0 1s pnpm check:ci-filter-parity 0 17s pnpm check:cli-command-ids 0 33s pnpm check:cross-package-test-inputs 0 36s pnpm check:declared-population-live 0 2s pnpm check:doc-frontmatter 0 1s pnpm check:docs-nav-label 0 5s pnpm check:driver-memory-census 0 1s pnpm check:dts-closure 0 22s pnpm check:dual-build-cjs-loads 0 38s pnpm check:entry-guard 0 1s pnpm check:gitlink-declared 0 3s pnpm check:lean-entry-closure 0 1s pnpm check:manifest-repository-directory 0 23s pnpm check:merge-driver 0 1s pnpm check:node-version 0 4s pnpm check:nul-bytes 0 1s pnpm check:override-consistency 0 4s pnpm check:parse-guard 0 376s pnpm check:pm-dispatch-gates 0 5s pnpm check:pm-expected-skips 0 10s pnpm check:pm-governed-merges 0 1s pnpm check:pm-post-stamped 0 4s pnpm check:pm-record-recognisers 0 1s pnpm check:pnpm-acquisition 0 3s pnpm check:pnpm-filter-targets 0 6s pnpm check:pnpm-flag-spellings 0 4s pnpm check:ratchet-remedy-authority 0 23s pnpm check:refd-timer-probe 0 4s pnpm check:required-contexts 0 8s pnpm check:scripts-symbol-anchors 0 4s pnpm check:select-gate-families 0 3s pnpm check:shard-attestation 0 1s pnpm check:sourcemap-no-sources-content 0 10s pnpm check:spec-docblock-symbol-anchors 0 2s pnpm check:stall-guard-budget 0 4s pnpm check:stall-guard-headroom 0 1s pnpm check:turbo-task-graph 0 5s pnpm check:type-check-coverage 0 358s pnpm check:type-check-debt 0 12s pnpm check:vendor-export-contract-resolve 0 6s pnpm check:watch-hint-literal 0 2s pnpm check:workflow-status-functions 0 1s pnpm check:workflow-step-name-quoting ``` </details> ## Acceptance notes - Wanted 2's literal text, "never `node scripts/<file>` directly", is read through the note's three cases. CI still has about 60 direct `node scripts/check-*` lines, for 33 scripts with no alias. Converting them all means adding 33 keys and touching `ci.yml` (out of bounds for this claim) and nine other workflows. Under #25919 they move when their steps are next rewired. The rule, the pins and the acceptance numbers above are what this card asked to be true. - No gate is removed or weakened. One alias is removed (`check:pm-closed-card-sweep`), and every command it ran still runs in CI. The symbol-anchor reshaping keeps every self-test and sweep, each in its own step. - `ci.yml` is not touched, and no `ui/` path is touched. ## Verification ```sh for a in aggregator-roster ci-filter-parity doc-frontmatter docs-nav-label symbol-anchors adr-symbol-anchors scripts-symbol-anchors spec-docblock-symbol-anchors changeset-fixed; do pnpm -s check:$a > /dev/null 2>&1; echo "$? check:$a"; done for f in scripts/check-*.mjs; do grep -q -- --self-test $f || echo $f; done # prints nothing ``` Tier H (`.github/workflows/**`, including `release.yml`): draft until a GOVERNED_APPROVERS approval (os-zhuang, hotlong). --- _Generated by [Claude Code](https://claude.ai/code/session_01ADHkmQq9EYQdTQwmRutQTS)_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01ADHkmQq9EYQdTQwmRutQTS --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent cc0d77b commit c91544a

13 files changed

Lines changed: 334 additions & 147 deletions

‎.github/workflows/half-state-patrol.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,8 @@ jobs:
356356
# The judge's own cases first, and the sweep only if they hold: this
357357
# step WRITES to other people's cards, and a broken predicate that
358358
# still runs is the one failure mode that cannot be undone by the next
359-
# run. `check:pm-closed-card-sweep` is the same command under a dev
360-
# -facing name; this is the invocation CI holds.
359+
# run. It has no root alias: this job sets up no pnpm, so this line is
360+
# the one definition (the GATE INVOCATION IDIOM note in lint.yml).
361361
set +e
362362
node scripts/pm/sweep-closed-cards.mjs --self-test > "$RUNNER_TEMP/closed-cards-selftest.log" 2>&1
363363
selftest=$?

‎.github/workflows/lint.yml‎

Lines changed: 58 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -108,48 +108,40 @@ concurrency:
108108
# ─────────────────────────────────────────────────────────────────────────────
109109
# ⭐ GATE INVOCATION IDIOM — stated ONCE, here. The steps below point at it.
110110
#
111-
# Most gate steps in this file run their script directly:
111+
# A gate step runs its root `package.json` alias:
112112
#
113-
# run: node scripts/check-<thing>.mjs
113+
# run: pnpm check:<thing>
114114
#
115-
# rather than through a `pnpm check:*` alias. That is a deliberate in-repo
116-
# idiom with its own justification, not a workaround:
115+
# so `package.json` holds the one definition of the command, and a fix to the
116+
# alias is a fix to CI (#26091, #26086). A gate that is new, or whose step is
117+
# being rewired, gets a `check:*` key and CI calls that key. The gates that pin
118+
# their own wiring (check-aggregator-roster, check-ci-filter-parity,
119+
# check-doc-frontmatter, check-docs-nav-label, check-system-context-census)
120+
# assert both halves in their self-tests: this file runs `pnpm check:<thing>`,
121+
# and the root alias is exactly `--self-test` then the gate. So the step and the
122+
# alias cannot drift apart without a red.
117123
#
118-
# * Many gate steps in this file already use it — it is the local precedent.
119-
# * `scripts/pm/dispatch-gates.mjs` derives gate families from EITHER
120-
# spelling, so the direct form loses no discovery.
121-
# * It adds no key to the root manifest.
122-
# * It is pinned rather than incidental: check-aggregator-roster,
123-
# check-ci-filter-parity and check-doc-frontmatter each assert in their own
124-
# self-test that `node <self>` appears in THIS file, so silently rewiring
125-
# one of them to an alias reddens its gate.
124+
# A step still runs `node scripts/…` directly in three cases, and only these:
126125
#
127-
# ⚠️ It is NOT because root `package.json` is off limits. This file used to say
128-
# that, in one shape or another, at nineteen separate sites, and it is FALSE.
129-
# The declared territory of the #9465 @changesets/cli v3 lane inside that file
130-
# is scoped by the lane's own parenthetical, verbatim from the issue body:
126+
# * it runs a DIFFERENT invocation from any alias: other arguments
127+
# (`--base "$MERGE_BASE"`, `--advisory`, `--census`), or one leg only (the
128+
# self-test half of a gate whose scan runs elsewhere). An alias is a copy
129+
# only when it is the same command, and a copy is what this rule removes;
130+
# * its job sets up no pnpm (an install-free job elsewhere, such as
131+
# check-links.yml or board-snapshot.yml, keeps the direct form);
132+
# * it predates this rule and its script has no alias yet. Those steps are
133+
# not swept (#25919 「存量不横扫」); each gains an alias when its step is
134+
# next rewired. Their comments say "invoked as `node` rather than through a
135+
# `pnpm check:*` alias" and point here.
131136
#
132-
# root `package.json` (the `@changesets/cli` range and the `version` script)
137+
# `scripts/pm/dispatch-gates.mjs` derives gate families from either spelling,
138+
# so neither form loses discovery.
133139
#
134-
# That parenthetical is SCOPING, not illustrative: one dependency range and one
135-
# script key. It does not cover the file, and it does not cover a new `check:*`
136-
# key — so adding `check:<thing>` to the root manifest would have been allowed
137-
# all along. The steps below take the direct form on the merits listed above;
138-
# they are not fenced out of the alternative.
139-
#
140-
# Stated once here, and POINTED AT rather than restated, because the over-broad
141-
# reading propagates by copying — measured, not supposed. A dev agent wrote the
142-
# same sentence into a new comment and a new script's docblock and said plainly:
143-
# "I copied the phrasing from neighbouring comments instead of checking it."
144-
# The count was 15 sites when #10894 was filed on 2026-08-21 and 19 by
145-
# 2026-08-24, four of them added AFTER the card was filed and two of those
146-
# within ninety minutes of it being picked up. Nineteen CORRECTED copies would
147-
# re-arm the identical mechanism: a claim that reads as verified because it
148-
# reads exactly like the verified ones beside it. So there is one statement of
149-
# this idiom — this one — and every step refers to it.
150-
#
151-
# Changing this note? It is prose, and no gate can red on a wrong sentence
152-
# here; that is precisely how nineteen wrong ones accumulated. Check any claim
140+
# ⚠️ Root `package.json` was never off limits. The #9465 @changesets/cli v3
141+
# lane's territory in that file is one dependency range and one script key,
142+
# verbatim from that issue: root `package.json` (the `@changesets/cli` range
143+
# and the `version` script). A new `check:*` key was always allowed; the
144+
# opposite reading once spread to nineteen comments by copying. Check any claim
153145
# about the #9465 fence against #9465's own body before you write it down.
154146
# ─────────────────────────────────────────────────────────────────────────────
155147

@@ -1818,9 +1810,7 @@ jobs:
18181810
- name: Docs frontmatter parses
18191811
id: docs-frontmatter-parses
18201812
continue-on-error: true
1821-
run: |
1822-
node scripts/check-doc-frontmatter.mjs --self-test
1823-
node scripts/check-doc-frontmatter.mjs
1813+
run: pnpm check:doc-frontmatter
18241814

18251815
# The docs site's short sidebar label (`navTitle`) reaches the PAGE TREE
18261816
# and nothing else (#12311). A doc page's `title` serves the SERP title,
@@ -1845,15 +1835,12 @@ jobs:
18451835
# an upgrade does the gate says migrate instead of letting ours become the
18461836
# thing nobody migrated.
18471837
#
1848-
# Invoked as `node` rather than a `pnpm check:*` alias: see the GATE
1849-
# INVOCATION IDIOM note at the top of this file. Filesystem read plus one
1850-
# type-stripped import; sub-second.
1838+
# Runs its root alias, per the GATE INVOCATION IDIOM note at the top of
1839+
# this file. Filesystem read plus one type-stripped import; sub-second.
18511840
- name: Docs nav label stays out of the title surfaces
18521841
id: docs-nav-label-stays-out-of-the-title
18531842
continue-on-error: true
1854-
run: |
1855-
node scripts/check-docs-nav-label.mjs --self-test
1856-
node scripts/check-docs-nav-label.mjs
1843+
run: pnpm check:docs-nav-label
18571844

18581845
# #13548 tenant-audit census. `content/docs/permissions/tenant-audit-census.mdx`
18591846
# carries the population `SqlDriver.auditMissingTenant` acts on: every
@@ -2024,9 +2011,9 @@ jobs:
20242011
# job's check-run is advisory with no signal anywhere (#5617), while a
20252012
# failing step here is read by everyone — and enforcement later needs
20262013
# only the flag flip, not a Settings change.
2027-
# Invoked as `node` rather than a `pnpm check:*` alias, same as the
2028-
# frontmatter step above: see the GATE INVOCATION IDIOM note at the top of
2029-
# this file.
2014+
# Invoked as `node` rather than a `pnpm check:*` alias (it has none yet,
2015+
# and its scan runs `--advisory`): see the GATE INVOCATION IDIOM note at
2016+
# the top of this file.
20302017
- name: Route spellings taught in prose match the ledgers (advisory)
20312018
id: route-spellings-taught-in-prose-match
20322019
continue-on-error: true
@@ -2418,69 +2405,36 @@ jobs:
24182405
# #13788 (1,647 platform-checklist citations) joins by registering its own
24192406
# corpus — ⛔ not by forking the resolver.
24202407
#
2421-
# Invoked as `node` rather than a pnpm alias per the GATE INVOCATION IDIOM
2422-
# at the top of this file; the gate's own --self-test asserts BOTH lines
2423-
# below are present, so rewiring it silently reddens it.
2424-
#
2425-
# ⚠️ The two self-tests go through a `run_self_test` COLLECTOR, not a bare
2426-
# sequence. Under `bash -e` the first non-zero exit aborts the step, so a
2427-
# chained second self-test is neither green nor red — it never runs
2428-
# (#10814). The collector runs both unconditionally and fails at the end
2429-
# naming every one that broke.
2430-
#
2431-
# ⛔ AND THE PRODUCTION SWEEP IS A SEPARATE STEP, which is not cosmetic.
2432-
# `check-step-collectors` drives this very block under a real `bash -e`
2433-
# with a STUB planted at each collected command's script path, and holds
2434-
# "all green => every command runs" as an equality. A trailing
2435-
# `node scripts/check-adr-symbol-anchors.mjs` in the same block re-invokes
2436-
# that same stub, so the harness counts 3 executions against 2 collected
2437-
# commands and the gate reds (3/2) — which is exactly what it did here.
2438-
# Both existing collectors in this file carry self-tests ONLY, for the
2439-
# same reason. Keep the sweep out of the collector block.
2440-
- name: Symbol-anchor gate self-tests
2441-
id: symbol-anchor-gate-self-tests
2442-
continue-on-error: true
2443-
run: |
2444-
failed=""
2445-
run_self_test() {
2446-
echo "-- $*"
2447-
if "$@"; then
2448-
echo "PASS $*"
2449-
else
2450-
echo "FAIL $*"
2451-
failed="${failed} $*"$'\n'
2452-
fi
2453-
return 0
2454-
}
2455-
run_self_test node scripts/symbol-anchors.mjs --self-test
2456-
run_self_test node scripts/check-adr-symbol-anchors.mjs --self-test
2457-
run_self_test node scripts/check-scripts-symbol-anchors.mjs --self-test
2458-
run_self_test node scripts/check-spec-docblock-symbol-anchors.mjs --self-test
2459-
if [ -n "$failed" ]; then
2460-
echo ""
2461-
echo "Symbol-anchor self-tests — the following FAILED:"
2462-
printf "%s" "$failed"
2463-
exit 1
2464-
fi
2408+
# Every step here runs a root alias, per the GATE INVOCATION IDIOM note at
2409+
# the top of this file: `pnpm check:symbol-anchors` is the shared
2410+
# resolver's `--self-test`, and each `pnpm check:<corpus>-symbol-anchors`
2411+
# is that corpus's own `--self-test`, then its sweep. One step each, each
2412+
# with an `id:` and `continue-on-error`, so a red one never hides the
2413+
# others — the job the `run_self_test` collector that used to hold the
2414+
# four self-tests did (#10814). Each corpus gate's own --self-test asserts
2415+
# its step and its alias, so rewiring one silently reddens it. The
2416+
# resolver keeps its own step and alias because it declares no path
2417+
# population of its own (its `dispatch-gates: no-path-population` marker)
2418+
# while every corpus does.
2419+
- name: Symbol-anchor resolver self-test
2420+
id: symbol-anchor-resolver-self-test
2421+
continue-on-error: true
2422+
run: pnpm check:symbol-anchors
24652423

24662424
- name: ADR symbol anchors resolve (no line numbers survive)
24672425
id: adr-symbol-anchors-resolve-no-line-numbers
24682426
continue-on-error: true
2469-
run: node scripts/check-adr-symbol-anchors.mjs
2427+
run: pnpm check:adr-symbol-anchors
24702428

24712429
# The SECOND corpus (#15765), and it is a `defineCorpus` registration over
2472-
# `scripts/**` comment prose — ⛔ not a second resolver. Its own sweep is a
2473-
# separate step for the same `check-step-collectors` reason stated above:
2474-
# a production sweep inside the collector block re-invokes the stub the
2475-
# harness plants and the count comes out 4/3.
2430+
# `scripts/**` comment prose — ⛔ not a second resolver.
24762431
- name: scripts/** symbol anchors resolve (no line citations on tracked targets survive)
24772432
id: scripts-symbol-anchors-resolve-no-line
24782433
continue-on-error: true
2479-
run: node scripts/check-scripts-symbol-anchors.mjs
2434+
run: pnpm check:scripts-symbol-anchors
24802435

24812436
# The THIRD corpus (#17065) — `packages/spec/src/**` doc blocks, again a
2482-
# `defineCorpus` registration and ⛔ not a second resolver. Separate sweep
2483-
# step for the same `check-step-collectors` reason stated above.
2437+
# `defineCorpus` registration and ⛔ not a second resolver.
24842438
#
24852439
# ⭐ Its exit contract is a PINNED DAY-ONE RESIDUAL, not a clean tree: the
24862440
# census (7 findings across 6 of 1,317 files, taken in reporting mode
@@ -2492,7 +2446,7 @@ jobs:
24922446
- name: packages/spec/src/** doc-block symbol anchors resolve (no NEW line citations on tracked targets)
24932447
id: packages-spec-src-doc-block-symbol-anchors
24942448
continue-on-error: true
2495-
run: node scripts/check-spec-docblock-symbol-anchors.mjs
2449+
run: pnpm check:spec-docblock-symbol-anchors
24962450

24972451
# NOTE: the standing platform test checklist (docs/qa/platform-checklist/)
24982452
# is validated by `pnpm check:platform-checklist`, but by MAINTAINER
@@ -3429,9 +3383,7 @@ jobs:
34293383
- name: Aggregator roster gate
34303384
id: aggregator-roster-gate
34313385
continue-on-error: true
3432-
run: |
3433-
node scripts/check-aggregator-roster.mjs --self-test
3434-
node scripts/check-aggregator-roster.mjs
3386+
run: pnpm check:aggregator-roster
34353387

34363388
# Rationale: `scripts/ci/lane-verdict.mjs` header (#23191). The verdict
34373389
# every lane above and below ends with reads each gate's `outcome`, never
@@ -3562,9 +3514,7 @@ jobs:
35623514
- name: CI filter parity (cross-package Layer C)
35633515
id: ci-filter-parity-cross-package-layer-c
35643516
continue-on-error: true
3565-
run: |
3566-
node scripts/check-ci-filter-parity.mjs --self-test
3567-
node scripts/check-ci-filter-parity.mjs
3517+
run: pnpm check:ci-filter-parity
35683518

35693519
# The READING half of the gate above (#10046). `--union-into` appends the
35703520
# cross-package scans to the `turbo ls` document ci.yml is about to shard,
@@ -4039,7 +3989,7 @@ jobs:
40393989
#
40403990
# ⛔ The manifest alias is NOT the verdict. It runs `--self-test` and
40413991
# nothing else — the shape every credential-needing gate in this manifest
4042-
# uses (`check:pm-half-states`, `check:pm-closed-card-sweep`), because a
3992+
# uses (`check:pm-half-states`, for one), because a
40433993
# live mode needs a board and a credential. Wiring the alias ALONE would
40443994
# run the self-test twice and scan nothing. Both spellings are here on
40453995
# purpose, self-test first: `check-self-test-wired` requires CI to run the

‎.github/workflows/release.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ jobs:
299299
# (the publish lane runs it again — a gate on one lane is not a gate on
300300
# the other).
301301
- name: Verify Changesets "fixed" group covers every public package
302-
run: node scripts/check-changeset-fixed.mjs
302+
run: pnpm check:changeset-fixed
303303

304304
# ══════════════════════════════════════════════════════════════════════
305305
# POST-VERSION VALIDATION — THE ONLY GATE THE RELEASE COMMIT EVER PASSES
@@ -1816,7 +1816,7 @@ jobs:
18161816
${{ runner.os }}-turbo-${{ github.job }}-
18171817
18181818
- name: Verify Changesets "fixed" group covers every public package
1819-
run: node scripts/check-changeset-fixed.mjs
1819+
run: pnpm check:changeset-fixed
18201820

18211821
# ──────────────────────────────────────────────────────────────────────
18221822
# ⛔ TOMBSTONE — no objectui pin is read, built or checked here, and none

‎.github/workflows/validate-deps.yml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ jobs:
6161
with:
6262
install-args: --prefer-offline
6363

64+
# Through its root alias, so its --self-test runs first (#26091).
6465
- name: Verify Changesets "fixed" group covers every public package
65-
run: node scripts/check-changeset-fixed.mjs
66+
run: pnpm check:changeset-fixed
6667

6768
# pnpm overrides pin what THIS workspace resolves, but they do not ship
6869
# with published packages — downstream installs see only the declared

0 commit comments

Comments
 (0)