Uh oh!
There was an error while loading. Please reload this page.
feat(tooling): read plugin key tables in the doc component-type gate, and judge the namespace half - #6205
Merged
Conversation
… and judge the namespace half `scripts/check-doc-component-types.mjs` read fenced code only. The objectui#5002 family (eight PRs) replaced the plugin pages' fictional registration loops with a markdown key table — the right form, landing entirely outside the scan surface, while the code blocks it replaced had been inside it. A fake key in a table was green; the same key in a fence was red. It also never judged a namespace. It compared bare keys against a universe that merely happens to contain namespaced ones, so flipping a registration's `namespace` left every doc teaching the old one green. Both halves of every key-table row are now judged. The anchor is the table HEADER, not the row shape: the row heuristic was measured over this tree and matched 33 rows of which only 22 were keys — the rest are route patterns, URLs, HTTP routes and JSON literals, every one a false red on correct docs. Also fixes a dead floor: `FLOORS.docFiles` named a counter that never existed (`scanDocs` publishes `files`), so it compared `undefined` and the check meant to catch the walk finding nothing was inert. The class is closed too — a floor naming no counter now fails loudly. Part of #5106 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
yinlianghui-tw
marked this pull request as ready for review
August 25, 2026 01:52
Uh oh!
There was an error while loading. Please reload this page.
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.
Part of #5106
Route A as triage adopted it. Two of the order's three parts had already landed — see "Premise" below — so this PR is part 1, plus one defect found inside the mechanism it extends.
What changed
scripts/check-doc-component-types.mjsread fenced code only. The #5002 family (PRs #5071 / #5078 / #5079 / #5085 / #5089 / #5093 / #5100 / #5104) replaced the plugin pages' fictional*Componentsregistration loops with a markdown key table. The new form is the right one, and it landed entirely outside the scan surface — while the code blocks it replaced had been inside it. The fact "which keys does this plugin claim" moved from a checked place to an unchecked one.It also never judged a namespace at all. It compared bare keys against a universe that merely happens to contain namespaced ones, so
view:dashboarddocumented asplugin-dashboard:dashboardproduced no signal from any static check.Both halves of every key-table row are now judged.
The anchor is the table HEADER, not the row shape — this is the whole design
The obvious row heuristic ("first cell is a backticked token containing a colon, second cell is a backticked token") was built and measured over this tree before being rejected. It matches 33 rows, of which only 22 are keys. The other 11:
guide/console-architecture.md:104`/apps/:appName/:objectName`|`ObjectView`utilities/runner.mdx:99`http://localhost:5173/`|`LocalBundleLoader`guide/metadata-diagnostics.md:43`GET /api/v1/meta/items/:type/:name`guide/designing-app-navigation.md:21`{ "type": "object", … }`Every one would be a false RED on correct documentation — the expensive direction for a gate whose entire value is being trusted about docs. So the anchor is
| Namespaced key | Bare-name fallback | … |, which is a declaration by the page that the rows beneath it are registry keys. It discriminates perfectly where a row shape cannot, and costs authors nothing they were not already writing. Prose backticks are not dragged into the scan.Deliberately not checked: when the fallback cell reads
none — `skipFallback: true`, the gate does not assert the bare name is absent. It cannot — the universe is a deliberate union across every package, soview:gridskipping its own fallback says nothing about whether another package registers a baregrid, and one does. Asserting the negative would redplugins/plugin-grid.mdx:185, which is correct.DOC_TYPE_EXEMPTIONSdeliberately does not apply to table rows: a row under a header saying "Namespaced key" has already declared its vocabulary, so an exemption there would be a lie rather than a fact.Controls — the card's own discriminating experiment, run as a before/after pair
Each run against HEAD's gate and this branch's gate on the identical mutated tree, so the pair isolates the change rather than the tree. Every mutation proven on disk by anchored counts; every restore proven by an empty
git diff HEAD.plugin-dashboard:phantom-widget):107:155)unregistered-doc-typenamespace: 'view'→'dash'inplugin-dashboard/src/index.tsx:83plugin-dashboard.mdx:99 [unregistered-key-table-key] namespaced 'view:dashboard'"type": "crud"intoschema-reference.md(a.mdfile that has exemptions)unregistered-doc-type— exemptions are keyed(file, value)and do not swallow itThe namespace control is the one worth reading twice: only one finding is produced, because the bare
dashboardstill matches. That is exactly why a gate judging only bare keys can never notice a namespace move, and why the namespaced cell is the half that closes it.One honest note: the fenced control's first attempt was a no-op — the
perl -ianchor matched zero lines, exited 0, and the gate ran green, which would have read as "the fenced surface still works" while testing nothing. Caught by the anchored count not moving (phantomstayed 0). Re-run against a verified anchor at:155; the table above is the real reading.Non-vacuity, and a dead floor found inside it
Census now in the verdict line:
Re-derived counts (the order asked; the card's 143/40 is from 2026-08-18): 144
.mdx+ 40.md= 184. All 24 rows across 4 tables pass today — the card's "现存的每张键表实测都是对的" still holds.Zero key tables fails: renaming the header in all four files (4 → 0 occurrences, proven) gives
The scan collapsed: keyTables = 0, below the floor of 2.— not a green pass.While adding those floors I found the existing one was dead.
FLOORS.docFilesnamed a counter that never existed —scanDocspublishesfiles— so it evaluatedundefined < 100, which isfalse. The one floor whose job is catching the walk finding nothing had been inert for its whole life. Fixed by spelling, and the class closed: a floor naming no counter now fails loudly, naming the real counter list. Proven by re-introducing the exact original spelling:This is a bounded in-place fix, not scope creep: same defect class (this gate's own collapse detection, the mechanism this PR extends), mechanical, and evidence-pinned.
Premise: two of the three ordered parts had already landed
Verified against
origin/mainbefore writing code, per the order's own instruction to re-derive..mdfiles. Already done.DOC_EXTENSIONS = ['.mdx', '.md']with the exemption ledger keyed by.mdpaths throughout. Landed as sub-issue check-doc-component-types collects only.mdxtoo — 26.mdguides teach 345typeliterals inside fences with nothing checking them #5342, closed 2026-08-20. The order cites:694; the file is now 1065 lines.schema-reference.md:530"type": "crud"— thecrudnode type was retired withCRUDSchemain refactor(types,core)!: retire CRUDSchema and thecrudnode type (ADR-0049) #6117 (ADR-0049). The page now documents its removal;grep '"type": "crud"'returns nothing.building-crud-app.md:187ObjectGrid— fixed, and already pinned by a test (check-doc-component-types.test.ts:458, "the CRUD guide spells the registered keys, not the PascalCase component names").Since the intended corpus no longer exists, the controls above serve as this PR's validation corpus — which is what the order specified as the discriminating experiment anyway.
Verification
Union re-run on the final commit
93124e4d5:node scripts/check-doc-component-types.mjs→ exit 0, census abovepnpm --filter @object-ui/app-shell test跑的是 @object-ui/console 的 22 个文件,app-shell 自己的 276 个一个没跑,却报绿 #3378), gate + every consumer that imports it —check-doc-component-types,known-schema-types-derivation-5115,check-pre-install-import-graph,scripts-type-check,catalog-gallery-render→ all passed. A tooling diff is not automatically tooling-only: consumers importderiveRegistryKeys, which is untouched;scanDocs/analyzechanged additively. 49 tests in the gate's own file (+12 new), 652 across the consumer set.check-control-bytes→ OK (5122 files) ·type-check:scripts→ exit 0 ·lint:coverage,type-check:coverage,check-changeset-presence,check-pre-install-import-graph,check-doc-fences→ exit 0Exit codes captured by redirect before any pipe; each verdict quoted from the gate's own line.
Declared narrowings (CI runs the full farm regardless):
eslintnarrowed to the two changed source files: both resolve under eslint's own config (2 files linted per--format json), 0 errors / 0 warnings, andeslint.config.jsenables no type-aware linting (noprojectService, noparserOptions.project), so this diff cannot move any untouched file's verdict.check:doc-snippetsdeclined to run — "the packages it resolves against are not built" — an unbuilt worktree, not a finding. This diff contains zerocontent/docsbytes.Out of scope, reported not fixed
The widened surface found no new ghosts: all 45 table keys are registered. Per the order, no other ghost was fixed.
Generated by Claude Code
Generated by Claude Code