docs(plugin-charts): compile the README's snippets against the shipped surface - #8245
Conversation
…d surface
Burn down `packages/plugin-charts/README.md`'s UNGATED_DOCS entry in
scripts/check-doc-snippet-types.mjs so the gate compiles the page instead of
ledgering it (objectui#5174, batch 31).
The row read "6 parse diagnostic(s)". Measured with the gate's own analyzer,
all six were TS1109 on one block — the "Schema API" fence, a TYPE shape written
as an object literal, one diagnostic per optional member. A parse-only row hides
the semantic phase, so the page's other three fences had never been judged at
all.
- Schema API: the fence is replaced by a members table. It re-declared the
published `BarChartSchema` instead of importing it, so the gate would have
judged a private copy of the contract; a table teaches the members without
teaching the copy.
- The bare `const schema = { … }` is annotated `BarChartSchema` and imports the
type, so its keys are now checked against the declaration.
- The manual-registration loop passes `{ namespace: 'plugin-charts' }`, the
shipped call. `register()` with two arguments is the deprecated form and warns
at runtime.
- `color`'s documented default was `'#8884d8'`, which nothing on the render path
reads; the renderer defaults it to the theme token. Corrected, with the drift
named.
- `chart-bar` is not a registered keyword; both occurrences now read `bar-chart`.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
✅ 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
|
|
Standing down on That check is informational (not in the Generated by Claude Code |
|
Armed —
Landing stroke follows the merge: content probe on re-fetched Generated by Claude Code |
|
LANDED — Merged at 2026-09-07T03:34:17Z as Batch 32 ( Generated by Claude Code |
Part of #5174 (batch 31:
packages/plugin-charts/README.md)Burns down this page's
UNGATED_DOCSentry inscripts/check-doc-snippet-types.mjsso the gate compiles its snippets instead of ledgering them.f10c6c5596acb9c03fc7f882276b494c3cfdd7e2(carries PR docs(plugin-chatbot): compile the README's snippets against the shipped surface #8228, batch 30).0ee362ae82e184c647391736df42069ff28c3f8c. One commit, no amend, no force-push.Notation. Generic parameters are spelled as uppercase words, never in angle brackets, because this repository has measured GitHub's body sanitizer eating tag-shaped fragments inside backticks and fenced blocks alike (AGENTS.md, "GitHub 会改写你写进 issue/PR 正文的字节"). So
Array of Record from STRING to ANYbelow is the literalArraygeneric the file writes.Census — two readings, with the gate's own analyzer
Both readings call the script's exported
analyze()/scanFences()/compileSnippets()with this page removed fromUNGATED_DOCS, against the built closure (pnpm exec turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2, 35/35 successful). No hand-written regex. Harness controls on every run: resolution landed onpackages/types/dist/index.d.ts,srcLeaks0, positive control 0 diagnostics, sentinel 1, undeclared 1, root-declared 1.Fences on the base: four
typescript(22, 42, 56, 73), one unlabeled (100), twobash.Reading 1 — ledger-literal (base page, base ledger row)
The row read:
6 parse diagnostic(s) — blocks fenced ts that are bare object literals or elided bodies.typescripttypescripttypescripttypescriptbashBlind spot: 1 fence of 4 never reached the semantic phase. Two corrections to the row itself, both measured:
?:member.6 × TS1109, because fence 22's binding carried no type for anything to be checked against.Reading 2 — after the minimum in-memory parse repair
Fence 73 made parseable with the smallest possible change (the bare shape given a name:
type SchemaAPI = { … }), nothing else touched:Zero. This is the first real look at the page's type debt, and the honest reading is that the page has none that a compiler can see — because two of its four fences were written so that nothing could be checked: fence 22 was an unannotated literal (every key inferred, nothing compared) and fence 73 was a private re-declaration of a published type (a copy cannot disagree with itself). Green here means "not looked at", not "verified". That is what the repairs below change, and the positive/negative control pair is the proof.
Per-fence decision
const schema = { … }, unannotated; comment taught the keywordchart-barconst schema: BarChartSchema = { … }plusimport type { BarChartSchema }; comment readsbar-chartchart-baris registered by nothing;bar-chartis (src/index.tsx:38).ComponentRegistry.register(type, component)ComponentRegistry.register(type, component, { namespace: 'plugin-charts' })register(type, component, meta?)(packages/core/src/registry/Registry.ts:433) accepts two arguments, so this compiled — andRegistry.ts:440–449warns at runtime that the no-namespace form is deprecated. The page taught the deprecated call; the package's own sixregister()calls all pass a namespace. Repaired to the shipped call, not to something new.const schema: BarChartSchema = …check:doc-fencesis green over it and this page appears in no entry of that gate's shrink-only ledger (grepforplugin-chartsinscripts/check-doc-fence-languages.mjsexits 1).bashFence 73 — the route, on the four axes
Route (a): replace the fence with a Markdown table of
BarChartSchema's declared members. Alternatives weighed: (b) atypescriptfence that imports the type and shows its members through a typed value; (c) a fragment marker naming the shape.BarChartSchemais the published contract, re-exported from@object-ui/types(packages/plugin-charts/src/types.ts:52— assumption A5 confirmed) so that the type an author annotates with and the schema that validates their document are one declaration. A fence re-declaring it is a private second copy that drifts silently, which is exactly objectui#7646. (a) deletes the copy; (c) keeps the copy forever and merely stops the gate from looking at it.check:doc-typesreads the table (4 key table(s), 24 row(s), 45 table key(s) judged, 45 registered), so the one machine-checkable claim in it — thatbar-chartis a registered keyword — is still verified on every commit.⇒ (a), matching the dispatching seat's reading. (b) was reserved for the case where the page's teaching needs a compilable example at that spot; it does not — fence 56 is that example.
Per-key table (objectui#7927 key-surface bound)
BarChartSchema extends BaseSchema(packages/types/src/data-display.ts:2143) andBaseSchemacarries[key: string]: any(packages/types/src/base.ts:467), so an annotation checks member types and never keys. Every key the examples write is therefore classified by hand-reading the declaration and the renderer's reads, not by the compiler.typedata-display.ts:2144('bar-chart'), narrowingBaseSchema.type(base.ts:75)src/index.tsx:38)datadata-display.tsdata?ChartRenderer.tsx:32dataKeydata-display.tsdataKey?ChartRenderer.tsx:33xAxisKeydata-display.tsxAxisKey?ChartRenderer.tsx:34heightdata-display.tsheight?ChartRenderer.tsx:35colordata-display.tscolor?ChartRenderer.tsx:37classNameBaseSchemaclassName?(base.ts:171)ChartRenderer.tsx:36No phantoms, and no undeclared-but-read key among what these examples write: the seven keys are exactly the six
ChartBarRendererforwards plustype. Nothing dropped, nothing withheld, nosrc/**ortypes/**proposal owed on this axis.Defaults check — one wrong documented default, repaired
The base page documented four defaults inside fence 73. Checked against the renderer's own parameter defaults in
packages/plugin-charts/src/ChartImpl.tsx:55–61:dataKey'value''value'(:56)xAxisKey'name''name'(:57)height400400(:58)color'#8884d8'hsl(var(--primary))(:61)data[](:55)className''(:59)ChartBarRendererforwardscolor={schema.color}verbatim (ChartRenderer.tsx:37), so an omittedcolorreachesChartImplasundefined, so the theme token is what actually renders. The literal'#8884d8'survives in two places, neither of which is on the render path:defaultProps.color(src/index.tsx:63) — the package's own comment atsrc/index.tsx:143–151records the finding of objectui#7401 thatSchemaRenderernever reads a registration'sdefaultProps; I re-verified it: the only read ofdefaultPropsinpackages/coreandpackages/reactoutside tests isWidgetRegistry.ts:189, which writes manifest defaults into the registry;@default '#8884d8'onBarChartSchema.color(packages/types/src/data-display.ts).Proposal for the PM (no edit made —
packages/types/**andpackages/plugin-charts/src/**are out of surface): the type's@defaulttag oncolorrecords a value nothing on the render path produces. Two candidate directions, and this is a contract question rather than a doc one: correct the JSDoc to the theme token, or make the registration'sdefaultPropsactually reachable so the documented value becomes true. The README now states the runtime truth and names the drift in one sentence so a reader who opens the type is not silently contradicted.Ledger decision
Ruling 5, first branch: the file reads zero after the repairs (reading 3, on the committed tree — parse 0, bound 0, semantic 0, all three remaining
typescriptfences judged and green), so itsUNGATED_DOCSentry is deleted rather than rewritten. No fragment marker was added: nothing on this page is parked on a filed defect, and every block compiles as written. The ledger reads 6 rows on the head (was 7).Strictness region
The region from the
Fence scanningbanner to EOF, byte-identical as ruling 6 requires. Both values recomputed here withtail -n +LINE scripts/check-doc-snippet-types.mjs | sha256sum:f10c6c5592749d53ae3a8df033a53b8d7a354fa7e22ee2d1a17f6ad0c3d61122e904e084b0ee362ae82749d53ae3a8df033a53b8d7a354fa7e22ee2d1a17f6ad0c3d61122e904e084bIdentical. The two-line shift is the deleted ledger row, which sits above the banner.
Positive control (and its negative twin)
Run against the committed tree, under a
trapwith absolute paths, restore proven by STATE.Positive —
height: 400mutated toheight: 'tall'in the repaired fence 22 (the typed binding):^ height: 400$went 2 → 1,height: 'tall'went 0 → 1; blob movedd0e2535ee2d55e220e9c8217b7be66b34c2fa592→c814e819cbbc016393bd9342a504b696864a5e6f.pnpm check:doc-snippetsexit 1, naming the page and the line:[semantic] packages/plugin-charts/README.md:39:3 TS2322: Type 'string' is not assignable to type 'number'.andSemantic phase: 614 of 614 block(s) judged, 1 failed.git checkout HEAD -- PATH, thengit diff HEAD -- PATHempty andgit hash-object PATH=d0e2535ee2d55e220e9c8217b7be66b34c2fa592= the HEAD blob. Anchors back to 2 and 0.Negative twin (the blind-spot proof). The identical mutation applied to the base page, compiled in memory through the same analyzer: parse still
6 × TS1109on fence 73, semantic failures 0. The base ledger row is byte-for-byte the same with and without a type error in the very fence the row is silent about. That is the second blind-spot form batch 30 recorded, in its purest shape here — not an errored binding feeding a checked element, but a binding with no type at all, so there was never anything to check.Gates (all pinned to head
0ee362ae8, tree clean; exit codes captured by redirect-then-capture, never through a pipe)pnpm check:doc-snippetsScanned 229 document(s): 223 covered (120 hold a ts/tsx block), 6 ungated;614 to compile, 159 declared fragment(s);Semantic phase: 614 of 614 judged, 0 failed. This page is in the covered/compiled tier.pnpm exec vitest run scripts/__tests__/(whole directory, includescheck-doc-snippet-types.test.tsandcheck-doc-fence-languages.test.ts)pnpm check:doc-types4 key table(s), 24 row(s), 45 table key(s) judged, 45 registered— the new members table is read by this gate.pnpm check:readme-exports0 wrong-path, 0 fabricated. Assumption A4 confirmed:chartComponents(src/index.tsx:32) andBarChartSchema(src/index.tsx:14) are both real exports; the gate was green on the base too.pnpm check:doc-fencespnpm type-check:scriptspnpm lint:rootpnpm check:control-bytesgrep -naPself-scan of both changed paths: no hits.pnpm check:entry-guardnode scripts/check-changeset-presence.mjs0 of them published source of a package the release covers … no changeset is owed.No changeset added, no label.node scripts/check-governed-queue-guard.mjs --test(both paths)NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched.pnpm exec vitest run packages/plugin-charts/turbo ls --affectedagainst the base names@object-ui/plugin-charts(the README is inside the package). Its seven transitive dependents are affected only through that README byte and are declared to CI.Live E2E (informational)is red on every branch today for an upstream reason (#7990 / objectstack#16186) — not from this change.Assumptions
register()compiles (the third parameter is optional) and is the deprecated form the registry warns about at runtime.git log --oneline -5 origin/mainon both paths tops out at the base commit; agit ls-remote --heads originscan of 1022 heads finds no other branch namingdoc-snippet,5174orplugin-charts. Main did not move during the task.BarChartSchemafrom@object-ui/types; it declares nothing of its own.🤖 Generated with Claude Code
https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Generated by Claude Code