Found while implementing objectui#7692 (the bash 3.2 floor gate, which adds a step to lint.yml). Out of scope for that card; filed rather than fixed.
The gap
content/docs/guide/ci-cd-pipeline.md's ## Lint (\lint.yml`)` section describes the job's steps in prose:
scripts/check-lint-coverage.mjs runs first: every package must run ESLint or be declared a known gap. […]
- Then
pnpm lint.
- Then
pnpm check […]
Measured on origin/main 28cfff4 by parsing the workflow and testing each first-party command against that section's text:
command the lint job runs |
named in that section |
scripts/check-lint-coverage.mjs |
yes |
pnpm lint |
yes |
pnpm check |
yes |
scripts/check-entry-guard.mjs |
no |
scripts/check-upstream-port-parity.mjs |
no |
scripts/check-cross-repo-closer-outcome.mjs |
no |
So three blocking gates in a required check run undescribed on the page whose stated job is to tell a contributor which checks can block them. All three predate objectui#7692; that card adds a fourth step and, per its dispatch, does not touch the page (nothing forced a row — see "Why no test caught it").
Positive control for the reading: the same scan, same parser, same section text, reports scripts/check-lint-coverage.mjs, pnpm lint and pnpm check as PRESENT. A zero is not being read off a broken matcher.
Why no test caught it
scripts/__tests__/ci-cd-pipeline-doc.test.ts has exactly the pin this needs — names every first-party command the job actually runs plus its inverse credits no job with a first-party command it does not run — and it is scoped to ONE workflow:
describe('ci-cd-pipeline.md — ci.yml job table', () => {
const ciWorkflow = fs.readFileSync(path.join(workflowDir, 'ci.yml'), 'utf8');
lint.yml is covered only by the workflow-INVENTORY pin, which requires a heading naming the file and nothing about its contents. lint.yml has a heading, so it passes while its step list drifts. That is objectui#3212's shape one level down: the page reads as authoritative about a required gate, and the part that is wrong is the part nothing looks at.
Direction of harm is the one this repository treats as worst — the page UNDERSTATES the gate, so a contributor reading it to find out why Lint is red will not find check-entry-guard or check-upstream-port-parity there at all.
Shape of the fix (not asserted)
Either extend the existing both-directions command pin to lint.yml (the job is a single lint job, so it needs no job-table parse — a section-scoped command set on both sides would do), or move lint.yml's steps into a pinned table the way ci.yml's are. Updating the prose alone repeats the drift, which is the lesson that test file records at length for this same page.
Related but distinct, both on this page and neither covering this: objectui#8006 (the check-skills-paths.mjs description at line 551) and objectui#7965 (three drifted live counts).
Filed unassigned, finding.
Generated by Claude Code
Found while implementing objectui#7692 (the bash 3.2 floor gate, which adds a step to
lint.yml). Out of scope for that card; filed rather than fixed.The gap
content/docs/guide/ci-cd-pipeline.md's## Lint (\lint.yml`)` section describes the job's steps in prose:Measured on
origin/main28cfff4by parsing the workflow and testing each first-party command against that section's text:lintjob runsscripts/check-lint-coverage.mjspnpm lintpnpm checkscripts/check-entry-guard.mjsscripts/check-upstream-port-parity.mjsscripts/check-cross-repo-closer-outcome.mjsSo three blocking gates in a required check run undescribed on the page whose stated job is to tell a contributor which checks can block them. All three predate objectui#7692; that card adds a fourth step and, per its dispatch, does not touch the page (nothing forced a row — see "Why no test caught it").
Positive control for the reading: the same scan, same parser, same section text, reports
scripts/check-lint-coverage.mjs,pnpm lintandpnpm checkas PRESENT. A zero is not being read off a broken matcher.Why no test caught it
scripts/__tests__/ci-cd-pipeline-doc.test.tshas exactly the pin this needs —names every first-party command the job actually runsplus its inversecredits no job with a first-party command it does not run— and it is scoped to ONE workflow:lint.ymlis covered only by the workflow-INVENTORY pin, which requires a heading naming the file and nothing about its contents.lint.ymlhas a heading, so it passes while its step list drifts. That is objectui#3212's shape one level down: the page reads as authoritative about a required gate, and the part that is wrong is the part nothing looks at.Direction of harm is the one this repository treats as worst — the page UNDERSTATES the gate, so a contributor reading it to find out why
Lintis red will not findcheck-entry-guardorcheck-upstream-port-paritythere at all.Shape of the fix (not asserted)
Either extend the existing both-directions command pin to
lint.yml(the job is a singlelintjob, so it needs no job-table parse — a section-scoped command set on both sides would do), or movelint.yml's steps into a pinned table the wayci.yml's are. Updating the prose alone repeats the drift, which is the lesson that test file records at length for this same page.Related but distinct, both on this page and neither covering this: objectui#8006 (the
check-skills-paths.mjsdescription at line 551) and objectui#7965 (three drifted live counts).Filed unassigned,
finding.Generated by Claude Code