test(docs): pin command parity for every ci-cd-pipeline.md section by default - #9467
Conversation
… default
`ci-cd-pipeline.md` documents 38 workflows and only 8 of its sections were pinned
against what their workflow actually runs. objectui#8420 priced the rest at ~30
rounds, one section per PR, because the naive sweep flagged 24 of 34 and "a gate
that cries wolf gets switched off rather than fixed".
That ruling does not survive objectui#8420's own follow-up: its census named the
false-positive population, so the exceptions can now be written down and the
default inverted. Measured on origin/main at 38 sections: 21 agree outright, 15
are phantom-only (the page names a command the job does not run, for a stated
reason), and 2 are the direction that hides a gate.
The 2 are repaired on the page rather than declared away:
- `doc-component-types.yml` runs `pnpm check:prompt-keys` in a step of its own
with no `continue-on-error`; the section named neither script nor alias.
- `changeset-presence.yml` grew a second job, `changeset-claims`; the section
documented only the first.
Both landed on 2026-09-11, two days after the census that had put both sections
in its "agrees today, and nothing holds them that way" bucket — which is the
argument for inverting rather than queueing. A section added tomorrow is born
pinned.
Nothing is weakened: `undocumentedCommands` admits no exception at all in the
sweep, the per-job pins keep running unchanged, and the alias rule is applied
verbatim. The one argument-carrying alias (`pnpm governed`) is declared with its
reason and flagged as a decision about the rule, not taken here.
`DECLARED_NON_RUN_COMMANDS` moves to module scope so the sweep re-keys it rather
than growing a second copy of the same four claims.
Refs #9463
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
PM review — verified, ⛔ NOT landed. Seat is being handed over; the next seat lands this.
⭐ What I verified myself, because it is the load-bearing claimThis PR's case is not 「the sweep can be made to work」. It is 「the thirty-round queue would not have caught these」 — and that is measurable: ⇒ both real defects were introduced two days AFTER the census that had classified those very sections as 「agrees today, and nothing holds them that way」. ⭐ The census did not miss them — they did not exist yet. A one-section-per-PR queue thirty deep would have been just as blind. That is the empirical argument for inverting the default rather than queueing, and it is the strongest thing in this PR. Denominator, re-derived on
|
Part of #9463 — the remaining pin appetite for
content/docs/guide/ci-cd-pipeline.md, taken as one PR instead of ~thirty rounds.⛔
Part of, notFixes, deliberately. This PR delivers the card's steps ① and ② in full and makes the fallback in step ③ unnecessary. What it does not deliver is the card's own stop clause: the alias-rule question is reported here, not decided (see the three items under Reported, not decided below). Letting a merge auto-close #9463 would swallow that half, and the inbox filter only reads open cards. Close it once a maintainer has ruled on item 2, or split that into its own card.The card's instruction was to measure the cheaper shape before starting the queue. It is measured, and it holds.
① Census re-derived on today's 38 sections
Counted on
origin/main(f5b9c1797), never on the worktree — the card records a per-container stale-checkout hazard that silently confirms the obsolete "24 of 34"..ymlgrep -cE '^#{1,6} .*\([^]+\.yml)\s*$'ongit show origin/main:…`doc-snippet-types.ymlcarries two headings (its###sub-gate)git ls-tree --name-only origin/main -- .github/workflows/Bijection is exact: no workflow undocumented, no heading naming a file that is gone.
The delta from the census's 36 is 3 added and 1 removed, not "2 new". Net +2, but the list matters:
doc-example-ids.ymlline-citation-gate.ymldependabot-merge-gate.mjs(classifies itNOT_A_GATE) andpnpm census:cross-file-line-citations, of which the page itself says "runs in no workflow"required-check-set-patrol.ymldependabot-merge-gate.mjsas the classifier everypull_requestcheck run must pass, which is its stated reason for having nopull_requestlegstale.ymlRe-derived buckets, 38 total:
Note
already pinnedis 8, not the 5 the card's title says: 5 is thecommandParity()call-site count, and one call site is a.mapover four sections.② The inverted default, measured
38 sections = 21 agree outright + 17 flagged. The 17 split in the only way that matters:
⭐ With the exception table encoded, the residual is 0 — after repairing those 2. That is the card's step 2, and it answers "one PR".
The 2 real defects — repaired on the page, ⛔ not declared away
doc-component-types.ymlrunspnpm check:prompt-keysin a step of its own with nocontinue-on-error— blocking — and the section named neither the script nor the alias. This is objectui#8420'scheck:sdui-registration-pinsshape exactly: a gate that can stop your PR and that you cannot find from the page.changeset-presence.ymlgrew a second job,changeset-claims(report-only); the section documented only the first.⭐ Both landed on 2026-09-11 — two days after the census that had put both sections in its "agrees today, and nothing holds them that way" bucket. The census did not miss them; they did not exist yet. A thirty-deep one-section-per-PR queue would not have caught them either. That is the whole argument for inverting the default rather than queueing: a section added tomorrow is born pinned.
⛔ Gates weakened: NONE
No assertion relaxed, no accept set widened, no blocking check demoted.
undocumentedCommands— the direction that hides a gate — admits no exception at all in the sweep. The existing per-job pins keep running unchanged on top of it. Everything here is added coverage.DECLARED_NON_RUN_COMMANDSmoves to module scope so the sweep re-keys it instead of growing a second copy of the same four claims — the same "two copies of a rule are two rules" move this file already made for the alias rule.## Governed Surface Guardoffers bothpnpm governed -- PATHSandnode scripts/check-governed-queue-guard.mjs --test PATHSas local spellings, while the job runs that script with--self-testand bare. Becausegovernedcarries--test, the settled rule refuses to merge it and it reads as a phantom. It is declared with that reason. Whether an argument-carrying alias should ever merge is a decision about the rule, not about this section — ⛔ not taken here.Verification
pnpm exec vitest run --project unit scripts/__tests__/ci-cd-pipeline-doc.test.ts— exit 0, 80/80.scripts/__tests__— exit 0, 156 files / 4606 tests.tsc -p tsconfig.scripts.json --noEmit— exit 0, and--listFilesproves this test file is in the program (1 hit; control hits 2) rather than silently excluded.check-changeset-presence(its own verdict line: no changeset is owed — doc + test, no published source),check-control-bytes,check-doc-component-types,check-doc-fence-languages,check-doc-links— all exit 0, exit codes captured by redirect-then-capture, never across a pipe.eslint .reports 95 pre-existing errors across 79 files inapps/,packages/,e2e/— none in this diff, andeslint .is not this repo's lint gate (turbo run lintis). The farm is CI's.Ablation — five legs, on-disk mutation proven, restore by hash equality
Every leg:
git hash-objectbefore/after proves the mutation reached disk; restore isgit checkout HEAD -- PATHverified by hash equality and an emptygit diff HEAD; the harness carries atrap … EXIT INT TERMwith absolute paths.check:prompt-keysdoc-component-types.yml: pnpm check:prompt-keys(1 failed / 83)check:changeset-claimschangeset-presence.yml: pnpm check:changeset-claims(1 failed / 83)Tree verified clean at HEAD afterwards.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Generated by Claude Code