Skip to content

docs(readme): compile the root README's snippets against the shipped surface - #8312

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-5174-doc-snippets-batch37-root-readme
Sep 7, 2026
Merged

docs(readme): compile the root README's snippets against the shipped surface#8312
baozhoutao merged 1 commit into
mainfrom
claude/issue-5174-doc-snippets-batch37-root-readme

Conversation

@claude

@claude claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Part of #5174 (batch 37: the root README.md — the ledger reaches zero)

⚠️ Type parameters in this description are spelled as words ("DataSource at T", "Promise of boolean") rather than with angle brackets, because this repository has measured GitHub silently deleting tag-shaped fragments from stored bodies — inside backticks and fenced blocks alike. See AGENTS.md, "GitHub 会改写你写进 issue/PR 正文的字节".

The root README.md was the LAST row on UNGATED_DOCS. Its five ts/tsx fences now compile against the built dist/*.d.ts, the row is deleted, and the gate prints 0 ungated.

Census — measured with the gate's own scanFences + compileSnippets, never a regex

Reading 1, on the base 0ea7054f8 (the ledger emptied for the measurement so the page is judged):

fence lang verdict
99 tsx TS2552 myAPI, TS2304 MySidebar
137 tsx ZERO
214 tsx ZERO
382 typescript TS2304 SchemaRenderer, TS2304 schema
398 typescript TS2420 (missing findOne, create, update, delete, getObjectSchema) + TS2355

5 fences, 0 parse failures, 0 root-bound refusals, 5 of 5 judged, 6 diagnostics across 3 blocks. The ledger row's wording — "4 undefined-name … 2 elided-body (TS2420, TS2355)" — is accurate in count AND classification, the only row on this ledger that stayed both. Harness controls: sentinel 1 (TS2305), positive 0, undeclared 1, root-declared 1, srcLeaks 0, resolution to packages/types/dist/index.d.ts.

Reading 2, after the repairs: 5 fences, 0 diagnostics, 0 failed. Gate summary now reads Scanned 229 document(s): 229 covered (126 of them hold a ts/tsx block), 0 ungated · 631 of 631 block(s) judged, 0 failed.

Negative controls — were the two PASSING fences bound?

Length-preserving decimal mutations on the base page, trap/restore discipline, every leg proven on disk before its result was read and proven restored by blob equality plus git diff HEAD at 0 bytes.

leg mutation result
NC_A none (control) reproduces reading 1 exactly
NC_B fence 137, member NAME objectName GREEN — nothing checked it
NC_C fence 137, member VALUE "object-form" GREEN — nothing checked it
NC_D fence 214, outer type NAME RED TS2322 Property 'type' is missing … but required in type 'BaseSchema'
NC_E fence 214, sibling columns NAME GREENBaseSchema's index signature absorbs it
NC_F fence 214, outer type VALUE RED TS2322 Type 'number' is not assignable to type 'string'
NC_G fence 214, nested items[].label NAME GREEN

fence 137 was FULLY UNBOUND — an unannotated literal nothing consumes, so all four authored keys and all four values were decoration. Fence 214 is bound at exactly one member: BaseSchema.type, the interface's only required key, at the OUTER literal only (objectui#7927's index signature is the bound; measured here, not assumed).

What changed, and why

Fence 99 — the two ambient names became typed stand-ins: declare const myAPI: DataSource (from @object-ui/types, which is what ObjectViewProps.dataSource REQUIRES three lines further down the same block) and declare const MySidebar: FC (because AppShellProps.sidebar takes a ReactNode and the page renders the value as an element).

Fence 382 — imports its own SchemaRenderer instead of continuing an earlier block (each fence is its own module in this gate's program), and declares schema as BaseSchema, which is what SchemaRendererProps.schema accepts.

Fence 137 — bound to ObjectFormSchema. Decided under the four axes: business — this is the landing page's flagship "Stop Writing Repetitive UI Code" literal, the first metadata object most readers copy; long-term — the annotation moves when the type does; anti-AI-error — DECIDING: an unannotated metadata literal is exactly what an AI copies and then edits, and mode: "created" is the plausible edit that nothing could refuse before (leg M2c now refuses it by name); startup focus — one import type and one annotation, no new surface.

Fence 398 — the // ... other methods elision. DataSource was counted mechanically off the built d.ts: 38 members, 6 required, 32 optional, no index signature. Route (c) taken — an ambient declare class MyCustomDataSource at T implements DataSource at T carrying all six required members with no bodies:

  • actual business need: the section invites readers to implement the interface, and the file it links one line below (packages/types/examples/rest-data-source.ts, real, on main) implements exactly those six. The doc and the example now teach the same set.
  • long-term soundness: route (b) — a members table plus the link, with no fence — is prose no gate reads, and it drifts the day a member moves. The ambient class is re-judged on every commit: leg M3 proves implements IS enforced on a declare class (TS2416), so this is a checked contract, not a picture of one.
  • anti-AI error (deciding): // ... other methods is the elision an AI copies and ships — a class that satisfies nothing and dies at the first findOne. Naming every required member is the structural fix; route (a) (bodies that only satisfy the type) would teach fake implementations, which is worse than teaching nothing.
  • startup focus: no new surface — six existing members restated, nothing exported, no new type.

⛔ No fragment marker, no @ts-expect-error, no any, and nothing in this gate's strictness region moved.

Fence tags — measured, NOT corrected. TS_FENCE_LANGUAGES is ts / tsx / typescript, check:doc-fences treats all three as TypeScript, and compileSnippets parses every block as TSX regardless of the fence label (its own comment states this is deliberate). So the typescript tag on the two JSX-bearing fences is not wrong by either gate's judgement, and re-tagging would have been an unmeasured change.

Fence 214 — deliberately NOT annotated. The precise type of that node is PageNodeSchema, and annotating the literal with it turns the landing page's own example RED: PageNodeSchema.body is SchemaNode[], array-only, while BaseSchema.body is SchemaNode or SchemaNode[] and the only reader (FlatContent) explicitly accepts a single node behind a cast. The example matches the runtime; the declaration does not. Filed as #8310, not repaired here.

Per-key table — every key/prop authored across the five fences

site key declared at read at verdict
99 DataSourceProvider.dataSource providers/src/types.ts DataSourceProviderProps DataSourceProvider body declared, typed any — value unchecked (leg M1 GREEN)
99 AppShell.sidebar app-shell/src/types.ts:19 ReactNode AppShell declared, keep
99 ObjectView.schema plugin-view/src/ObjectView.tsx:230 ObjectViewSchema useSettledSchema declared, keep — checked (leg M1b RED)
99 schema literal type / objectName types/src/objectql.ts:1774 / :1779 as above declared, required, checked
99 ObjectView.dataSource ObjectView.tsx:268, required guarded at three sites declared, keep — satisfied here by useDataSource()'s any return, so unchecked in this block
99 myAPI's declared type this snippet nothing stand-in type checked by NOTHING on this page (leg M8 GREEN)
99 MySidebar's declared type this snippet the JSX element checked (leg M4 RED)
137 type / objectName / mode ObjectFormSchema :1190 / :1210 / :1215 the form renderer declared, required — now checked (M2b, M2c RED)
137 fields ObjectFormSchema fields?: string[] the form renderer declared, OPTIONAL — name still absorbed by the inherited index signature (M2a GREEN)
214 type (outer) BaseSchema.type: string SchemaRenderer declared, required, checked (NC_D, NC_F)
214 title, body, columns, items[].type/label/value BaseSchema index signature PageRenderer at runtime unchecked (NC_E, NC_G)
214 SchemaRenderer.data ForwardedProps, Record of string to any forwarded to the resolved component declared as a pass-through, unchecked by construction
382 createObjectStackAdapter config baseUrl / token data-objectstack/dist/index.d.ts factory param the adapter declared, sealed — no index signature (leg M5 RED)
382 SchemaRenderer.schema SchemaRendererProps.schema the renderer loop declared, keep — checked (leg M6 RED)
382 SchemaRenderer.dataSource ForwardedProps forwarded pass-through, unchecked
398 the six required members types/src/data.ts DataSource every adapter declared, checked through implements (leg M3 RED)

Phantoms dropped: none — no fence on this page authors an undeclared key.

Positive controls — on the COMMITTED tree, against the real gate

Trap on EXIT INT TERM with absolute paths from git rev-parse --show-toplevel; restore is git checkout HEAD -- ABSOLUTE_PATH, never a bare checkout; every mutation proven ON DISK (injected/removed anchor counts plus blob inequality against the HEAD blob d086dd5d0e8383b5bd5133acfa773d432bf8ac52) BEFORE any result was read; every restore proven by blob equality AND git diff HEAD at 0 bytes, never by an exit code. The harness refuses a mutation that is not length-preserving — it did so once, and that leg was rewritten rather than run.

leg mutation gate diagnostic
M1 fence 99 dataSource={myAPI} value to a number exit 0 GREEN THE BOUND: DataSourceProviderProps.dataSource is any
M8 fence 99 myAPI's stand-in type to a numeric literal type exit 0 GREEN THE BOUND: nothing on this page reads that annotation
M1b fence 99 objectName key in the object-view literal exit 1 RED TS2741 Property 'objectName' is missing … but required in type 'ObjectViewSchema'
M2a fence 137 optional member fields renamed exit 0 GREEN THE BOUND: BaseSchema's inherited index signature (objectui#7927)
M2b fence 137 required member objectName renamed exit 1 RED TS2741 … required in type 'ObjectFormSchema' — the exact diagnostic NC_B proved IMPOSSIBLE on the base
M2c fence 137 mode value to a number exit 1 RED TS2322 Type 'number' is not assignable to type '"create" | "view" | "edit"'
M3 fence 398 delete's return type to a numeric literal type exit 1 RED TS2416 Property 'delete' in type 'MyCustomDataSource' … is not assignable to the same property in base typeimplements IS enforced on an ambient class
M4 fence 99 MySidebar's FC to a numeric literal type exit 1 RED TS2604 + TS2786 — the stand-in is a typed component, not an escape hatch
M5 fence 382 baseUrl key renamed exit 1 RED TS2353 Object literal may only specify known properties
M6 fence 382 schema's BaseSchema to a numeric literal type exit 1 RED TS2322 at the READER site (line 405)
M7 unmodified, same session exit 0 GREEN 631 of 631 judged, 0 failed

Ledger and strictness region

UNGATED_DOCS is now {}. Its declaration, @type tag, the header comment, analyze({ ungated = UNGATED_DOCS }), the summary line and the export are all untouched. One header sentence that went FALSE at zero was rewritten — it claimed "what remains here is .mdx pages under content/docs plus package READMEs" — and it now records the terminal state plus the ⛔ rule that an empty object is not an invitation to park the next failing page.

Strictness region (from the ── Fence scanning banner to EOF), awk … | sha256sum:

  • base 0ea7054f8: 2749d53ae3a8df033a53b8d7a354fa7e22ee2d1a17f6ad0c3d61122e904e084b
  • head 94e842dad: 2749d53ae3a8df033a53b8d7a354fa7e22ee2d1a17f6ad0c3d61122e904e084b
  • identical

The objectui#7115 pin moves with the row: it asserted the root README was DECLARED debt with a reason naming objectui#7417. It now asserts the far end — off the ledger and contributing blocks to the compiled tier, so a page leaving the ledger by having no ts/tsx block left cannot pass for coverage.

Prose claims verified against the tree

  • "Importing the package registers every default renderer as a side effect — there is no separate registration call." (line 217) — TRUE: @object-ui/components declares sideEffects: true and its barrel does import './renderers' (packages/components/src/index.ts:36). registerDefaultRenderers exists nowhere in the tree except a pin test asserting its absence.
  • "Use with any component" (fence 382) — TRUE with a stated bound: dataSource reaches the resolved component through SchemaRenderer's declared pass-through surface (ForwardedProps), so it is forwarded to whatever the schema names; whether that component reads it is the component's business, and the pass-through is unchecked by construction.
  • "Object UI is designed to work with any backend through its universal DataSource interface" / "by implementing the DataSource interface" — TRUE, and the repaired fence now shows exactly which members "implementing" means.
  • "~50KB vs 500KB+ full console" — NOT VERIFIED; a bundle-size claim with no gauge in this batch's reach. Reported, not asserted either way.

Gates — pinned to 94e842dad, redirect-then-capture, exit codes never read through a pipe

  • pnpm check:doc-snippets — exit 0: 229 scanned, 229 covered, 0 ungated; 790 covered blocks (631 to compile, 159 declared fragments); 631 of 631 judged, 0 failed
  • pnpm exec vitest run scripts/__tests__/check-doc-snippet-types.test.ts scripts/__tests__/check-doc-fence-languages.test.ts — exit 0: 2 files, 123 tests
  • pnpm exec vitest run scripts/__tests__/ — exit 0: 118 files, 3491 tests
  • pnpm check:doc-types — exit 0: 188 docs, 889 type literals, every documented component type registered
  • pnpm check:readme-exports — exit 0: 532 self-imports judged, 532 real, 0 fabricated. ⚠️ What it does NOT judge here: its surface is packages/NAME/README.md, so the root README's import names are read by no gate — the ledger row said so, and that stays true after the row is gone. The compile gate now judges whether those imports RESOLVE and type-check, which is a different question from whether the named symbol is a real export of the package that owns the README.
  • pnpm check:doc-fences — exit 0: 227 documents
  • node scripts/check-doc-links.mjs — exit 0: links valid across 17 scan roots (including ./packages/types/examples/rest-data-source.ts)
  • pnpm type-check:scripts — exit 0
  • pnpm lint:root — exit 0: 32 problems, 0 errors, 32 pre-existing no-explicit-any warnings, none in any changed file
  • pnpm check:control-bytes — exit 0: 6602 tracked text files; plus a grep -naP self-scan of all three changed paths, no match
  • pnpm check:entry-guard — exit 0: 72 scripts/ files
  • pnpm check:comment-mask-corpus — exit 0: 4426 files, 1 disagree, unchanged at objectui#7882's ceiling
  • node scripts/check-changeset-presence.mjs — exit 0: 3 files changed, 0 published sources, no changeset owed
  • node scripts/check-governed-queue-guard.mjs --test on all three paths — exit 0, NOT GOVERNED
  • build closure pnpm exec turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2 — exit 0, 35/35
  • TURBO_SCM_BASE=0ea7054f8 pnpm exec turbo ls --affected0 packages: this diff touches no workspace package, so no package test / typecheck is owed

CI is not awaited: the report is delivered at draft-PR time per the dispatch contract.

Out-of-scope finding

Dedup method (no /search: 403 for this seat): REST listing of all 390 open non-PR issues across 4 pages, matched locally. Control terms readme (15 hits) and datasource (11 hits) both answered, so the read is real. Two candidate findings were withdrawn as already filed: DataSourceProviderProps.dataSource / useDataSource() typed any, and @object-ui/app-shell's unexported near-duplicate DataSource — both are already named in #8160, with #7912 as the adjacent root-cause card. Nothing new was filed for either.


Generated by Claude Code

…surface

The root README's five ts/tsx fences held six semantic diagnostics across
three blocks, and the page was the LAST row on `UNGATED_DOCS`. Each block is
its own module in the gate's program, so each repair is local:

* fence 99 (minimal integration) declared `myAPI` and `MySidebar` — the two
  pieces a reader brings — as typed stand-ins: `DataSource` from
  `@object-ui/types`, which is what `ObjectView.dataSource` REQUIRES further
  down the same block, and React's `FC`, because `AppShellProps.sidebar` takes
  a `ReactNode` and the page renders `<MySidebar />`.
* fence 382 imports its own `SchemaRenderer` instead of continuing an earlier
  block, and declares `schema` as `BaseSchema` — what `SchemaRendererProps`
  accepts.
* fence 398's `// ... other methods` elision (TS2420 + TS2355) became an
  ambient `declare class … implements DataSource<T>` carrying all six required
  members with no bodies: the contract complete instead of hidden, and
  re-judged by the gate whenever `DataSource` moves.
* fence 137's `const schema` literal was measured UNBOUND — neither its member
  names nor their values were checked by anything — and is now annotated
  `ObjectFormSchema`.

The ledger row is deleted, so `UNGATED_DOCS` reaches `{}` and the gate prints
`0 ungated`. Its declaration, header, readers, summary line and export are
untouched, and the strictness region hashes byte-identical to the base. The
objectui#7115 pin flips with the row: from "DECLARED debt" to covered AND
contributing blocks to the compiled tier, so leaving the ledger with no block
left cannot pass for coverage.

Part of #5174

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests labels Sep 7, 2026
@claude

claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

ACCEPT (batch 37, the root README.md — the ledger reaches ZERO) — reviewed on the tree at head 94e842dad against origin/main 8f9d87af7, read 2026-09-07T10:29Z; domain:devx @ objectui seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr. Merges clean.

Verified from the diff and the tree, not the report:

  • Three files. UNGATED_DOCS is now {} on the head; its declaration, header, analyze({ ungated = UNGATED_DOCS }), the summary line and the export all remain (7 occurrences). Strictness region hashes 2749d53ae3a8df03… on the head, byte-identical to origin/main — the region did not move.
  • Fence 99: declare const myAPI: DataSource + declare const MySidebar: FC with their type imports. Fence 137: const schema: ObjectFormSchema. Fence 382: its own SchemaRenderer import plus declare const schema: BaseSchema. Fence 398: an ambient declare class MyCustomDataSource<T> implements DataSource<T> carrying exactly the six members DataSource requires — confirmed on the tree: 38 members, 6 required (find, findOne, create, update, delete, getObjectSchema), no index signature. No marker, no @ts-expect-error, no any.
  • Negative controls on the two previously-passing fences are the reading this burn-down had been missing: fence 137 was FULLY unbound (member names and values both), fence 214 is bound at exactly one member (BaseSchema.type) with everything else absorbed by the index signature (finding(types): BaseSchema closes with [key: string]: any (packages/types/src/base.ts:467), so NO annotation on any node schema can catch a misspelled metadata key — measured green by a planted probe while the type, optionality and payload-member probes all went red #7927 measured, not assumed).
  • Positive controls include the bounds as well as the reds: the provider prop is any so a wrong value there CANNOT red (M1, M8 green — stated, not hidden), while M1b/M2b/M2c/M3/M4/M5/M6 red with the code named, and implements is enforced on an ambient class (TS2416).
  • The third path (scripts/__tests__/check-doc-snippet-types.test.ts) is the mechanical pin ON the deleted row: it now pins the far end of the same walk — off the ledger AND contributing blocks to the compiled tier, so a page leaving by having no block left cannot pass for coverage. Accepted as the same edit one file over, and declared.
  • Fence tags: measured and NOT changed — compileSnippets parses every block as TSX regardless of label and check-doc-fences pins typescript as a non-finding.
  • Fence 214 left unannotated with the reason filed as finding(types/components): PageNodeSchema.body is array-only while its only reader casts around that to accept a single node — and the root README's flagship example authors the refused form #8310 (PageNodeSchema.body array-only while its only reader casts around it — the cast is on the tree at page.tsx:270). Correct call: binding it would red the landing page's own example for a shape the renderer handles.
  • Branch cut from 0ea7054f8 (never rebased, no merge needed); check:doc-snippets reads 229/229 covered, 0 ungated, 631 of 631 judged.

On the dev's open question (the attribution trailer): option A, and it is now measured rather than assumed — the squash path normalises it. Batch 35 (f20e57d62) and batch 36 (dc75260a2) both landed on main with a plain Co-authored-by: Claude <noreply@anthropic.com> and no model identifier. Nothing to amend, and the no-amend rule stands.

Next: CI convergence → flip ready → post-flip guard → auto-merge SQUASH → queue confirmation → landing probe (UNGATED_DOCS = {} on re-fetched origin/main, the strictness hash unchanged as control) → LANDED here and on #5174, then this seat re-reads #5174 and closes it.


Generated by Claude Code

@baozhoutao
baozhoutao marked this pull request as ready for review September 7, 2026 10:39
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 7, 2026
@claude

claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Armed: PR #8312 flipped ready at 2026-09-07T10:39:18Z on head 94e842dad after CI converged all green (28 checks, read 10:39:10Z); post-flip Governed Surface Queue Guard completed/success at 10:39:36Z; auto-merge SQUASH enabled; queued (timestamp in the REST timeline). Landing stroke on merge: probe on re-fetched origin/mainconst UNGATED_DOCS = {}; present, the row's key absent, the strictness region hash unchanged as the control — then LANDED here and on #5174, and this seat re-reads #5174 in full and closes it. — domain:devx @ objectui seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr.


Generated by Claude Code

@claude

claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Queue reading, recorded rather than acted on — domain:devx @ objectui seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr, 2026-09-07T11:13Z.

PR #8312 has been in the merge queue since 10:39:41Z (33 min). Its merge-group head 0a2f692cc has all 17 workflow runs completed with no non-green conclusion, and there is no removed_from_merge_queue event. origin/main is still 8f9d87af7, so the queue has merged nothing since. Same shape as the 08:41Z–09:36Z stall on #8276 / #8282, which resolved on its own after 55 minutes; the draft toggle attempted then did NOT dequeue and is not repeated here. No action beyond re-arming the merge waiter (this session's container restarted at ~11:10Z and the previous waiter was lost with it).

Nothing about this PR is red, and nothing about it changed. Next re-check is patrol 30 at 11:24Z. — recorded so the timeline reads correctly.


Generated by Claude Code

@claude

claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Correction to the reading above (5569770556) — domain:devx @ objectui seat, 2026-09-07T11:26Z. That note said the queue "has merged nothing since", which reads as an idle queue. It is not idle: two other seats' PRs (#8296, #8297) have merge groups IN PROGRESS right now, and this PR's group has been rebuilt at least once (pr-8312-0a2f692cc earlier, pr-8312-ee6d… now, both completing green). So the accurate reading is that the queue is actively building groups and this entry has been re-grouped rather than stuck behind a dead queue; the last merge into main was #8298 at 10:06Z. No action, no toggling — the merge waiter is armed and patrol 31 re-checks at 12:17Z.


Generated by Claude Code

Merged via the queue into main with commit 59cca05 Sep 7, 2026
31 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-5174-doc-snippets-batch37-root-readme branch September 7, 2026 11:32
@claude

claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

LANDED: merged at 2026-09-07T11:32:20Z as 59cca05b0 (squash — one parent, via the merge queue, after its group was rebuilt while other seats' PRs joined the queue). Content probe on re-fetched origin/main (read 11:32Z): const UNGATED_DOCS = {}; present (1), no README.md key inside it (0), control DOC_EXTENSIONS = ['.mdx', '.md'] present (1); strictness region hashes 2749d53ae3a8df033a53b8d7a354fa7e22ee2d1a17f6ad0c3d61122e904e084b, unchanged; the ambient declare class MyCustomDataSource and the const schema: ObjectFormSchema annotation are on main; the flipped pin (is COVERED and actually judged) is on main. Merge commit is an ancestor of origin/main.

The attribution question resolved as predicted: the landed commit carries a plain Co-authored-by: Claude <noreply@anthropic.com> with no model identifier. Nothing was amended.

#5174 is re-read and closed in the next stroke. — domain:devx @ objectui seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants