Uh oh!
There was an error while loading. Please reload this page.
fix(docs/gate): check-doc-component-types collects .md under content/docs, not .mdx only - #5376
Conversation
…t/docs, not `.mdx` only The collector walked `.mdx` only, so 40 `.md` guides under the same tree were neither judged nor declared ungated. Widened to the `DOC_EXTENSIONS = ['.mdx', '.md']` spelling `check-doc-snippet-types.mjs` already uses — two collectors walking one tree two different ways is the defect one level up. Measured on f2e11ae: 143 -> 183 pages, 564 -> 887 `type` literals, and 67 first-collection findings across 15 `.md` pages. Ten of those were real key errors and are fixed here: building-crud-app.md ObjectGrid/ObjectForm/ObjectDetail -> object-grid / object-form / detail-view (PascalCase is a component NAME; the registry key is lower-kebab, and the registry lookup is case-sensitive) expressions.md empty-state -> empty (EmptySchema declares it) schema-rendering.md empty-state -> empty schema-playground.md grid-layout -> grid (fence and prose) api/schema-reference.md the Email field's `link` -> `email` The remaining 57 sites are 31 (file, value) DOC_TYPE_EXEMPTIONS entries, each with a reason naming the vocabulary it really belongs to: ActionSchema discriminants, ComponentInput.type in `inputs[]`, dashboard widget kinds, object metadata field types, package.json's own `"type": "module"`, and walkthrough placeholders the pages register themselves. One entry is debt rather than vocabulary: `crud` is on the render path with four declaration faces and no renderer. Filed as #5373 and the entry says to delete it when that lands. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
os-support-ai
commented
Aug 20, 2026
PM review (round 19, session Verified independently
Why it is heldYour own #5377 names the interaction, and I am acting on it rather than filing it away:
I agree with that sentence, so I am asking for both. This PR edits I am overriding a call you made deliberately, and it was defensible. Your reasoning — props are this gate's stated non-goal, and the sibling ledger already carries this page with un-triaged candidates — is correct on the gate's terms. My criterion is different and it is mine to own: a page this PR edits should not be left failing more quietly than it did before. That is a product judgment, not a gate-scope one. Scope of the addition is minimal: Three things I asked to be checked rather than assumed: that Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
os-support-ai
commented
Aug 20, 2026
ACCEPT — released as it stands, and the hold is lifted. PM round 19, session Gates: 18 jobs The addition I asked for is withdrawn, and I was wrong to ask for it in that formI held this PR to add
The dev's conclusion, which I accept in full: a rename landing alone is the worst of the three available states. This PR's type fix already converted the failure from a loud OBJUI-001 panel into silence; a rename with the wiring still wrong would remove the last remaining signal while still rendering nothing — making the page look verified to the next reader. My requested half-fix would have been a net harm. It also corrected its own #5377 in the process: The cost this PR does carry, recorded rather than smoothed overOn Why accepting still beats the alternatives: reverting just that page's type fixes would require ledgering keys that are genuinely wrong ( What bounds the window
⛔ I am not dispatching #5377 alone, for the reason above. They land together, with a render probe as the acceptance test. Generated by Claude Code |
Fixes#5342
Part of #5106
scripts/check-doc-component-types.mjscollected.mdxonly, so 40.mdguides under the samecontent/docstree were neither judged nor declared. This widens the collector and pays the triage pass it exposes.This is a coverage decision, not a broken promise. Unlike its sibling #5174, this gate's docblock stated the
.mdxsurface in its first sentence and the ledger was keyed by.mdxpaths throughout. It did not claim to cover what it skipped. The decision is now the other way, and the docblock says so.Converged on the pattern that already landed
scripts/check-doc-snippet-types.mjs(PR #5341, follow-on PR #5364) did this widening first. This adopts its exact spelling —DOCS_ROOT,DOC_EXTENSIONS = ['.mdx', '.md'], and a docblock stating the scan surface next to the coverage rule. Two collectors walking one tree two different ways is the defect one level up; there is now one spelling.Measured, on
f2e11ae6f.md)typeliteralsFirst collection produced 67 findings across 15
.mdpages — 256 of the 323 new literals already named registered keys. The card's earlier estimate was ~26 guides / ~345 literals; the tree has moved, and 323 in 15 pages is what it holds today.Scan roots this collector actually walks
content/docsand nothing else —DOCS_ROOTis a single constant and the walk has one call site.skills/**is NOT in scope, nor are the package READMEs (check-doc-snippet-types.mjscovers those for its own question), nordocs/**. So none ofskills/objectui/guides/i18n.md(claim #5081),skills/objectui/guides/schema-expressions.md,skills/objectui/guides/data-integration.mdorskills/objectui/rules/protocol.mdis reachable by this gate, and none is touched here. I added that sentence to theDOCS_ROOTdocblock so the next reader does not have to re-derive it.10 real key errors fixed
Each one paints the renderer's red "Unknown component type" panel (OBJUI-001) for a reader who copies it. Keys taken from the actual
register(...)calls, never from file or component names:guide/building-crud-app.mdx3ObjectGridobject-gridpackages/plugin-grid/src/index.tsx:202guide/building-crud-app.mdObjectFormobject-formpackages/plugin-form/src/index.tsx:100guide/building-crud-app.mdObjectDetaildetail-viewpackages/plugin-detail/src/index.tsx:133guide/expressions.mdempty-stateemptypackages/types/src/feedback.ts:186declares it,components/src/renderers/feedback/empty.tsx:15registers itguide/schema-rendering.mdempty-stateemptyguide/schema-playground.mdgrid-layoutgridcomponents/src/renderers/layout/grid.tsx:50, which readscolumnsas the number the snippet already writesapi/schema-reference.mdx2"type": "link""email"linkis not infieldWidgetMap;emailandurlareThree notes a reviewer should weigh:
ObjectDetailtodetail-viewis the one judgment call here. There is noobject-detailkey.detail-viewis the record-detail component plugin-detail registers, andapi/schema-reference.md:1091already teaches that spelling for the same shape. Flagging it rather than burying it.Page/Card/Text/Button) and the registry lookup is case-sensitive #5236 / [Decision] Should component-registry lookup normalise case? Two measured instances of "every node renders Unknown component type" #5247 shape. Registry lookup is case-sensitive, soObjectGridwas never going to resolve. This spells the registered lower-kebab keys, which is correct whichever way the [Decision] Should component-registry lookup normalise case? Two measured instances of "every node renders Unknown component type" #5247 decision goes.typekey is corrected, not the props beside it.object-gridandobject-formreadobjectName, and those snippets writeobject. Whether a snippet's OTHER keys are read is this gate's stated non-goal and the sibling gate's ledger already carriesbuilding-crud-app.mdwith un-triaged candidate defects. Left alone deliberately; not folded in.One prose word moved with its snippet:
schema-playground.md:283listedgrid-layoutamong the container types. Same page, same falsehood, one word. This is not a scan-surface change — the collector still stops at code fences, which is #5106's first half and stays untouched.31 ledger entries, covering the remaining 57 sites
Every entry is
(file, value)with a reason naming the vocabulary it really belongs to and where that vocabulary is declared. No entry was widened, none relaxes the gate, and no threshold moved —FLOORSis byte-identical.The vocabularies the
.mdhalf turned out to speak:toolbar.actions[],rowActions[],batchActions[], a form'sactions[]) —packages/types/src/crud.ts:89ComponentInput.typein aregister(...)call'sinputs[]— a designer input's coarse control kind,packages/types/src/base.ts:386. This is the single largest class, and it is why the "write a plugin" walkthroughs lit up.board(plugin-development.md builds@object-ui/plugin-boardend to end),my-component,my-grid,my-feature,customcomponent-name,plugin-component-namebar/line, AppSchema menu kindsitem/group, ThemeSchema / BlockSchema discriminants, BlockVariable and PageVariable data typespicklist, the picker/lookup family spellingpackages/core/src/utils/record-title.ts:101namespackage.json's own"type": "module"inguide/plugins.md. Same collisionobjectui check把每个 JSON 文件的根type都当成组件键判定,于是在任何 Node 工程里都对 package.json 的"type": "module"报未知类型 #5127 measured onobjectui check.ActionDef.typepassed touseActionRunner().execute(...)—packages/core/src/actions/ActionRunner.ts:112One entry is disclosed debt, not vocabulary
api/schema-reference.md->crud.CRUDSchemahas four declaration faces (interface, zod mirror, validator branch, builder) and no registered renderer, and unlike its siblings it sits on the render path. There is no registered spelling to move it to — register a renderer / retire it under ADR-0049 / demote it off the node union are three different page edits, and that is the contract question #5115 left open after PR #5128 landed only its CLI half. Filed as #5373, and the entry says to delete itself when that lands. The gate reportsstale-exemptionthe moment the site changes, so it cannot be forgotten.Two entries are honest about being weaker than their neighbours:
schema-rendering.md->admin-panel/user-panelare stand-ins for the reader's own components in a block whose subject isvisibleOn, and unlike themy-componentplaceholder above them the page never registers them. The reason string says exactly that rather than pretending they are the same class.Verification
All runs from the repo root. Heavy runs held
/tmp/os-heavy-verify.lock.The script passing is not its test passing — the test carries hardcoded ledgers the script never touches, so both are reported. 7 tests added: two fixture-level (both extensions collected; a
.mdpage judged by the same rule), one repo-level pin that the widened walk really reaches the.mdtree, and four pinning the key errors above so a revert reads as itself rather than as noise in a 183-file scan.Counter-probed the zeros. A zero from a broken matcher looks exactly like a clean result, so the derived universe was probed with keys known to be registered before any of it was trusted:
object-gridYES,object-formYES,gridYES,formYES — againstObjectGridno,object-detailno,empty-stateno,grid-layoutno. The universe is 659 keys taken from theregister(...)calls themselves.Reverse-verification, and the direction is not the one the template predicts. Reverting only the walk to
.mdx-only, from the committed state:The newly-collected pages do stop being seen, as expected. But the gate does not fall quiet — it goes red, because all 31 new ledger entries lose their sites at once. That is the ratchet working in the reverting direction, and it is a better result than a silent green. The restore leg was verified by marker absence (
f.endsWith('.mdx')gone from the file) before re-reading anything, and re-ran green: 34/34.Build artifacts, per leg. This gate has none between the edit and the result: every import in
check-doc-component-types.mjsis anode:builtin, which its own test asserts (needs no install, so it can afford to run unfiltered). So no leg here was rebuilt, and none needed to be — stating that rather than claiming a rebuild that did not happen.The sibling gate does resolve to
dist/, and my doc edits touch five pages in its ledger, so it was owed a real run. Built its 15 packages (--build-filter), proved the artifacts landed in this worktree rather than trusting a turbo cache-hit that replayed logs from another worktree's path, then:Its ledger is still exact — the edits were inside
jsonfences or were string-literal values, and shifted no diagnostic mix.Other gates touched by these paths, all green at
0a6cba7b9:check:control-bytes(4761 files),check-doc-links.mjs(13 scan roots),check:skills-paths. Plus thecheck-doc-links/check-doc-snippet-types/check-doc-component-typestests together: 141 passed.scripts/pm/dispatch-gates.mjsdoes not exist in this repo — it lives inobjectstack— so the gate set was derived from the 14check:*scripts against my changed paths instead.Every number above and the gate union were taken at
0a6cba7b9, which is this branch's head.Changeset: empty frontmatter
.changeset/doc-component-types-md-surface.mddeclares no package. The diff is the gate script, its test, workflow comments and six documentation pages — nopackages/*/srcfile changes and nothing published moves. Apatchwould version all 39 packages of the fixed group for a change with zero runtime effect, so this uses the repo's declared "no release" form, whichscripts/check-changeset-presence.mjsdocuments as a first-class pass. Nevermajor.content/docs/releases/is untouched.This repo has no
skip-changesetlabel mechanism — the empty-frontmatter changeset is the declaration, and no label was created or applied.Serial constraint held
#5106 is deliberately out of scope and nothing here folds it in. Its two halves — the scan surface stopping at code fences, and the gate never judging the namespace half — are separate questions from the extension gap.
scanDocs's fence loop is byte-identical tomainexcept for the one predicate on the walk, and no namespace logic was added. #5106 remains open and undispatched.Generated by Claude Code