docs(core): compile every README snippet and leave the UNGATED_DOCS ledger - #8132
Conversation
…edger Part of #5174 — batch 25 of the UNGATED_DOCS burn-down. `packages/core/README.md` leaves the ledger; every ts/tsx block on the page now compiles against the built types. The gate file's only change is the ten lines of that one entry, removals only. The five TS2304 are paid down with real self-imports plus `declare const` stand-ins typed from the shipped surface (`ComponentRenderer`, `ServerActionFetch`, `ActionRunner`), never a lenient alias. The surviving TS2339 is the System-View immutability demonstration, whose rejection IS the documentation: the line stays and carries a `@ts-expect-error` with its reason, which pins the property in both directions. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
|
Standing down on
Every other check on Generated by Claude Code |
✅ 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
|
|
Armed — squash auto-merge enabled and the PR is in the merge queue,
On MERGED: content probe on re-fetched Generated by Claude Code |
|
LANDED — merged at 2026-09-06T18:23:15Z as Content probe on re-fetched
#5174 stays open ( Generated by Claude Code |
Part of #5174 — batch 25 of the
UNGATED_DOCSburn-down.packages/core/README.mdleaves the ledger and every ts/tsx block on the pagenow compiles against the built types. The gate file's only change is the ten
lines of that one entry.
Notation, read this first
This repository has measured that GitHub's body sanitizer deletes tag-shaped
fragments even inside backticks and fenced blocks. So generic parameters and
JSX elements are spelled out in words below — "Registry of any", "DeepReadonly
of T", "the ActionProvider element" — rather than in their real angle-bracket
form. The README itself carries the real spellings; this page does not.
Concurrency
mainmoved under this batch twice, and both were absorbed by merging(never rebasing, never force-pushing).
e23cfb000tocf1d29e2f— two PRs, including feat(types): ComponentInput.of — the coarse member kind, with readers on day one #8097, which declaresComponentInput.ofonpackages/typessource. Package source moves thebuilt types this corpus is judged against, so the forced build, the census,
every gate, every probe and every test were re-run on the merged head. Every
reading was byte-identical.
cf1d29e2ftof10bcd497— two docs PRs (docs(guide): make three drifted counts on ci-cd-pipeline.md self-maintaining #8121 oncontent/docs/guide/ci-cd-pipeline.md, docs(gates): record the package-README census and defer check:doc-types' fourth leg (objectui#7896) #8111 adding a comment block toscripts/check-doc-component-types.mjs). Both are inside the corpus thisgate scans, so everything was re-run again on
1ad6167a6. Readings againbyte-identical.
All 16 open pull requests' file lists were read over the REST files endpoint and
each count reconciled against that PR's own
changed_files: 8118/9, 8116/34,8112/1, 8111/1, 8109/1, 8104/2, 8097/16, 8091/1, 8090/1, 8076/6, 7749/4,
7685/67, 7058/24, 7054/2, 7053/2, 5400/1058. #5400's 1058-file list was paged to
exhaustion because the endpoint pages at 100 and a truncated list renders as a
confident absence. No open PR touches
packages/core/README.mdorscripts/check-doc-snippet-types.mjs. The one open PR that touches anypackage README is #7685, on
packages/auth/README.md— which is exactly thestanding exclusion, so it doubles as the positive control that this grep can
find a hit at all.
Live E2E (informational)is red on every branch today for an upstream reason(objectui#7990 / objectstack#16186), not because of this diff.
Ledger arithmetic
Both rows MEASURED by a real gate run, never computed. Base row at the final
merge base
f10bcd497bytes (probe M0, both paths checked out to the main blobsand proven equal by hash, restored under a trap); branch row at
1ad6167a6.f10bcd4971ad6167a6UNGATED_DOCSentriescheck:readme-exports)Programmatic diff of the two
UNGATED_DOCSobjects — both imported as OBJECTS,never diffed as text: removed =
['packages/core/README.md'], added =[],reason-changed =
[], survivor key order preserved = true.git diff --numstaton the gate file against the merge base is exactly
0 10. On the branch: coreentries 0,
packages/NAME/README.mdentries 11 (from 12), control'packages/auth/README.md'1.The strictness region — the
Fence scanningbanner line to EOF, 1178 lines onboth sides — hashes to
f46b5662ba336f026bca3a0003e0b7979789d48d0291fa5760be7d23c8ed0160on the mergebase and on the branch. Re-measured here on both sides, not inherited; it is the
value batches 15 through 24 recorded.
This entry's reason string was ACCURATE — the stale-ledger streak ends here.
It claimed "5 undefined-name diagnostic(s) … plus TS2339x1 — TRIAGED, and NOT a
defect". Measured: exactly TS2304x5 and exactly TS2339x1, and the TS2339 is
exactly the line the string names. Every recent batch has reported its entry as
stale about what the debt was; this one was right, including its triage, and
that is worth recording rather than passing over.
Census and the rung that decided
Re-taken on this batch's own base through the gate's exported
analyze()/compileSnippets(), one document un-gated at a time, over every non-excludedledger candidate — and re-taken again after each merge.
Rung 1 does not decide, and neither does rung 2:
packages/coreandpackages/plugin-kanbantie on blocks (5), on rung 1's second term(6 diagnostics) and on rung 2's distinct codes (2). Rung 3 decides
alphabetically —
packages/core/README.md.Assumption A1 is CONFIRMED — every block total, diagnostic total and
per-code figure matches batch 24's census exactly, and held identical across
both merges. Zero bound refusals on this page.
Exclusions re-verified against GitHub on this base, not inherited: the root
README.mdis not apackages/NAME/README.md;packages/auth/README.mdisheld by open draft PR #7685;
packages/plugin-chatbot/README.mdis deferred bythe earlier ruling.
The System-View block: a failure that IS the documentation
This is the batch-25 ruling, and it is the reason this page needed a decision
rather than a repair.
packages/core/README.mddemonstrates System-View immutability by writing acolumns.pushthat is supposed to be refused, annotated// (cross) TypeError (strict mode). Its TS2339 is not debt — the ledger's ownentry called it "TRIAGED, and NOT a defect", and the measurement agrees. Three
shapes were available and only one is honest:
cannot be checked, and this block can be — claiming otherwise would be the
one thing the gate's fragment rule exists to prevent.
The line now carries, directly above it, a
@ts-expect-errorwhose trailingtext is its reason — that the readonly rejection is
defineSystemViewdeepfreezing the graph and typing it readonly, so the push is refused at compile
time as well as at run time. The prose comment stays: it is the runtime half of
the same lesson.
This shape is a pin in BOTH directions, and both were measured.
(
Semantic phase: 572 of 572 block(s) judged, 0 failed).defineSystemViewever stops returning a readonly graph, thedirective becomes unused and TypeScript reports TS2578 — so the gate goes
red exactly when the documented property is lost. That is what probe PD
proves, below, and it is why this is stronger than the ungated entry it
replaces: an ungated page could lose the property in silence.
Two facts had to be established before this shape could be used, and both were:
scripts/check-doc-snippet-types.mjscontains no mention of
expect-error,ts-ignore,ts-nocheckor any@ts-prefix (grep count 0) — it hands each block to a real TypeScriptprogram (
strict: true) and reads the diagnostics back, so the directive isthe compiler's to honour, not the gate's to strip. Confirmed empirically: the
gate is green with the directive in place.
There was no fallback to the fragment marker, so there is no
needs_decisionon this point.The other five: TS2304, paid down by binding to the shipped surface
All five are ambient names the page never defined. None is repaired with a
lenient alias, and none with a hand-copied type.
Component Registry block (1).
buttonMetadatahad no declaration. It nowgets a real self-import of the shipped
ComponentRenderername plus adeclare conststand-in typed to it.counting it as a check.
ComponentRendereris a deliberate IDENTITY alias —Registry.d.tsdocuments it as load-bearing for objectui#6298, it resolves toits own parameter and contributes no type information, and
component-config-single-declaration.test.tspins that identity so it cannotchange unnoticed. So the stand-in binds to a slot that is inert by design.
That is a measurement, not a defect, and nothing is filed for it: unlike batch
24's #8106 (an undeclared
anyon a public prop), this one is intentional,documented and already pinned.
A README-versus-shipped-type contradiction, fixed in the README. While
typing that stand-in, the shipped signature contradicted the page's vocabulary:
register()'s second parameter is the component, its optional third is themetadata, and
getMeta()— notget()— reads metadata back. The block calledthe second argument
buttonMetadataand namedget()'s resultmetadata. Bothare renamed to what the shipped surface says they are, and the prose beneath the
block now states the rule. The gate cannot catch this (the slot is the
identity alias above), so it is named here rather than left to be inferred from
the diff.
Server Action Dispatch block (4).
myAuthenticatedFetch,currentObject,refetchDataandrunnerare all host-injected. Each is now adeclare consttyped from the shipped surface —
ServerActionFetchandActionRunnerby realself-import — so the example is checked against the factory's own
ServerActionHandlerConfigrather than against a copy of it. These are realchecks, and probes P4 and P5 are what make that falsifiable: retype one
stand-in and the config literal rejects it by name.
⭐ One of them turns a documented CLAIM into a compile-time check.
serverActionHandler.d.tssays in prose that the handler it produces is"Assignable to
ActionRunnerHandler". By typingrunneras the shippedActionRunner, the linerunner.registerHandler('script', script)nowverifies that sentence on every commit instead of asserting it.
No
packages/**source touched, no public type widened, no lenient alias added,no gate loosened, and no new fragment marker: declared fragments 158 to 158.
Probes — a base measurement and seven probes, each predicted in writing first
Predictions were written to the scratchpad before any probe ran and were not
amended:
5174-b25-PREDICTIONS.md(md55cbbdd6c967794a467871bad822890e1) atimplementation commit
775ccf34ewith a clean tree. Every mutation is proven ondisk by occurrence counts of both the injected and the deleted text plus
git hash-objectagainst the HEAD blob; every restore is proven by an emptygit diff HEAD; every leg runs under atrap … EXIT INT TERMwith absolutepaths, restoring with
git checkout HEAD --against an absolute path ratherthan a bare checkout from the index. No dist preflight is owed, and that is a
measurement rather than an omission: both mutated paths are read from disk by
the gate itself, so no rebuild sits between a mutation and its reading.
isSystemViewlineREADME.md:134:1, plus TS2339 returning at133:22runnerstand-incurrentObjectto a numberresolveObjectmyAuthenticatedFetchto a void thunkfetchkey naming ServerActionFetchpackages/core/README.md:48PD is the load-bearing one for this batch, and it is load-bearing in an
unusual way: it does not prove a repair, it proves that a deliberately-failing
line is still failing for the documented reason. Moving the directive one line
down — onto
isSystemView(userListView), which does not error — turns the gatered with TS2578, and the push line's TS2339 returns at the same time. Both
halves of the pin fire.
No prediction was falsified. All eight readings hit as written, on the first
implementation head and again after each of the two merges.
Gates — all at
1ad6167a6, clean tree, nothing pushed afterExit codes captured by redirect-then-capture, before any pipe; each row quotes
the gate's own verdict line. The build was forced first
(
pnpm exec turbo run build --filter=./packages/* --concurrency=2 --force,39 successful / 0 cached) and again inside the provenance gate (43 successful /
0 cached); every dist-sensitive gate was then re-run on that force-built dist.
Note the invocation: bare
turbois not on PATH in this container, sopnpm exec turbois what ran.pnpm check:doc-snippetsexit 0 — "Scanned 227 document(s): 215 covered (113 of them hold a ts/tsx block), 12 ungated" / "Covered blocks: 730 — 572 to compile, 158 declared fragment(s)" / "Root bound: no block imports a specifier that resolves only through this repository's ROOT manifest" / "Semantic phase: 572 of 572 block(s) judged, 0 failed" / "Every covered documentation snippet compiles against the built types."pnpm check:doc-fencesexit 0 — "every TypeScript block in 227 document(s) is fenced ts/tsx/typescript"pnpm check:readme-exportsexit 0 — "499 of them self-imports judged (499 real, 0 wrong-path, 0 fabricated)"pnpm check:doc-typesexit 0 — "Every documented component type is registered."node scripts/check-doc-links.mjsexit 0 — "Links are valid across 17 scan roots."pnpm check:doc-example-readersexit 0 — "OK 80 documented symbol(s), 3947 call site(s)"pnpm check:control-bytesexit 0 — "OK (scanned 6499 tracked text file(s); skipped 85 binary)"node scripts/check-node-esm-load.mjs --force-buildexit 0 — "Provenance leg: 37 of 37 gradable entries were built by this tree." Green on its first run, so no gate had to be re-run over a replayed sibling cache.pnpm type-check:scriptsexit 0node scripts/check-changeset-presence.mjsexit 0 — "2 file(s) changed, 0 of them published source of a package the release covers … no changeset is owed." Noskip-changesetlabel applied: this repository declares with an empty-frontmatter changeset rather than that label, and the presence gate says none is owed, so nothing was labelled at all by this seat.node scripts/check-governed-queue-guard.mjs --teston both paths exit 0 — "NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched"pnpm exec vitest run packages/core/— "Test Files 120 passed (120) / Tests 2559 passed (2559)";pnpm --filter @object-ui/core type-checkexit 0, its output echoingtsc --noEmit && tsc -p tsconfig.test.json, so the test tsconfig is genuinely included and the script really ran.grep -naPover the C0/DEL ranges found nothing (exit 1, zero output bytes).Lint, with the narrowing declared and its three evidence items.
pnpm linthere is
turbo run lintper package, so the repository-wide sweep is CI's run;the narrowed run over exactly this diff is
pnpm exec eslint --no-inline-config --format jsonon both paths — 2 entries,0 errors. eslint's own answer for the README is "File ignored because no
matching configuration was supplied", so the real lint surface of this diff is
the one
.mjsat 0 errors and 0 warnings. (1) The population eslint wouldotherwise judge is 4380 files by its own count. (2) That run exits 1 with
93 errors and 12219 warnings, and the touched files carry 0 of them —
measured, and reported rather than smoothed, because a reader must not mistake
the narrowing for a green repository. (3)
eslint.config.jsdeclares noproject,projectServiceorparserOptions.project(grep count 0), sotype-aware linting is off and this diff cannot move the verdict on any untouched
file. Both readings were taken on the final commit
1ad6167a6.Readers of the changed paths
Derived with
git grep -lon both paths on this head, not guessed — 18 testfiles, 724 tests, all green in one run, and the set was identical before and
after both merges.
A2 is CONFIRMED, and its warning was checked rather than assumed.
packages/core/src/utils/__tests__/freeze-schema.types.test.tsdoes namepackages/core/README.md— but only in prose, in its header and in a commentabove its first case. It pins the type behaviour, not the README's text, with
its own inline cases, and it is green untouched. It is also independent
corroboration of the ruling: its case index 3, "the System View itself still
refuses .push on a nested array", asserts
rejected: truefor exactly thestatement this README demonstrates — and it compiles against source while
the snippet gate compiles against dist, so the two legs resolve differently
on purpose. The
@ts-expect-erroradded here is the dist-side half of aproperty the source side already pins.
The other two readers of the README are
scripts/__tests__/check-doc-links.test.tsandpackages/core/CHANGELOG.md(prose, not a reader). The remaining fifteen are readers of the gate file.
Batch 24 counted 16 readers; this batch counts 18 because its document has two
live readers of its own, which batch 24's did not.
Out of scope
Nothing was filed, and that is a finding rather than an omission. The one
candidate — that
ComponentRegistry.register's component parameter contributesno type information — was traced to a deliberate, documented, already-pinned
identity alias (objectui#6298) rather than to an oversight, so filing it would
have added noise to triage. It is reported in the section above instead. No
dedup search was run, because a search with nothing to dedup is not a reading.
This PR is a DRAFT and stays a draft: this seat does not flip ready, does not
enable auto-merge, and touches no labels or assignee.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Generated by Claude Code