Skip to content

gate(scripts): widen the expression-carriage census to check:doc-types' surface (objectui#7878) - #8105

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-7878-expression-carriage-census-surface
Sep 6, 2026
Merged

gate(scripts): widen the expression-carriage census to check:doc-types' surface (objectui#7878)#8105
baozhoutao merged 2 commits into
mainfrom
claude/issue-7878-expression-carriage-census-surface

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes #7878

The report-only expression-carriage census landed (PR #7868) with its population pinned to content/docs, while its two sibling doc gates had already been widened onto the per-app docs trees (#6600) and the root pages (#7115). This widens it to exactly the surface check:doc-types walks — content/docs, every apps/*/docs tree, and ROOT_PAGES — and re-verifies PR #7868's four properties on the new population.

Report-only is unchanged: exit 0 on findings, exit 1 only when the instrument is broken. No predicate change, no exit-code change, no ci.yml change (the step invocation is untouched).

⚠️ Premise correction — this does NOT reach docs/ARCHITECTURE.md

The card says the widening "brings docs/ARCHITECTURE.md and the root README into the census". It does not, and this is a correction to the card's premise, not a scope choice. Re-derived on this branch:

So the widened surface gains the root README.md and the apps/*/docs trees, and nothing else. Option C (every tracked markdown file) was rejected on the card and is not implemented.

The surface is imported, not copied

APP_DOCS, appDocsDirs and ROOT_PAGES are now imported from check-doc-component-types.mjs, so the two walks are the same objects rather than two arrays a test hopes are equal. The three gates that carry copies do so for a stated reason that does not apply here — check-doc-snippet-types pulls in typescript at load, and check-doc-fence-languages must run with no install. check-doc-component-types.mjs imports node built-ins plus invoked-as.mjs, the same four this gate already imported. (regenerate-known-schema-types.mjs already imports that module, so cross-gate import is established here.)

DOCS_ROOT is the one leg still spelled locally, because that gate declares it const rather than export const and this card's file surface does not extend to that file. It is pinned against that file's source text, so the enumeration and the reading come from different places.

Cross-check on this head: check:doc-types reports Scanned 188 doc file(s); this census reports Scanned 188 file(s).

The census, alongside the content/docs figure

All three readings taken on this branch; the first two differ only by population, so the split below is exact rather than estimated.

files fences parsed UNPARSED nodes ${…} sites carried uncarried
59df1dab2 baseline (from the card) 184 204 204 0 359 66 49 17
unwidened, on base 1f0f51d48 184 204 204 0 361 64 61 3
widened, on ace6fd56c 188 209 209 0 375 68 65 3

Delta attribution — the two movements, separated:

  • Corpus churn since 59df1dab2 (row 1 → row 2, population held at content/docs): files 0, fences 0, nodes +2, sites −2, carried +12, uncarried −14. The entire headline movement is churn — the class's open cards repairing their own sites, which is what report-only was for.
  • The new directories (row 2 → row 3, same commit, population widened): files +4, fences +5, nodes +14, sites +4, carried +4, uncarried +0, unparsed +0.

Per new document: apps/console/docs/deployment.md 1 fence, README.md 4 fences; apps/console/docs/UI_IMPROVEMENT_PROPOSAL.md and apps/console/docs/error-tracking.md contribute 0. All 4 new expression sites are carried, so the widening adds zero findings today.

⚠️ A small delta is a finding, not a failure — and it was predicted: check-doc-component-types joined the same trees at zero present yield and said so in its own header. The argument is forward: #7115 is the card where the root README.md fell BETWEEN two gates' surfaces and taught an unregistered component type four times, for exactly one reason — nothing read the file. Leaving this gate pointed away from a tree its two siblings read rebuilds that geometry in the same gate family.

Summary line printed on this head:

Scanned 188 file(s) across content/docs, apps/*/docs and README.md: 209 json/jsonc fence(s), 209 parsed, 0 UNPARSED (1 parsed as an object body).
375 node(s) with a string `type`; 68 ${…} site(s) on those nodes, 65 of them carried.
By fence language: json 203 (203 parsed, 0 unparsed); jsonc 6 (6 parsed, 0 unparsed)

The surface label is spelled with a glob star rather than an angle-bracket placeholder on purpose: this line is quoted into pull-request bodies and issue comments, and GitHub's body sanitizer eats tag-shaped fragments.

PR #7868's four properties, re-verified on the widened population

  1. Both halves stay DERIVED. Untouched. Channels still come from SchemaRenderer.tsx's own call sites, the carriage map from the built @objectstack/spec dist/ui/index.mjs. Either matching nothing is still exit 1, and the two pins that prove it still pass.
  2. 0 UNPARSED, per fence language, on the widened set. json 203 (203 parsed, 0 unparsed); jsonc 6 (6 parsed, 0 unparsed). Dialect blind-spot probe kept and still reports none — the 4 new documents contributed 0 unparsed and 0 out-of-set JSON-like fences.
  3. "A hit is a CANDIDATE, not a verdict" still printed under every findings list; unchanged.
  4. Controls re-armed against the new population. The fixture tree now carries the same planted defect on every leg (guide tree, an apps/*/docs tree, a root page) and asserts all three are found; a population-sabotage test removes the two new legs and requires exactly the two new findings to disappear. Two new relative controls run against the real widened corpus: dropping visibleOn or content from the channels must report strictly more sites, and emptying the carriage map must report strictly more. ⛔ No finding count is pinned — that would make this gate blocking through the back door.

Reverse verification — each new control proven able to fail

Every ablation ran from the committed implementation, mutated on disk with the change proven by counting the anchor text in both directions, restored with git checkout HEAD -- PATH, and confirmed restored by an empty git diff HEAD. Each script carried a trap on EXIT INT TERM.

ablation anchor before → after result
A — narrow the walk back to content/docs app-docs leg 1→0, root-pages leg 1→0, marker 0→1 5 tests red (surface equality, leg reach, three-leg fixture, population sabotage, walk order)
B — revert the ci-cd-pipeline surface clause widened clause 1→0, old clause 0→1 1 test red (the wiring pin on that row)
C — analyze ignores the injected channels injection site 1→0, marker 0→1 1 test red ("still notices a dropped channel on the widened corpus")
D — analyze ignores the injected carriage injection site 1→0, marker 0→2 2 tests red ("still notices an emptied carriage map on the widened corpus", plus the orphan control)

After all four, git status clean and the suite back to 37/37.

The docs row of content/docs/guide/ci-cd-pipeline.md

#3653 pins that table by command, so the row is owed in the same change. Only the surface clause moved — the posture sentence, the exit-code sentence, the docs-links.yml history and everything else in the row are byte-identical. ci-cd-pipeline-doc.test.ts (44 tests) passes; the gate's own wiring pin now also requires the row to name all three legs.

Scope

Three files, exactly the dispatched surface: scripts/check-doc-expression-carriage.mjs, scripts/__tests__/check-doc-expression-carriage.test.ts, and one row of content/docs/guide/ci-cd-pipeline.md. No .github/workflows/ci.yml, no packages/**, no docs/**, no content/docs/releases/.

Changeset: none owed. node scripts/check-changeset-presence.mjs on this head: 3 file(s) changed, 0 of them published source of a package the release covers … no changeset is owed. Clause ② confirmed no — report-only census, no published export, no existing gate's predicate touched. check-governed-queue-guard --test on all three paths: NOT GOVERNED.

Gates, all on ace6fd56c

Exit codes captured by redirect-then-capture, never through a pipe.

gate exit reading
node scripts/check-doc-expression-carriage.mjs 0 census above; Controls pass; Blind spot: none
vitest run scripts/__tests__/check-doc-expression-carriage.test.ts 0 37 passed (was 24)
vitest run scripts/__tests__/ci-cd-pipeline-doc.test.ts 0 44 passed
vitest run scripts/__tests__/ 0 112 files, 3353 passed
pnpm type-check:scripts 0
pnpm lint:root 0 full root scan, not narrowed: 32 warnings, 0 errors, none on the changed files
pnpm check:doc-fences 0 227 documents
node scripts/check-doc-links.mjs 0 17 scan roots
pnpm check:control-bytes 0 6479 tracked text files
manual control-byte scan of the 3 changed paths 1 (no hits) grep -naP over the escape class
pnpm check:doc-types 0 188 doc files — the surface cross-check
pnpm check:unreferenced-sources 0
pnpm check:pre-install-import-graph 0 26 modules walked, every non-relative leaf a node builtin
pnpm check:self-import, check:esm-specifiers 0
node scripts/check-changeset-presence.mjs 0 no changeset owed
node scripts/check-governed-queue-guard.mjs --test 0 NOT GOVERNED

⚠️ pnpm check:node-esm-load exits 1 in this worktree with only 2 entries evaluated on ERR_UNKNOWN_FILE_EXTENSION for .css files inside react-grid-layout and maplibre-gl. That is an unbuilt-workspace precondition, not a reading about this change: it grades built package artifacts, and this diff touches no package source. Live E2E (informational) is red on every branch today for an upstream reason (#7990) and is not this change's.

Back-links, no closing keywords: #7851 · PR #7868 · #7838 / PR #7859 · #7856 · #3653 · #7115 · #6600 · #7872.


Generated by Claude Code

…s' surface (objectui#7878)

The report-only census landed (PR #7868) pointed at `content/docs` alone, while
its two sibling doc gates had already been widened onto the per-app docs trees
(#6600) and the root pages (#7115). That is the #7115 geometry rebuilt one gate
over: the root `README.md` fell between two gates' surfaces and taught an
unregistered component type four times, for exactly one reason -- nothing read
the file.

The surface is now imported from `check-doc-component-types.mjs` rather than
copied: `APP_DOCS`, `appDocsDirs` and `ROOT_PAGES` are the same objects, so there
is nothing to drift. `DOCS_ROOT` stays spelled here (that gate declares it
`const`, not `export const`) and is pinned against that file's source text.

Report-only is unchanged: exit 0 on findings, exit 1 only when the instrument is
broken. No predicate, exit-code or ci.yml change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr

Copy link
Copy Markdown
Contributor Author

Standing down on Live E2E (informational): that check is red on main itself today (base-red, anchored on objectui#7990 / objectstack-ai/objectstack#16186), it is informational (not required), and this PR changes a report-only census script, its pin file and one row of a docs page — nothing the live lane exercises. No fix is ported because none exists yet upstream. The flip to ready happens only once every non-informational check on ace6fd56c is green.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants