test(types): judge the zod-mirror-parity WIDER ledger per ARM, not per key - #8323
Merged
Conversation
…r key objectui#8252. `WiderThanDeclared` recorded one prose class per ENTRY, and the clause for `DashboardComponentSchema.widgets` was three words — "`widgets` is SCHEMA-NODE" — true of its second arm and false of its first, a concrete component node the TypeScript face was missing whole (objectui#7952, declared by #8296 as c842594). A per-KEY verdict over a per-ARM fact. `WIDER_ARMS` records one verdict per union arm of each ledgered key. The arm ENUMERATION is measured from the mirror values (`measureMirrorArms`); the verdicts are judged. Pinned: every ledgered key has exactly one row, every row names one verdict per MEASURED arm, and objectui#7952's key cannot collapse to a single verdict. The header gains this ledger's figures — the fifth ledger and the only one objectui#7733 / objectui#8222 did not reach, which is how "27 SCHEMA-NODE keys" could be quoted while the re-derived figure is 25. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QtGhnU3WnnWyiWeYQhw2aX
…a property access The dotted `<pair>.<key>` spelling put a property-read of one mirror's handler-array key into a file that already names that mirror, which is anchor A of the reader census in `handler-keys-string-any-mirrors-7344.test.ts`: that census read this file as a third reader and failed, correctly. Separator moved to `::` rather than widening the other census's allow-list, and the docblock records the collision without reproducing it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QtGhnU3WnnWyiWeYQhw2aX
…ity-ledger-per-arm
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
|
3 tasks
os-zhuang
marked this pull request as ready for review
September 7, 2026 12:41
This was referenced Sep 7, 2026
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 free
to 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.
Fixes #8252
What
The
WiderThanDeclaredledger inpackages/types/src/__tests__/zod-mirror-parity.test.tsgains a second table,WIDER_ARMS, holding one verdict per union arm of each ledgered key instead of one prose class per entry. The arm ENUMERATION is measured from the mirror values (measureMirrorArms, a runtime leg for the same reason the blind-region leg is at runtime); the per-arm VERDICT is judged and recorded. The header gains this ledger's figures, derived and pinned.⛔ No declaration and no mirror was touched. This card classifies and re-files; it does not repair.
The census — re-derived, and the card's "27" is wrong
The card's figure is 27, inherited from #7759's exclusion set. Re-derived from the ledger itself on
c842594, the SCHEMA-NODE bucket is 25 — 24 keys whose every arm is the artifact, plus 1 MIXED. Two independent derivations agree on the 25: the ledger's own docblock classes, and a runtime walk marking every key whose slot reaches a recursion-breaking lazy node. The whole ledger is 34 entries / 52 keys / 61 arms; the CONCRETE half is 27 and has not moved since #7759.⭐ Why the 27 could rot unnoticed:
WiderThanDeclaredis the one ledger with no figure in this file's header at all. objectui#7733 pinned three ledgers' entry counts, objectui#8222 their key totals, and both name the ledgers they reach — this one is in neither. So "27 keys / 21 pairs" was published by #7759, quoted into #8252's card body, and went two out with every pin in this file green. That hole is closed here: six figures for this ledger now live in the header and are read offWIDER_ARMSand the mirrors.Per-arm table
Nine of the 52 keys are unions at the mirror's slot. The other 43 are single-arm — and a single-arm key has no sibling to hide behind, which is the entire #7952 mechanism, so each is recorded as a one-verdict row rather than reasoned about.
complex.zod.ts#DashboardComponentSchemawidgetsc842594. The positive control.app.zod.ts#AppComponentSchemalabelobjectql.zod.ts#ObjectGridSchemalabelobjectql.zod.ts#ObjectGridSchemadescriptionform.zod.ts#SliderSchemadefaultValueform.zod.ts#SliderSchemavalueform.zod.ts#CalendarSchemadefaultValueform.zod.ts#CalendarSchemavaluelayout.zod.ts#ContainerSchemamaxWidth⇒ Nothing was re-filed, and that is the finding. Of the nine union keys, exactly one is in the SCHEMA-NODE bucket and it is #7952's own — already ruled and already repaired. The other eight were each already CONCRETE in #7759's disposition lane, arm by arm. The #7952 shape does not recur. Filing a card for a divergence already sitting in an open lane would have been queue noise; filing nothing into #7759 is correct because it gains nothing it does not already hold.
The census also looked one level down — every arm's own shape properties, for a union mixing a schema-node arm with a concrete one — and found none.
Two bounds, stated
DashboardComponentSchema.widgetsis a two-arm union in zod and a one-arm array in TypeScript — the ruled-legalmetric-cardcomponent node parses green andtscrefuses it, and the parity ledger files the key as SCHEMA-NODE #7952 describes the component arm as having "no schema-node recursion in it at all". Measured, it has — throughBaseSchema's ownbody/childrenslots. Its conclusion survives the correction (what makes the arm CONCRETE is itstypeenum and passthrough shape, not the absence of the artifact), but it is why the verdicts are judged and not derived: at runtime both ofwidgets' arms reachSchemaNodeSchema, so "reaches a lazy node" separates neither arm from the other and would classify every component-node arm in the repo as an artifact.The pins, and each proved able to fail
Four legs, each committed first, mutated on disk with a before/after grep, run, then restored (script carries a
trap … EXIT INT TERM; restore proven by blob hash612c8634equal toHEADand an emptygit diff HEAD). Run under the shared verify lock on final headafcd389.['SCHEMA-NODE'](two-arm spelling 1→0, collapsed 1)ViewSwitcherSchema::views, 1→0)z.array(z.union(…))reads one armoptional, so a multi-arm key is still seen. The arity pin is what catches it. Recorded because a non-vacuity leg that looks stronger than it is, is the failure this file exists to prevent.⭐ Incidental live proof: the merge of
origin/mainin this branch brought in #7735 ("zod mirrors stop authoring defaults"), which edits the mirrors these pins read. The suite stayed green through it — had a mirror's arm count moved, the header-figures pin reads the mirrors and would have said so.The first spelling of a row key joined the pair and the key with a DOT. That puts the literal text of a property read of one mirror's handler-array key into a file that already names that mirror — which is anchor A of the reader census in
packages/types/src/__tests__/handler-keys-string-any-mirrors-7344.test.ts. That census then read this file as a third reader of a key whose reader set it pins at one file, and failed. Correctly, on its own terms.Two repairs were available and they are not equal: adding this file to that census's prose allow-list would have blunted a working guard here permanently, and touched a file this claim does not name. The separator moved to
::instead, so the diff is still one test file plus one changeset and the other census keeps its edge. The reason is recorded beside the constant — including the instruction not to spell the colliding key literally in that docblock, because the first version of the explanation reproduced the very match it described.Gates (exit code captured to disk before any read)
pnpm --filter @object-ui/types type-checkafcd389pnpm exec vitest run packages/types/afcd389node scripts/check-control-bytes.mjsafcd389node scripts/check-changeset-presence.mjsafcd389node scripts/check-lint-coverage.mjscheck-governed-queue-guard.mjs --teston both pathsafcd389Lint, narrowed — and the narrowing is measured, not assumed.
eslint --no-inline-config --format jsonon the one changed file: 1 file, 0 errors, 0 warnings. ① Population read fromeslint.config.jsitself (files: ['**/*.{ts,tsx}']), not guessed; the changeset.mdis outside it. ② The file count is the length of the--format jsonoutput. ③ Invariance:project:/projectServiceappear zero times ineslint.config.js⇒ type-aware linting is not enabled, and no rule ineslint-rules/reads another file ⇒ this diff cannot move the verdict on any untouched file. Repo-widepnpm lintis CI's run.Changeset: empty frontmatter — declared as releasing nothing, which the gate names as the explicit exemption for a diff confined to
src/__tests__/. ⛔ Noskip-changesetlabel: in this repo that label is read by nothing.🤖 Generated with Claude Code
https://claude.ai/code/session_01QtGhnU3WnnWyiWeYQhw2aX
Generated by Claude Code