Uh oh!
There was an error while loading. Please reload this page.
test(types): split the unmirrored ledger by remedy — 23 runtime-only callbacks (#6152) - #6181
Merged
Merged
Conversation
…callbacks (#6152) `UnmirroredDeclared` recorded 121 declared-but-unmirrored keys. 23 of them are callback-shaped (`on*`) and mirroring is the wrong remedy for every one: measured on the shipped `dist/*.d.ts` they are already function-only, so the only available mirror spelling is `z.function()` — which no serialized authored document can satisfy. Mirroring them would move 23 rows off a ledger while enforcing nothing, converting visible debt into invisible non-enforcement. Narrowing is not available either (there is no string branch left to remove, unlike the #4453 precedent), and removing the declarations would break shipped renderers: 21 of the 23 are read off `schema.*` in renderer source, fed by sibling components that synthesize a schema-shaped object in code and render it through `SchemaRenderer`. So they are RECLASSIFIED, not fixed: a new `RuntimeOnlyDeclared` ledger holds all 23, `UnmirroredDeclared` goes 121 -> 98 keys, and the two are reconciled against ONE measurement through the union at `RecordedUnmirrored`. The move is stated in the seed comments of both ledgers, including the 16/7 oversight-vs-policy split, so 121 is not silently re-citable as the mirroring debt. The new category is a ratchet, not a waiver, pinned in both directions on synthetic pairs: a fresh callback-shaped unmirrored key reddens until filed, a recorded one that leaves the measurement fails as STALE. Shape pins refuse a callback key in `UnmirroredDeclared` and a non-callback key in `RuntimeOnlyDeclared`, and a disjointness pin refuses double-filing. No published type, no mirror and no runtime behaviour changes. Part of #6152 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
Contributor
✅ 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
|
yinlianghui-tw
marked this pull request as ready for review
August 24, 2026 23:13
This was referenced Aug 24, 2026
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #6152 — implements the PM's option A ruling (#6152 (comment)). This lands the reclassification only; the other 98 keys, every mirror,
KnownDriftandNarrowerThanDeclaredare untouched.What changed
UnmirroredDeclaredrecorded 121 declared-but-unmirrored keys. 23 are callback-shaped (on*), and mirroring is the wrong remedy for every one of them. They move, whole and still pinned, into a newRuntimeOnlyDeclaredledger.⛔ This is a RECLASSIFICATION, and nothing here was repaired. Nothing was mirrored, no declaration was removed, nothing was waived. The same 23 facts are still measured and still reconciled — under a different remedy. 98 is the mirroring debt; 98 + 23 is what "121" used to mean. That statement is written into the seed comment of both ledgers and into the file header, so 121 cannot be re-cited as the mirroring debt the way #6141's numbers were.
Round 1's measurement (comment above) falsified the card's premise in three places, and the ruling followed the measurement:
dist/*.d.ts, so the only mirror spelling available isz.function()— which no serialized authored document can satisfy. It would move 23 rows off a ledger while adding validator surface no authored payload can populate: visible debt converted into invisible non-enforcement, the exact shape this guard family exists to close.onEventClickreaches CalendarView through the spread and throws an UNCAUGHT error on click — needs a contract decision, not a strip #4453 narrowed a key that acceptedstringOR a function; there is no string branch left here to remove.schema.*in renderer source, fed by sibling components that synthesise a schema-shaped object in code and render it throughSchemaRenderer.73
on*keys are already mirrored repo-wide (56z.function(), 11z.string(), 3z.any(), 3 named). So the mirrors do not omit callbacks by policy:DataTableSchema(mirror already carries 4 callbacks),FormSchema(3),DetailViewSchema(1, in the other dialect)ObjectFormSchema5,ObjectGridSchema1,ObjectViewSchema1objectql.zod.tshas zeroon*and zeroz.function(), and says so at:164—successMessageapplies "when noonSuccesshandler is given"Reclassifying all 23 is still right (same remedy), but a later reader must not infer uniform intent from uniform treatment.
The new ledger also records the standing prior art that reached this verdict independently for 3 of the 23 —
docs/audits/2026-07-objectview-detailview-schema.md:148and:237-241("live state and callbacks, not metadata", "must never enter a serializable protocol", "a props bag wearing a schema's clothes") and #4650's two-layer split — plus the evidence the declaration was already not trusted:DetailView.tsx:1402reads a declared key through an(schema as any)cast at its only read site.The new category is a ratchet, not a waiver
One measurement, two ledgers on the recorded side, reconciled through the union at
RecordedUnmirrored. Four new pins keep the split honest, and all four were ablated (mutation proven on disk by anchored counts, restored bygit checkout HEAD --and verified byte-identical):EXIT 2assertionUnmirroredMatchesLedger—Type '"data-display.zod.ts#DataTableSchema"' is not assignable to type 'never'EXIT 2assertionUnmirroredMatchesLedger—Type '"objectql.zod.ts#ObjectGridSchema"' is not assignable to type 'never'EXIT 2assertionNoCallbackShapedKeyInUnmirroredDeclared(:1066) — the union is deliberately blind to which half, so this pin is what catches itEXIT 2assertionRuntimeOnlyIsCallbackShapedOnly(:1080) — this is what stops the category becoming a bucketEXIT 2assertionLedgerHalvesAreDisjoint(:1096) +…NoCallbackShapedKey…(:1066)The blindness of the union is not a gap discovered later — it is pinned as
assertionSplitLedgerIsBlindToWhichHalf, next to the three synthetic-pair pins for the split ledger's growth and shrink directions.Verification — all at
1df712b5fHeavy steps serialized through the shared verify lock; exit codes captured before any pipe.
Ledger counts re-derived mechanically (brace-matched interface, comments stripped), not inherited:
98 + 23 = 121: the 23 are visible and countable in the new category, so the reclassification is distinguishable from a waiver by measurement rather than by claim.
Out of scope, deliberately
No mirror edit · no declaration removed · the other 98 keys ·
KnownDrift·NarrowerThanDeclared· #6175 (ObjectGrid column persistence, filed separately and referenced but not addressed here) · theonColumnReorder/onColumnsReordernear-duplicate, recorded in the ledger as an open ruling · the 3 spec-derived pairs beyond what reclassification mechanically required (ObjectViewSchema's other ten keys stay inUnmirroredDeclaredand stay routed to #2231).One observation, recorded in the ledger rather than acted on:
ObjectFormSchema.submitHandleris handler-shaped but noton*, so the/^on[A-Z]/reclassification did not take it. It stays inUnmirroredDeclareduntil someone measures it.Test-only; the changeset declares an empty frontmatter, so nothing releases.
Generated by Claude Code