Uh oh!
There was an error while loading. Please reload this page.
fix(docs,gates): the root README joins both doc gates' scan surface, and stops teaching stat-card - #7419
Merged
os-project-manager merged 2 commits intoSep 3, 2026
Conversation
…and stops teaching `stat-card`
The root `README.md` was outside the scan surface of EVERY doc gate.
`check-doc-component-types` walked `content/docs`; `check-doc-snippet-types`
walked `content/docs` plus the package READMEs; the most-read authored file in
the repository fell between the two. It taught `stat-card` four times, in the
flagship "dashboard in JSON" example, and `stat-card` is registered nowhere: a
reader who copied the headline snippet got four OBJUI-001 panels.
Maintainer ruling 2026-09-01 (verbatim 「同意」), in the ruled order:
1. The gate blind spot lands first — 「内容修了不加面就会再烂」.
2. The four widgets become `statistic`, which is registered
(`statistic.tsx:64`) and declares a `value` carriage row, so the example
keeps its expressions rather than degrading to literals.
3. The (A)/(B) fork is ruled B: non-`text` types get NO new carriage rows, and
the docs stop authoring `${…}` in keys that have none — 「文档教现实」.
Red-then-green, because a widened surface can be green about nothing: with
`ROOT_PAGES` added and the content untouched, `check-doc-component-types`
failed on `README.md:290`-`:293` naming `stat-card`; the content fix turned it
green. The same widening on `check-doc-snippet-types` red-flagged nine semantic
diagnostics, which are declared as measured debt in `UNGATED_DOCS` and filed as
objectui#7417 — the ledger names the file instead of the walk missing it.
Beyond the ruling's enumeration, and flagged rather than folded in silently:
`crud` (retired in objectui#5373) and `submit` were the other unregistered types
the widened gate found in the same file, and `card.value` carries no carriage
row. All four are the card's own defect classes in the card's own file; the PR
body names each with its evidence.
Fixes#7115
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyCContributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
…he third gate, found by its own coupling pin `check-doc-fence-languages.test.ts` asserts `fenceDocuments(ROOT)` equals `snippetDocuments(ROOT)` — the fence guard re-implements the snippet gate's walk so it needs NO install, and that pin is what makes a deliberate copy safe. The previous commit widened the snippet gate onto the root `README.md` and left the copy behind, so the pin went red on 223 vs 224 documents. That is the pin doing exactly its job, so it is not touched: the fence guard's surface is widened instead, and its header now STATES the surface (objectui#5174's own finding, applied here as it was to the other two). `ROOT_PAGES` cannot be shared by import — anything imported from `check-doc-snippet-types.mjs` pulls in its `import ts from 'typescript'` at load, and this guard's whole value is running install-free in the unfiltered workflow a docs-only PR starts. So it stays a copy, on the same bargain the document walk and `TS_FENCE_LANGUAGES` already make: copy freely, compare always. All three gates now EXPORT `ROOT_PAGES` and a new pin compares all three, so the shared half cannot drift even where the full surfaces legitimately differ (component-types does not walk the package READMEs). ⭐ The root README needed no fence fix: with it in the walk the guard reports 225 documents and zero findings for it, and the green is not vacuous — un-fencing one of its `tsx` blocks in a census probe produces `README.md:206 language:'' mode: synonym`. The objectui#5867 shrink-only baseline is untouched: no entry added. This makes FOUR gates the root README's blind spot reached, now measured rather than assumed — the card's thesis proving itself a second time. Part of #7115 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
os-project-manager
marked this pull request as ready for review
September 3, 2026 01:06
Uh oh!
There was an error while loading. Please reload this page.
os-project-manager
deleted the
claude/issue-7115-root-readme-doc-gate-surface
branch
September 3, 2026 01:21
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#7115
The root
README.md— the repository's GitHub landing page and the npm page for the workspace, the most-read authored file in it — was outside the scan surface of every doc gate.check-doc-component-typeswalkedcontent/docs.check-doc-snippet-typeswalkedcontent/docsplus the package READMEs. The root README fell between the two, and taughtstat-cardfour times in its flagship "dashboard in JSON" example. Nothing registersstat-card, so a reader who copied the headline snippet got fourOBJUI-001"Unknown component type" panels.The ruling this implements
Maintainer, 2026-09-01, verbatim 「同意」 (comment 5494799307), quoted in the ruled order:
All three parts, one PR (lane's choice, as the ruling permits).
Part 1 — the gate blind spot, proved red-then-green
Widening a scan surface is exactly the change that can be green about nothing, so the widening was landed red first and the evidence is here rather than asserted.
check-doc-component-types(ROOT_PAGES = ['README.md'], joined toscanDocs's file list):The failure that proves the walk reaches the file, verbatim from the run:
Ablation, to show the pins can fail. With the implementation committed, the
files.push(...ROOT_PAGES…)line was deleted (anchored grep1to0, blob6688e098tod0441c22— confirmed on disk before the run, not asserted). The gate went back to 185 files and printed✅ Every documented component type is registered— the exact "green about nothing" state — and both new pins went red with the intended message. Restored withgit checkout HEAD -- ABSOLUTE_PATHunder atrap … EXIT INT TERM, and the restore is verified by state:git diff HEADempty and the blob equal to the HEAD blob, not by an exit code.check-doc-snippet-types— the root README does carry snippets its rules cover (fivetsx/typescriptblocks), so the same proof applies and is not hand-waved. Widening it took the scan set from 224 to 225 documents, and the build closure the gate computes for itself grew by exactly@object-ui/providers— a second, independent signal that the walk now reaches the file. It went red with 9 semantic diagnostics.README.mdis now named inUNGATED_DOCSwith a measured reason, which is that gate's own designed mechanism and the objectui#5174 distinction its header states — a document outside the walk is "neither covered NOR declared ungated", invisible to the gate's own accounting, whereas a ledgered one is named, counted, re-derived every run and shrink-only. Three of the nine are real defects (ObjectRenderer,registerDefaultRenderers,createObjectStackAdapterattributed to the wrong package) and are filed as #7417, with the reason string in the ledger naming that card. Making those blocks compile means resolving two phantom APIs, which is authoring work with an API question inside it — not this card.The third gate —
check-doc-fence-languages, found by its own coupling pin⭐ The ruling named two gates. There are four.
check-doc-fence-languagesre-implements the snippet gate's walk (deliberately, so it needs no install — the snippet gate importstypescript, and an install-gated docs check is one a docs-only PR skips), andcheck-doc-fence-languages.test.tsassertsfenceDocuments(ROOT)equalssnippetDocuments(ROOT). Widening one surface without the other breaks that coupling by construction, and it did: the pin went red at 223 vs 224 documents.The pin was not touched — it is doing precisely the job it was written for, and it is the only reason the third gate was found at all. The fence guard's surface is widened instead, and its header now states the surface where a reader will find it, as objectui#5174's own finding requires.
ROOT_PAGEScannot be shared by import: anything imported fromcheck-doc-snippet-types.mjspulls in itsimport ts from 'typescript'at load, which would install-gate the one gate whose value is running install-free. So it stays a copy, on the bargain the document walk andTS_FENCE_LANGUAGESalready make — copy freely, compare always. All three now exportROOT_PAGESand a new pin compares all three, so the shared half cannot drift even where the full surfaces legitimately differ (component-types deliberately does not walk the package READMEs, so it cannot join the list-equality comparison).The root README needed no fence fix, and that green is not vacuous. With it in the walk the guard reports 225 documents and zero findings for it; the objectui#5867 shrink-only baseline is untouched, with no entry added. Control, through the shipped
census(): un-fencing one of the README'stsxblocks produces{ rel: 'README.md', line: 206, language: '', mode: 'synonym' }, so the file is genuinely parsed and genuinely judged.Four gates, measured rather than assumed
The card's thesis was that the most-read authored file in the repository was checked by nothing. The true number turned out to be larger than the ruling enumerated, which is the thesis proving itself a second time:
check-doc-component-typescheck-doc-snippet-typescheck-readme-exportspackages/NAME/README.mdonly — filed as #7417check-doc-fence-languagesPart 2 — the content fix
The four widgets become
statistic, registered atpackages/components/src/renderers/data-display/statistic.tsx:64. ⭐ A retarget, not a downgrade to literals: measured from the built artifact (expressionBindableTextKeysForout of@objectstack/spec@17.2.0'sdist/ui/index.mjs, the same lookupSchemaRenderer.tsx:1139consumes),statisticcarries[label, value, description], so"value": "${stats.revenue}"keeps evaluating.Two keys moved with the type, because the renderer's real shape is not
stat-card's: it readsschema.label(nottitle), and itstrendis the enumup/down/neutralwith the delta text indescription."trend": "+12%"would have rendered no arrow and no text — 文档教现实 applies to the retarget too.Part 3 — fork ruled B, and no carriage row was added
⛔ Zero carriage rows added. The map lives in
@objectstack/spec(a dependency), and this PR touches neither it norSchemaRenderer.tsx.Every
${…}rewritten, with the measured row set for its node type:content/docs/guide/expressions.md(Percentage Bar)progressvalue75, withvisibleOncarrying the expressioncontent/docs/guide/expressions.md(Percentage Bar)progresslabel:388content/docs/guide/expressions.md(Computed Fields)inputvaluetextnode'scontent, which is evaluated on every typepackages/plugin-dashboard/README.mdmetric-cardvalueobject-*widgets that do read live datapackages/plugin-dashboard/README.mdmetric-cardtrend'up'packages/react/README.mdinputvaluetextnode'scontentOn the card's own second-order note: it recorded, unmeasured, that
metric-cardandinput"likely render the literal${...}". That is now measured — both carry the empty set — but the rendering claim itself was never put in a browser and is not restated here as one.Widening a surface finds what the surface was hiding. Four things surfaced that the ruling's enumeration does not name, because the census behind it was taken before any gate had read this file. Each is stated so a reviewer can drop it on its own.
crud× 2 — a RETIRED type. The widened gate foundREADME.md:137and:264teachingcrud.CRUDSchemaand thecrudnode type were removed in objectui#5373 under ADR-0049;content/docs/api/schema-reference.md:541-:563carries the retirement and an explicit "what to author instead" table, andvalidateSchemaalready returnsRETIRED_TYPEfor the name. The README was teaching a type the platform refuses by name. Retargeted per that table: theUserFormcomparison ontoobject-form, the "Data Grid" example ontoobject-gridwith that schema's real keys (field, notname, as its own doc row insists).submit— not a node type.README.md:256authored"actions": [{ "type": "submit" }]under a form.FormSchema.actionsisSchemaNode[], so this is a rendered node position, andActionSchema.typeis'action'— theauthentication.mdxexemption forsubmitdoes not reach here. The declared key for the built-in submit button issubmitLabel, which is what it now says.card.value× 3 — ruling B, in a site the ruling's census never read. The "Basic Usage" snippet bound${stats.*}incard.value;cardcarries[title, description], sovaluethere is a literal. Retargeted ontostatistic— the same move part 2 ordered, for the same reason.dist/index.d.ts, incl.createObjectStackAdapterattributed to the wrong package #7417 (the root README's snippet debt, pluscheck-readme-exports' identical blind spot) and finding(docs):guide/expressions.mdstill authors${…}in 6 more keys with no carriage row —badge.text/badge.variant/card.className/card.body, beyond the two the 2026-09-01 ruling named #7418 (six more non-carriage${…}inguide/expressions.mdbeyond the two the ruling enumerated).Items 1-3 are the card's own defect classes in the card's own file, and 1-2 are structurally forced: part 1 cannot land green while the file it now reads is red. They are bounded, and each correct form is pinned by evidence already in the tree — nothing here is a judgement call about an API.
Verification
All runs at
02efff4ba, the final commit, with a clean tree.check:doc-typestypeliterals, 787 registeredcheck:doc-snippetscheck:doc-fencesdocs:check-linkscheck:readme-exportscheck:control-bytescheck:pre-install-import-graphchangeset:check+check-changeset-presenceeslint --no-inline-configover the changed lintable filesOn the eslint narrowing, stated so it reads as a measurement rather than a skip: ① the receiving population is read from
eslint.config.jsitself (files: ['**/*.{ts,tsx}']plus narrower overrides;scripts/is not inignores) — the.mjsfiles are outside it and were passed explicitly, so this over-covers; ② the count comes from--format json: 0 errors, 0 warnings; ③eslint.config.jshas zero occurrences ofprojectService/parserOptions/project:(control:languageOptionsmatches once), so type-aware linting is off and no untouched file's verdict can depend on this diff.check:eager-closureis unmoved, and this is structural rather than a byte reading. Locally the gate reports its own precondition — "No eager-closure report atapps/console/dist/eager-closure.json… a broken gauge, not a passing budget" — so it is NOT MEASURED here, not green. What is measured: 0 files in this diff are underapps/**orpackages/*/src/**; the rest arescripts/CI tooling and markdown. No source imports a README or ascripts/file (the only?rawimports in the tree areapps/console/index.htmlinside console tests; control: the same probe overd4c6a86a1lists four realsrc/files). Nothing here is a bundler input. CI confirms it:Bundle Analysisis green on this PR.🤖 Generated with Claude Code
https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC