test(types): pin every AnyComponentSchema arm to a named zod export (objectui#8784) - #9070
Conversation
…objectui#8784) objectui#7917 found two arms with no named export on the `./zod` barrel, so `breadcrumb` and `object-tree` could not be validated on their own. PR #8777 repaired both and nothing kept it repaired. Each blindness was re-measured on this base rather than inherited: `zod-mirror-parity.test.ts` builds its export population with `/^export const NAME/m`, which matches a DECLARATION and can never match `export { NAME } from './x.js'` — so it is structurally blind to a missing re-export even though `index.zod.ts` is one of the files it reads; no test pinned a list or a count on the barrel; and `scripts/measure-strict-authoring-face.mjs`, the only script that computes the census, is a self-described MEASUREMENT THROWAWAY wired into no `package.json` script and no workflow. The pin derives the arm list on every run — flatten the union recursively through nested unions and `z.lazy`, then match each leaf arm to a named export BY IDENTITY. Both properties are controls in the file rather than claims in a comment: a walk that stops at the top-level sub-unions scores exactly `options.length` arms, and a name-based match is satisfied by `export { NavigationSchema as BreadcrumbSchema }`, the parent sub-union under the arm's name, which passes every behavioural leg of #8777's pin. No count is hard-coded; the only bound asserted against the real union is a floor read off that union's own top-level option count. Red on arrival, ledgered rather than repaired: `507b61bf7` (PR #8763, objectui#8499) armed four arms in `layout.zod.ts` and `form.zod.ts` and touched no barrel, 48 minutes after objectui#8784 was filed on a census reading 107 arms / 107 named / 0 unnamed. This base reads 111 arms / 154 type literals / 106 named / 5 unnamed. Four rows point at objectui#9067, which holds the ruling, because exporting them mints new names on a published surface; the fifth, `RetiredKanbanNodeSchema`, is a refusal arm the barrel already declares deliberately internal. A stale-row leg deletes any row the moment its arm is exported or stops existing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
✅ 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
|
Contract reviewPR #9070 · card objectui#8784 · head Charter read fresh from objectstack Tier fuse — MEASURED
Independence pair (machine-readable)
① Derived judgments — each named, measured, judgedBaseline I derived myself (two instruments, my own walk, not the pin's). Instrument 1: plain Node over the BUILT
Same walk at
② Semver grading vs. the changesetEmpty frontmatter — correct. ③ Dev flags, each answered or escalated
CI on the head
Platform artifacts, not findingsREST-appended PR-body footer; repo-wide Not measured
VERDICTThe pin's mechanism passes every measurement I could make — barrel read, identity matching, derived floor, both firing controls byte-identical, restores proven, ledger stale-leg correct, semver correct, no widening. What fails is factual: the diff's own prose (the top docblock's "one of them was LIVE" under the silent-failure modes, and the VERDICT: FAIL — patch round (prose and PR body only; the pin itself needs no change) Generated by Claude Code |
…d (objectui#8784) The contract review on `fc1ab897c` returned FAIL on a factual point, and it is right. This commit changes prose and two hardening details; the census, the identity matching, the ledger rows, the firing controls and the derived floor are untouched. WHAT WAS WRONG. The docblock filed `507b61bf7` (PR #8763, objectui#8499) under the barrel's SILENT failure modes, beside `d908a82f4`'s collateral drop and PR #1892's omission, and `ABSENT_PENDING_RULING`'s comment argued from "the same evidence objectui#7917 used to conclude its two omissions were accidental". That is refuted by three records, re-derived here rather than taken on trust: 1. `.changeset/8499-node-slot-registered-arms.md`, present in this very tree (blob c055695 on origin/main), declares the omission and its reason — exporting a `SemanticElementSchema` / `HtmlElementSchema` pair "would publish a NAMED authoring surface (`z.enum` families, not per-tag schemas) that this card's ruling does not cover", so "the metric is left to move and said out loud instead", and "whoever wants the number back down should treat naming these families as its own decision". It also declares the movement it caused: `unexportedNodeSchemas` from `[breadcrumb, object-tree]` to 49 node types, "Measured at this branch's head, not estimated." 2. objectui#8499's ceiling review raised exactly this as blocking F1 (`5597569641`: the four "are published by the union but unreachable by name from any published entry"), with the eight barrel lines named as the remedy. 3. That review then PASSed the deferral "on the surface-widening reason alone" (`5598263402`). So the omission was declared, reasoned and reviewed. The state "a decision is owed" is correct and the rows stay; their stated BASIS was wrong. WHAT CHANGED. The docblock gains a third, non-silent way an arm loses its barrel line and says why the pin still earns its place against it: the declaration lives in a `.changeset/*.md`, which is consumed and deleted at release (measured: `59f61cfb8` "chore: release packages (#4655)" removes the batch it versioned), so the absence outlives its own explanation. `ABSENT_PENDING_RULING` becomes `ABSENT_PENDING_DECISION`, and its comment now carries the recorded argument AGAINST naming these families rather than only the case for it. The failure message names all three acceptable answers. Timing corrected: PR #8763's `merged_at` is 2026-09-09T08:11:20Z; `07:53:59Z` was the squash commit's committer date, and the "48 minutes" arithmetic built on it is gone. The "13 sub-unions" aside is corrected to 12 sub-unions plus one object arm. HARDENING, both nits the review raised. `hasRow` replaces `key in LEDGER`, so an arm declaring `type: 'constructor'` cannot ledger itself off `Object.prototype`; `Object.hasOwn` does not compile under this package's `"lib": ["ES2020", "DOM"]` (tsc TS2550), so the `.call` form stands with that measurement recorded beside it. The walk's `if (!def || seen.has(schema)) return` is split: a member with no zod definition is now pushed to `unresolved` instead of being dropped, which is what the docblock already promised. Readings unchanged after both: types suite 172 files / 3385 tests green, `type-check` exit 0, eslint 0/0 on the file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
✅ 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
|
… changeset One clause, on the seat's ruling. `.changeset/8784-arm-named-export-pin.md` is release-note input — it is consumed into `packages/types/CHANGELOG.md` at the next publish — so it outlives the PR body that already carries the correction, and it was the last place in this branch still reading off the committer date. Replaced: "and touched no barrel — 48 minutes after objectui#8784 was filed on a census reading 107 arms / 107 named / 0 unnamed." With: "and touched no barrel deliberately (PR #8763 merged 2026-09-09T08:11:20Z; the omission and its reason are declared in `.changeset/8499-node-slot-registered-arms.md`)." ⛔ The interval is not restated as 66 minutes. Measured here — card created 2026-09-09T07:05:02Z, PR objectui#8763 `merged_at` 2026-09-09T08:11:20Z, so the true figure is 66.3 rather than the 48 that came off `507b61bf7`'s committer date 07:53:59Z — but the framing that made an interval meaningful was the accident premise, and that premise is withdrawn: the barrel omission was declared in objectui#8499's own changeset, raised as blocking F1 (`5597569641`) and passed on the surface-widening reason (`5598263402`). Nothing else in the file moves. Gates on the edited tree: check-changeset-presence exit 0 ("Every one of them has an EMPTY frontmatter"), check-changeset-no-major exit 0, check-changeset-fixed exit 0, check-changeset-overwrite exit 0 ("No pre-existing changeset was modified or deleted"), check-control-bytes exit 0, plus a direct `grep -naP` control-byte scan of the edited file (exit 1, no lines). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
✅ 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
|
…e pin's docblock
One clause, on the seat's ruling. Round 2 corrected this fact in the pin's
docblock and did not carry the correction into the changeset, so the PR shipped
two faces disagreeing about the same thing — and the changeset is the face that
is published into `packages/types/CHANGELOG.md` and outlives the docblock's
audience.
Before: "a walk that stops at the top-level sub-unions scores exactly
`options.length` arms"
After: "a walk that stops at the 13 top-level members — 12 sub-unions plus one
object arm (`AppComponentSchema`, an arm at depth 1), not 13 sub-unions — scores
exactly `options.length` arms"
The wording is taken from the docblock rather than paraphrased, and the match is
measured rather than eyeballed: with jsdoc leaders stripped and whitespace
collapsed, the phrase "12 sub-unions plus one object arm (`AppComponentSchema`,
an arm at depth 1), not 13 sub-unions" occurs exactly once in each file.
⛔ The claim itself is unchanged — such a walk does still score exactly
`options.length` arms, which is the property the derived floor rests on.
⛔ Nothing else in the file moves: "Red on arrival, reported rather than declared
away" stays byte-unchanged (it asserts nothing false and is a borrowed repo
idiom, `.changeset/4971-declared-arm-subset-gate.md`), and the withdrawn
interval stays dropped rather than restated.
Gates on the edited tree: check-changeset-presence exit 0 ("Every one of them has
an EMPTY frontmatter"), check-changeset-no-major exit 0, check-changeset-fixed
exit 0, check-changeset-overwrite exit 0 ("No pre-existing changeset was modified
or deleted"), check-control-bytes exit 0, plus a direct `grep -naP` control-byte
scan of the edited file (exit 1, no lines).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
✅ 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
|
|
Contract review record — ADOPTED VERBATIM. Ruling produced by a context-isolated ceiling-tier ( Contract reviewPR #9070 · card objectui#8784 · head Tree: fresh ① What the card asks for, and whether the diff delivers exactly thatThe card (#8784) asks for a keeper of "every The diff is two added files, +517/-0 (
One deviation from the card's wording: the card suggested the gate "read those [seven 'Deliberately NOT exported'] markers rather than invent a second ledger". The dev built an in-file ledger instead. Measured: the marker sites I can find ( What the FAIL demanded, and whether it arrived. (1) Correct the two docblock passages so the four are described as a declared, reasoned, reviewed deferral citing the #8499 changeset — done: the top docblock (lines 36-58) and the Anything the FAIL did not demand that has since gone wrong. Nothing in the mechanism: the code delta since Protocol. The diff touches no TypeScript face, no zod face, no Scope. Nothing outside the card. ② What I re-derived from the treeAll commands from the clone root unless noted; exit codes captured to files before any pipe. Runs on the head
My own census (independent walker, Firing legs on disk (HEAD blob
Both hashes are byte-identical to the ones the PR body and the round-1 ruling report. Both legs can fire for the stated reason: Does the pin pin — ablations of the test file itself (each restored,
Historical and prose claims, re-derived
Not measured (an unmeasured thing is not a clean thing): ③ FindingsBlocking: none. Non-blocking
IndependenceSame-session test, applied literally to what the two lines carry: VERDICT: PASS — mechanism, firing legs, census and the FAIL's demands all re-derived; seven non-blocking prose/hardening items in ③ Generated by Claude Code |
|
Seat correction — F6 falsifies the premise I overrode the dev on. Recording it here because I asserted it to the dev as the decisive ground. In round 3 the dev recommended shipping two residuals untouched. I overrode it and authorised one, and the reason I gave was:
The bolded half is false for this changeset, and the review measured both sides of it rather than one:
⭐ The error was a one-sided measurement, and it was available to both of us. The dev reported the mechanism as "confirmed by measurement rather than assumption", citing What does and does not change⛔ Nothing in the tree moves. The review is explicit and I agree: both edits my override produced are correct on their own merits — a stale interval removed, and two faces of one PR made to agree. A correct edit reached through a false premise is still a correct edit. ⇒ ⛔ this is not a reason to revert round 4, and ⛔ not a reason to move the head and void a PASS.
The generalisable form, since this is the second time tonightI have twice reported a negative from a probe whose other half I never ran — once with a control that could not fire (objectui#8563, objectui#8811), and now once with a measurement that established half a mechanism and let me infer the rest. ⛔ "X is deleted at release" does not establish "X is published at release." Both halves, or no claim. ⭐ And the dev was right that the review round was free; that part of my override stands. It was the reason I gave for spending it that was wrong, not the arithmetic. Generated by Claude Code |
Landing provenance — PR #9070 (card objectui#8784)Reviewed and landed head: ① in-seat clause-② contract review — PASS ON RECORD
⭐ The ruling was produced by a context-isolated ceiling-tier subagent fed only the card, this PR, and the prior FAIL
⭐ The review overturned this seat, and the correction is part of the recordFinding F6 falsified the premise on which I overrode the dev in round 4. I argued the changeset "is the face that gets published into
This PR's changeset has empty frontmatter ⇒ deleted at release, published nowhere. The dev's supporting evidence measured the deletion and never the copying, and I took the inference. ⛔ "X is deleted at release" does not establish "X is published at release." ⇒ ⛔ Nothing in the tree was reverted — a correct edit reached through a false premise is still correct — but the PR body, which becomes the squash message and therefore permanent history, was PATCHed so neither paragraph asserts the false mechanism. Seat correction at ② the enqueue gates
Run before the carriers were stripped, so "both carriers agree" was read at
③ every check, not a required subset35 check-runs on charter provenance, with its own controlsThe seven governing files are byte-identical between the clone's carriers — STRIPPED, both together
Landing by squash through the merge queue. Generated by Claude Code |
Fixes #8784
Adds
packages/types/src/__tests__/arm-named-export-8784.test.ts: everyAnyComponentSchemaarm is a NAMED export of@object-ui/types/zod, or carries a ledger row saying why it is not. Test-only; the changeset declares an empty frontmatter.What the pin does
Derive the arm list on every run — flatten
AnyComponentSchemarecursively through nested unions andz.lazy— then match each leaf arm to a named export of the barrel by identity. Two properties are load-bearing, and both are controls inside the file rather than claims in a comment:Object.entriesof the../zod/index.zod.jsmodule namespace, i.e. the runtime export surface itself, so a re-export counts and a declaration that never reached the barrel does not.⛔ No count is hard-coded. The only bound asserted against the real union is a floor read off that union's own top-level option count, which is what proves the walk recursed instead of stopping at those 13 top-level members (12 sub-unions plus
AppComponentSchema, an object arm at depth 1).The category modules are imported too, but only to turn a failing arm into a name a reader can act on —
namesOntakes ONE namespace and the real reading passes it the barrel.Round 2 — what the contract review corrected, and what it did not
Round 1 (
fc1ab897c) came back FAIL on a factual point, mechanism passing. Round 2 is prose plus two hardening nits; the census, the identity matching, the ledger rows, the derived floor and both firing controls are unchanged, and the firing controls were re-run on the patched head to prove it (same mutation hashes, same output).What was wrong. Round 1's docblock filed
507b61bf7(PR #8763, objectui#8499) under the barrel's SILENT failure modes, next tod908a82f4's collateral drop, and argued the four omissions were accidental. They were not. Three records say so, re-derived here rather than taken on trust:.changeset/8499-node-slot-registered-arms.md, present in this very tree (blobc055695d1onorigin/main), declares the omission and its reason: exporting aSemanticElementSchema/HtmlElementSchemapair "would publish a NAMED authoring surface (z.enumfamilies, not per-tag schemas) that this card's ruling does not cover: the ruling is 'arm the registered renderers', not 'add public exports to@object-ui/types'. So the metric is left to move and said out loud instead. ⇒ … whoever wants the number back down should treat naming these families as its own decision." It also declares the movement it caused —unexportedNodeSchemasfrom[breadcrumb, object-tree]to 49 node types, "Measured at this branch's head, not estimated."5597569641): the four "are published by the union but unreachable by name from any published entry", with the eight barrel lines named as the remedy.5598263402).⇒ A deferral with a written reason, reviewed twice. Withdrawn accordingly: round 1's claim that this was the objectui#7917 defect recurring silently, and its reading of the stale census as the card's thesis arriving as evidence. objectui#8784's thesis — that the invariant has no keeper — stands on its own and does not need this commit.
What survives, and is now the docblock's argument. The pin still earns its place against a declared deferral, for a reason about where the declaration lives: a
.changeset/*.mdis consumed and deleted at release — measured,59f61cfb8"chore: release packages (#4655)" removes the batch it versioned — so the absence outlives its own explanation, and once the explanation is gone a deferred non-export and a collateral drop are the same two lines of nothing inindex.zod.ts. The ledger moves that reason into the tree, where it is re-read on every run and deleted only when it stops being true. The classification is unchanged and was independently confirmed: the #8499 changeset itself leaves naming to "its own decision", so "a decision is owed" is the right state for those four rows.ABSENT_PENDING_RULINGis renamedABSENT_PENDING_DECISIONand its comment now carries the recorded argument AGAINST naming these families, not only the case for it — so a reader who meets the rows meets the counter-argument too.Hardening, both nits the review raised.
hasRowreplaceskey in LEDGER, so an arm declaringtype: 'constructor'cannot ledger itself offObject.prototype;Object.hasOwnis the modern spelling and does not compile under this package's"lib": ["ES2020", "DOM"](measured: tscTS2550, "Try changing the 'lib' compiler option to 'es2022' or later"), so the.callform stands with that measurement recorded beside it — a lib bump is a build-config change this pin does not own. And the walk'sif (!def || seen.has(schema)) returnis split, so a member carrying no zod definition is pushed tounresolvedinstead of dropped, which is what the docblock already promised. Neither moved a reading: the types suite is identical at 172 files / 3385 tests, andunresolvedis still empty on the real union.The census on this base
Base
7f27bc54343e6193f11ec3f58927fb9afb1bc635. The card reads 107 arms / 107 literals / 107 named / 0 unnamed. This base reads 111 arms / 154typeliterals / 106 named / 5 unnamed, derived as described above. The review reproduced the same four numbers with two instruments of its own, and reproduced107 / 107 / 107 / 0atee4d19f6c, the parent of507b61bf7— so the card's census was correct when it was taken.Sequence, by
merged_atrather than committer date: card filed 2026-09-09T07:05:02Z → PR #8777 merged 07:20:02Z (the objectui#7917 repair, census 107/107/0) → PR #8763 merged 2026-09-09T08:11:20Z, arming four arms inlayout.zod.tsandform.zod.tswith the barrel deliberately untouched. (07:53:59Z, which round 1 used, is507b61bf7's committer date, not its merge time.)The four are NOT exported here: a new exported symbol is the
Clause-2branch and the dispatch said stop and report. objectui#9067 carries the decision and its framing has been corrected there by the seat. The fifth unnamed arm,RetiredKanbanNodeSchema, is a refusal arm the barrel already declares deliberately internal in as many words (objectui#8802) and is ledgered as a decision taken. A stale-row leg deletes any row the moment its arm is exported or stops existing, so the ledger cannot outlive its cause — and Legs A and B below show any arm outside those five rows still reddens.Cross-check between the two instruments: the five unnamed arms carry 7 + 37 + 2 + 1 + 1 = 48
typeliterals, which is the #8499 changeset'sunexportedNodeSchemasmetric after PR #8777 landed (its own conditional, "If PR #8777 lands first, the same movement reads0to47") pluskanbanfrom objectui#8802.Firing controls — run for real, on the committed tree, both restored, re-run on the patched head
Both legs mutate ONLY
packages/types/src/zod/index.zod.ts, which is the shape of both historical breaks. Each leg proves the mutation reached disk by counting the anchor line before and after and by comparinggit hash-objectagainst theHEADblob; each restore is proved by hash equality plus an emptygit diff HEAD.Leg A — the dropped re-export. Delete the barrel's
BreadcrumbSchema,line, module untouched. This isd908a82f4in miniature. It can fire becausebreadcrumbis a live arm that IS named on the barrel today (PR #8777 put it back) and carries no ledger row, so the mutation moves it from named to unnamed — the exact transition the pin claims to detect, on a symbol this PR did not introduce.The failure names the arm:
Leg B — the parent union under the arm's name. Replace that line with
NavigationSchema as BreadcrumbSchema,. The NAME is present and bound to the parent sub-union. It can fire for the same reason as leg A, and it is the sharper control because a name-based census goes green on it:On the SAME mutation,
breadcrumb-object-tree-nameable-7917.test.tsis fully green —vitest exit 0,Tests 9 passed (9). That reproduces the ceiling reviewer's adversarial finding on this base: the accept leg succeeds, the near-miss refusal is byte-identical, another node type is still refused. Only identity catches it.Restore. After both legs:
RESTORED: hash matches HEAD blob and git diff HEAD is empty, thenRESTORED : vitest exit 0,Tests 17 passed (17),git status --porcelainempty. Both legs were re-run after the round-2 hardening and produced byte-identical mutation hashes and identical output, which is how "the walk did not change" is a reading rather than an assurance.Four further controls live in the file permanently rather than as one-off runs — a dropped re-export, the parent-union alias, a NESTED union whose arms must be counted instead of the union (the "13 arms / 2 literals" failure), and a
z.lazyarm named through either side of the wrapper.Verification
All commands run from the repository root, on the patched head. Exit codes captured to a file before any pipe; heavy runs serialised through the shared verify lock.
pnpm exec vitest run packages/types/—Test Files 172 passed (172),Tests 3385 passed (3385), exit 0. 172 = 171 tracked test files plus this one, so the new file is in the run rather than assumed to be.pnpm --filter @object-ui/types type-check— exit 0 (tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json).tsc -p tsconfig.test.json --listFileswas grepped and returns the file, 1 hit.pnpm exec eslint --format jsonon the changed file inpackages/types— 0 errors, 0 warnings, counts read from the JSON. The package baseline measured in round 1 was 242 files, 0 errors, 278 warnings; the repo-wide baseline is red onmain.node scripts/check-changeset-presence.mjs— exit 0: "Every one of them has an EMPTY frontmatter — declared as releasing nothing".node scripts/check-control-bytes.mjs— exit 0, 7258 tracked text files scanned. The changed file was also scanned directly withgrep -naP; grep exited 1 with no output lines, which is a reading on that file and not a general claim about the tree.node scripts/check-new-cross-file-line-citations.mjs— exit 0, 0 new citations.node scripts/check-vi-mock-override-shape.mjs— exit 0.Not run locally and left to CI: the repo-wide lint and type-check farms, the CLI self-check, and every gate outside the families above.
Changeset level, from this repository's own precedent
Empty frontmatter, unchanged in round 2.
scripts/check-changeset-presence.mjs's header is the authority and states it in as many words: "No carve-out for test files undersrc/. A change confined tosrc/__tests__/is answered by the empty-frontmatter exemption, in one line." Read by content, the nearest precedent is.changeset/4971-declared-arm-subset-gate.md— the same shape of change (a test-only gate over a declared surface, carrying reasoned, issue-backed exemptions and a stale-exemption leg), declared as releasing nothing. Nothing inpackages/types/package.json'sfileslist moves and no published contract field moves, so no package is released by this change..changeset/8784-arm-named-export-pin.mdstill carried round 1's "48 minutes after objectui#8784 was filed" — the same arithmetic corrected everywhere else, off the committer date — while the patch instruction listed the changeset among the files not to touch. The seat ruled to correct it.packages/types/CHANGELOG.md, so it outlives the PR body — is FALSE for this changeset, and the contract review on19f8ab48dmeasured both sides of it: in release commit59f61cfb8, 0 of the 62 deleted changesets with EMPTY frontmatter reach any CHANGELOG hunk, against a control of 40/40 for the non-empty ones. This file has empty frontmatter, so it is deleted at release and published nowhere. My own earlier evidence (git log --diff-filter=Dshowing the release commit deleting the batch) measured the DELETION and never the COPYING, and publication was inferred from deletion — ⛔ "X is deleted at release" does not establish "X is published at release". The edit stands on its own merit instead: a knowingly wrong figure in a file this PR ships is worth one clause whether or not anyone downstream reads it. That clause now reads "and touched no barrel deliberately (PR #8763 merged 2026-09-09T08:11:20Z; the omission and its reason are declared in.changeset/8499-node-slot-registered-arms.md)". ⛔ The interval is not restated as its true value of 66.3 minutes: what made an interval meaningful was the accident premise, and that premise is withdrawn. Nothing else moved in that round.packages/types/CHANGELOG.md" rationale given at the time, which the contract review falsified for empty-frontmatter changesets (see the round-3 note above). That clause now reads: a walk that stops at the 13 top-level members — 12 sub-unions plus one object arm (AppComponentSchema, an arm at depth 1), not 13 sub-unions — scores exactlyoptions.lengtharms. The wording is taken from the docblock rather than paraphrased, and the match is measured rather than eyeballed: with jsdoc leaders stripped and whitespace collapsed, that phrase occurs exactly once in each file. The claim itself is unchanged. ⛔ The paragraph's opening clause, "Red on arrival, reported rather than declared away", stays byte-unchanged — it asserts nothing false and is a borrowed repo idiom (.changeset/4971-declared-arm-subset-gate.md), so rewording it would be editing voice rather than fact.Scope
⛔ No arm added or renamed. ⛔ No existing parity check weakened —
zod-mirror-parity.test.tsis untouched, and this pin asks a question that census is structurally unable to ask rather than taking over any part of it. ⛔ No export added: that is objectui#9067's decision to take, not this PR's.The diff touches no governed surface. It stays
draftregardless: landing is the seat's act.Carries
needs:contract-reviewto match the card's carrier, per the dual-carrier rule.Generated by Claude Code
Generated by Claude Code