Skip to content

feat(scripts): point the three doc gates at apps/*/docs (#6600) - #7449

Merged
os-sales merged 2 commits into
mainfrom
claude/issue-6600-doc-gate-scan-roots
Sep 3, 2026
Merged

feat(scripts): point the three doc gates at apps/*/docs (#6600)#7449
os-sales merged 2 commits into
mainfrom
claude/issue-6600-doc-gate-scan-roots

Conversation

@os-sales

@os-sales os-sales commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes #6600

Step 2 of maintainer ruling D on #6600 (2026-09-02, verbatim 「同意」, recorded by the director seat). Step 1 was the content change, landed as PR #7425 (39af82f).

The three documentation gates all rooted their walk at content/docs — plus, for two of them, packages/NAME/README.md and the root README.md. None descended into apps/, so apps/console/docs/** was read by no documentation gate at all. The only check whose surface contained those files was check:control-bytes, which enumerates git ls-files and therefore covers every tracked text file: the console's operator guides were checked for control bytes and for nothing else.

check:doc-fences and check:doc-snippets move together because check-doc-fence-languages.test.ts pins their document lists deep-equal — that coupling is mechanical, not a convention. check:doc-types joining was the one judgement the ruling delegated to this lane; the reasoning is below and is written into that gate's header.

What moved

gate before after
check:doc-fences — documents 225 228
check:doc-snippets — documents 225 228
check:doc-snippets — covered / ungated 193 / 32 196 / 32
check:doc-snippets — covered blocks 563 577
check:doc-snippets — compiled / declared fragments 417 / 146 421 / 156
check:doc-types — doc files 186 189
check:doc-types — code blocks 1090 1115
check:doc-typestype literals 922 922

The acceptance criterion the ruling set, met verbatim: check:doc-snippets judges the apps/*/docs/** blocks and reports 0 failed (421 of 421 block(s) judged, 0 failed), with the fragment blocks counted as declared fragments (+10) rather than skipped files; no UNGATED_DOCS growth (32 → 32); the three gate headers state their scope and agree with their roots.

UNGATED_DOCS and the fences shrink-only baseline are byte-identical to main, asserted rather than eyeballed — same SHA-256 for the extracted block in both cases, and KNOWN_UNHIGHLIGHTED_TS_FENCES still reports the same 80 files / 90 blocks.

⚠️ Three of the four newly-compiled blocks are green about nothing — #7426

This is stated here rather than absorbed into the green, because this card exists precisely because a gate suite reports green over a file it never opened, and shipping a gate that reports green over blocks it cannot fail is the same defect wearing the fix's clothes.

Of the 4 blocks that become live-compiled in this tree, 3 are design-token lists under "Visual Design Specs" in apps/console/docs/UI_IMPROVEMENT_PROPOSAL.md (Color Palette, Typography, Spacing). They compile only because background: "bg-background" parses as a labelled statement whose body is a string-literal expression — syntactically legal, semantically empty. So three quarters of this tree's new semantic coverage is vacuous.

That is not a prediction. It is demonstrated in leg A2 of the ablation below: replacing background: "bg-background" with background: "ABLATION_6600_this_is_not_typescript_at_all" leaves check:doc-snippets green (exit 0), while the same class of defect in the one genuine block turns it red.

#7426 remains open and is the right home for it — re-fencing is a document-shape change and that card records the fence target (plain text vs. a markdown table) as undecided, which makes it domain:ui's judgement call. ⛔ The three blocks were deliberately not marked doc-snippet: fragment: that marker asserts a block cannot compile, which is false here, and it would drop them from real coverage. Out of scope for this PR: #7426.

Non-vacuity — each moved gate proven to actually judge the new population

A root that moves while the walk still misses the files passes every green check and buys nothing. Each leg plants a deliberate defect in an apps/*/docs/** block, proves the mutation reached disk before the run (HEAD blob hash != worktree blob hash, plus a marker grep -c), then restores with git checkout HEAD -- ABSOLUTE_PATH and proves the restore (blob == HEAD blob and empty git diff HEAD). The script carries trap … EXIT INT TERM. The mutated subject is markdown the gate reads by path at runtime, not an artifact resolved through a package dist/, so no rebuild leg applies; the packages the snippet gate compiles against were unchanged and already built.

leg planted defect gate exit verdict line
A1 const ABLATION_6600: number = "not a number"; in the genuine compiled block check:doc-snippets 1 TS2322 at UI_IMPROVEMENT_PROPOSAL.md:174; 421 of 421 block(s) judged, 1 failed
A2 same class of defect in a design-token block check:doc-snippets 0 421 of 421 block(s) judged, 0 failed — the #7426 vacuity, demonstrated
B interface ABLATION_6600 { under a bare fence in deployment.md check:doc-fences 1 deployment.md:21 — bare fence, no info string, body interface ABLATION_6600 {
C { "type": "ablation-6600-unregistered" } in a fenced block check:doc-types 1 [unregistered-doc-type] type 'ablation-6600-unregistered' (tsx)

Final tree state after all four legs: git diff HEAD empty.

Why check:doc-types joined, at zero present yield

Stated plainly because the alternative reading — that a widened scope was justified by a discovery — is false: the three files carry 0 type literals today, and the count is unchanged at 922 after the move. This gate finds nothing on the day it lands.

The argument for joining anyway is the split-surface defect this exact gate was already burned by once. In #7115, check-doc-component-types walked content/docs; check-doc-snippet-types walked content/docs plus the package READMEs; the root README.md fell between the two and was read by neither — and it taught the unregistered type stat-card four times, in the flagship example, for as long as that example existed. Leaving this gate pointed away from a tree its two siblings now read would rebuild that geometry deliberately, in the same gate family. And UI_IMPROVEMENT_PROPOSAL.md is a proposal about console UI shape, i.e. the file in that tree most likely to grow the first type literal.

⛔ This is not a precedent for widening onto any other unscanned tree, and no allowlist mechanism is built — the population is three files.

Scope statement, not scope expansion

The ruling asked for the ownership of the unscanned markdown to be written into the gate headers as a statement of what the roots are. The full ownership map lives once in check-doc-snippet-types.mjs beside UNGATED_DOCS (widest surface, holds the ledger); the other two headers state their own roots and point at it.

Measured for that statement rather than inherited: the unscanned population is 114 files excluding the ephemeral .changeset/ — not the "roughly 50" the ruling's prose carries — the largest groups being non-README .md under packages/** (54), docs/** (17) and the published skills/objectui/** (16). The header gives the re-derivation command rather than relying on that number, matching the fix this repo already applied to UNGATED_DOCS's own header.

No gate is widened onto skills/**. It is named in the map as unclaimed, which is the opposite of a claim: a governed, published surface whose coverage is a decision for whoever owns it, never a side effect of a root move. Writing an unscanned tree down is what keeps it a known debt rather than #5174's "neither covered NOR declared ungated".

Pins added

scripts/__tests__/check-doc-fence-languages.test.ts gains three, in the shape #7115 established and check-doc-component-types' header demands of anything added later:

  • all three gates carry the same APP_DOCS constant (mirrors the existing ROOT_PAGES tri-gate pin);
  • the three guides are really in the walk by name — the deep-equality assertion does not cover this, since both walks could drop the tree together and stay equal, which is exactly the state this card was filed about;
  • the walk takes one app-directory level and does not descend into apps/site/app/docs, a Next.js route directory holding .tsx route files.

Verification

Run from the repo root at eba0a9b7a, tree clean, exit codes captured by redirect before any pipe:

  • pnpm check:doc-fences0228 document(s), baseline unchanged at 80 files / 90 blocks
  • pnpm check:doc-snippets0421 of 421 block(s) judged, 0 failed
  • pnpm check:doc-types0Every documented component type is registered.
  • pnpm check:control-bytes0 — 6131 tracked text files
  • pnpm exec vitest run over check-doc-fence-languages, check-doc-snippet-types, check-doc-component-types plus every other test that names these scripts (check-pre-install-import-graph, one-authority-per-exported-name-6273, known-schema-types-derivation-5115, report-namespace-agreement-6416) → 7 files, 196 tests, all passing
  • pnpm lint (full repo, not narrowed) → 0 — 47/47 tasks, 0 errors

The three gate workflows carry no paths filter by deliberate design — their own tests fail if one is added — so the moved roots are exercised on every pull request, including the docs-only shape that would otherwise skip them.

Changeset

Empty-frontmatter changeset: these are gate scan roots, and scripts/** publishes nothing. skip-changeset is not used — ci-cd-pipeline-doc.test.ts pins it as a phantom label in this repository. Precedent followed: .changeset/7086-blockquoted-fence-collector.md.

Out of scope

🤖 Generated with Claude Code

https://claude.ai/code/session_019aCUUSwWefnbCJ4Xk1vqQW


Generated by Claude Code

The three documentation gates all rooted their walk at `content/docs` (plus,
for two of them, the package READMEs and the root `README.md`). None descended
into `apps/`, so `apps/console/docs/**` — the console's operator and deployment
guides — was read by no documentation gate at all. The only check whose surface
contained those files was `check:control-bytes`, which enumerates `git ls-files`
and therefore covers every tracked text file: they were checked for control
bytes and for nothing else.

`check:doc-fences` and `check:doc-snippets` move together because
`check-doc-fence-languages.test.ts` pins their document lists deep-equal.
`check:doc-types` joins them so that the tree is not left in the split-surface
geometry objectui#7115 was filed about, where a file fell between two gates'
differing roots and was read by neither.

No `UNGATED_DOCS` entry is added and no allowlist mechanism is built; both
shrink-only ledgers are byte-identical to `main`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019aCUUSwWefnbCJ4Xk1vqQW
@github-actions github-actions Bot added the tests label Sep 3, 2026
…#6600)

The first draft of the ownership map stated the unscanned markdown population
as 114 files. The re-derivation command the same block ships answers 111, at
both `origin/main` and this branch: the 114 counted the three
`apps/<app>/docs/` guides that this very pull request brings under the gates.

Rather than correct 114 to 111, this removes every hand-copied count from the
block — the total and the per-tree ones alike. A number in a header drifts from
the tree and nothing fails when it does, which is objectui#7448 exactly, and
which `UNGATED_DOCS`'s own header already records happening to its `12 .mdx
pages and 32 package READMEs` sentence. The trees are now named in descending
order of size, which is the ownership statement the ruling asked for, and the
command is left as the durable answer to both "how many" and "which".

Comment-only: no code line changes, and all three gates report identical
numbers before and after.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019aCUUSwWefnbCJ4Xk1vqQW
@os-sales
os-sales marked this pull request as ready for review September 3, 2026 06:08
@os-sales
os-sales added this pull request to the merge queue Sep 3, 2026
Merged via the queue into main with commit fda1247 Sep 3, 2026
31 checks passed
@os-sales
os-sales deleted the claude/issue-6600-doc-gate-scan-roots branch September 3, 2026 06:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants