docs(providers): compile every README snippet against the shipped surface - #8206
Conversation
…face `packages/providers/README.md` leaves the `UNGATED_DOCS` ledger in `scripts/check-doc-snippet-types.mjs` and joins the compiled tier of `check:doc-snippets` (objectui#5174, batch 29). The ledger row read `7 undefined-name diagnostic(s) … plus TS2741x1`. Measured with the gate's own analyzer, the seven undefined names were ambient values the page never defined (`myCustomDataSource`; `App` in the three provider fences; `myMetadata` twice; `myDataSource`) — the Usage Example defines its own `App`, so that name is a stand-in three times, not four. After adding only `declare` stand-ins, one diagnostic remained: `TS2741` — `children` missing on the `MetadataProvider` of the Usage Example, whose only child was a placeholder comment. `MetadataProviderProps` declares `children: ReactNode` required, so the page was teaching a comment as a value; it now nests a real element. Each stand-in is typed from the prop it is passed to (`DataSourceProviderProps['dataSource']`, `MetadataProviderProps['metadata']`, `() => ReactNode`). Both data bounds are declared `any` today, and the fences say so rather than inventing a stronger type — the laundering objectui#8160 and objectui#7912 already track. No type widened, no fragment marker added, no `@ts-expect-error`, and nothing under `packages/providers/src/**` touched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
…29-providers No overlap with this branch's two paths; merged so every reading below is pinned to a head that contains what landed on main mid-task. 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-07T01:22:09Z as Batch 30 ( Generated by Claude Code |
Part of #5174 (batch 29:
packages/providers/README.md)packages/providers/README.mdleaves theUNGATED_DOCSledger inscripts/check-doc-snippet-types.mjsand joins the compiled tier ofcheck:doc-snippets. The page reads zero after repair, so its entry is deleted rather than rewritten.158d75bb322e4697e28a6ae3d870cc3555f7d237(carries PR docs(auth): compile every README snippet against the shipped surface #8189, batch 28).origin/mainadvanced tod80447d4emid-task (three unrelated PRs;git diff --name-onlyover that range against both of my paths is empty). Merged in with a merge commit, never a rebase, per the brief. Every reading below is pinned to the merged head678609876.packages/providers/README.md,scripts/check-doc-snippet-types.mjs(the ledger row only). No changeset owed. Nothing underpackages/providers/src/**orpackages/types/src/**touched.Note on spelling: JSX tag-shaped and generic-shaped fragments are written as prose names below, because GitHub's body sanitizer silently eats them — see AGENTS.md.
Census — two readings, with the gate's own analyzer
Both readings drive the gate's exported
analyze/compileSnippets(no hand-written regex), with the page forced into the compiled tier and every other ledger row left ungated. Harness controls healthy on both runs: resolution landed onpackages/types/dist/index.d.ts, sentinel 1 diagnostic, positive 0, undeclared 1, zero package-srcleaks, zero analyzer findings.Reading 1 — ledger-literal, on the base
Total 8:
TS2304x7,TS2741x1. Matches the ledger row's own wording exactly.myCustomDataSource; TS2304AppmyMetadata; TS2304AppAppmyDataSource; TS2304myMetadata; TS2741childrenAssumption A1 is falsified in one place, and this is the exact split it asked for. The brief expected
Appfour times, one per fence — which would be eight mentions carried by seven diagnostics, and it flagged that arithmetic itself. The resolution is neither of the two the brief offered:Appis an ambient name in three fences only, because the Usage Example declaresfunction App()itself, so that name is bound inside its own block. Split:Appx3,myMetadatax2,myCustomDataSourcex1,myDataSourcex1 = 7. Nothing is counted once that appears twice, and no fence compilesAppdifferently.Reading 2 — after adding only the missing
declarestand-ins, in memoryPrefixed to each fence body: type-only imports plus
declare constlines, nothing else. Every fence already carried its own value import, so no value import line was added and no prop was touched.Total 1:
TS2741x1, fence 53. Fences 19, 31 and 43 read zero.Blind-spot count: 0. Batches 27 and 28 both found a mixed ledger row understating type debt, and the mechanism is specific: an unresolved JSX tag name short-circuits the prop check on its own element. That mechanism cannot fire here — every provider tag name is imported and bound in every fence, and all seven undefined names sit in ordinary value positions (
dataSource={…},metadata={…}, and anAppelement that takes no props). So this row was exact in the type-code direction. The other direction from batch 28 does hold, strongly: 7 of the 8 diagnostics were ambient names, 1 was a real defect.The ledger-or-repair decision is made on reading 2, per the batch-28 carry-forward.
Reading 3 — the page as committed
Total 0 across all four fences, measured through the same harness.
pnpm check:doc-snippetsagrees: 601 of 601 blocks judged, 0 failed.Per-fence decision
All four fences: repair. Nothing ledgered, nothing declared a fragment.
myCustomDataSourceandAppbecomedeclare conststand-insmyMetadataandAppbecome stand-insAppbecomes a stand-inmyDataSource/myMetadatastand-ins, and the MetadataProvider element is given a real childThe first three fences are bare JSX expression statements. That shape is kept, and the gate's parse phase never objected to it — before and after, its syntax line reads "every block parsed, so every one of them reached the semantic phase". No fragment marker, no
@ts-expect-error, no widened type, no loosened prop anywhere in the diff.Stand-in types, all read off the shipped surface:
DataSourceProviderProps['dataSource'],MetadataProviderProps['metadata'], and() => ReactNodefor the component stand-ins.The TS2741, decided against the exported props type
Declarations cited from
packages/providers/src/types.ts(byte-identical in the builtpackages/providers/dist/types.d.ts)::4DataSourceProviderProps—:5dataSource: any,:6children: ReactNoderequired:9MetadataProviderProps—:10metadata?: any,:11children: ReactNoderequired:43ThemeProviderProps—:44defaultTheme?: ThemePreference,:45storageKey?: string,:46children: ReactNoderequiredAssumption A2 confirmed. The diagnostic is on the Usage Example's MetadataProvider, exactly where the brief predicted:
Verdict: README defect, repaired to the shipped surface. This is batch 28's shape again — the type refuses nothing the page passes; it requires something the page omits. So it takes the first branch of the brief's rule, not the type-defect branch, and the ledger keeps no count.
What the page used to teach: that a placeholder comment satisfies a required
childrenprop. The element's entire content was a JSX expression container holding a comment and nothing else, which is no child at all — a reader copying the one example the page presents as the complete wiring gets a red build on it. It now nests anAppContentstand-in, and the prose above the fence states that both providers declarechildrenrequired, so the next author does not re-introduce the placeholder.The other two providers in that same fence were never at issue: ThemeProvider and DataSourceProvider each already had a real element inside them.
The
anybound, recorded rather than inventeddataSourceandmetadataare declaredany(types.ts:5and:10). No stronger type was invented for either: each stand-in is typed through the prop it is passed to, so it inheritsany, and the fence comment says out loud that the compiler therefore checks nothing about those objects' shape. That laundering is a known, declared one — objectui#8160 and objectui#7912 already name it — so it is cited here and not re-filed.Key surface (objectui#7927)
Verified rather than assumed: none of
DataSourceProviderProps,MetadataProviderPropsorThemeProviderPropsextends anything, none isBaseSchema-derived, and none carries an index signature — a grep ofpackages/providers/src/types.tsforextends,BaseSchemaand index-signature syntax returns no hits. So the compiler judges the keys itself through JSX excess-property checking, and the per-key table collapses to its verdict per fence:dataSource; compiler judges; zero.metadata; compiler judges; zero.defaultThemeandstorageKey, both declared and both optional;"system"is a member ofThemePreference; zero.dataSource,metadata, andchildrenon all three elements; zero after the repair.Strictness region
The region from the
Fence scanningbanner to EOF, byte-identical as the licence requires:158d75bb32749d53ae3a8df033a53b8d7a354fa7e22ee2d1a17f6ad0c3d61122e904e084b6786098762749d53ae3a8df033a53b8d7a354fa7e22ee2d1a17f6ad0c3d61122e904e084bIdentical. The gate diff is exactly the two lines of this page's
UNGATED_DOCSrow, deletions only (2 --, no additions).Ledger
The page reads zero, so its entry is deleted, per the ledger contract. Rows 9 to 8. No pin enumerates it —
scripts/__tests__/check-doc-snippet-types.test.tspins only the rootREADME.mdrow at:600/:601— so no test file needed editing.Counters on the head: 229 documents; covered 220 to 221 (118 of them hold a ts/tsx block); ungated 9 to 8; blocks to compile 597 to 601, exactly this page's four fences; declared fragments 158 to 158, unchanged.
Positive control
Injected
defaultTheme={42}into the repaired ThemeProvider fence (ThemePreferenceis a string union), against the committed tree, inside atrapwhose restore path is absolute.git diff HEADon the path 0 bytes; disk blob equals the HEAD blob3e986a6de1e0a19f75fadefeaa5e1611ba983c8167d0e621beebeb119777193a84c548b38ae3d933— not by an editor's exit code[semantic] packages/providers/README.md:70:16 TS2322: Type 'number' is not assignable to type 'ThemePreference | undefined'.and its semantic line reads
601 of 601 block(s) judged, 1 failed3e986a6de1e0a19f75fadefeaa5e1611ba983c81,git diff HEADon the path 0 bytes,git status --porcelainemptyRun twice with identical results — once on the pre-merge commit
5bf697c60, once on the merged head.Gates, every reading pinned to
678609876Exit codes captured by redirect-then-capture, never across a pipe.
pnpm check:doc-snippetspnpm exec vitest run scripts/__tests__/check-doc-snippet-types.test.ts scripts/__tests__/check-doc-fence-languages.test.tspnpm exec vitest run scripts/__tests__/pnpm check:doc-typespnpm check:readme-exportspnpm check:doc-fencespnpm type-check:scriptspnpm lint:rootpnpm check:control-bytesgrep -naPcontrol-byte self-scan, both changed pathsnode scripts/check-changeset-presence.mjsnode scripts/check-governed-queue-guard.mjs --testboth pathspnpm check:entry-guard--build-filter,--concurrency=2)Re-derived beyond the brief's list against the actual diff, all 0:
check:doc-example-readers,check:esm-specifiers,check:shell-escape-residue,lint:coverage,type-check:coverage,check:self-import,check:unreferenced-sources,check-doc-links.mjs,check-doc-component-types.mjs,check-doc-expression-carriage.mjs, andcheck:node-esm-load.check:node-esm-loadfirst exited 1 for the environmental reason the brief predicted: turbo shares one cache across every worktree of a checkout, so one package replayed an artefact built in a sibling worktree and the gate correctly refused to grade another tree's output. Re-run with--force-build, as its own message instructs, it exits 0 with 34 of 39 published ESM entries imported and evaluated.Live E2E (informational)is red on every branch today for an upstream reason (#7990, objectstack#16186) and is not this branch's.This PR is draft, base
main, and the work was published from Claude Code sessionsession_01FhBNJcLRZLe8M87VcUgpKr.Generated by Claude Code