Filed unassigned by the dev seat executing objectui#7069 (PR #7758), which added the fifth parity ledger WiderThanDeclared and SEEDED it at the debt this direction was already carrying. Seeding is what lets that PR be green on its own head; it is a floor, not a disposition. This card is the disposition lane, the shape objectui#6152 is for UnmirroredDeclared and objectui#6033 / objectui#5927 are for the NARROWER direction.
Recording and grouping only; ⛔ not proposing per-key remedies.
What was measured
packages/types/src/__tests__/zod-mirror-parity.test.ts, on origin/main e546222b merged at 8e037c81. Of the 157 registered pairs, the new operator reports 36 pairs / 54 keys. Those split into two classes that do NOT share a remedy, and only one of them is a defect:
- SCHEMA-NODE — 27 keys / 21 pairs. An
unknown survives into the mirror's input face from the recursion-breaking annotation on the schema-node mirrors. These record the ANNOTATION, not an accept-set gap: at runtime the lazy union does validate. ⛔ Not this card, and ⛔ not repairable per key. The instrument limitation behind them is its own card.
- CONCRETE — 27 keys / 18 pairs. Both faces concrete, so the reading means what it says: an author can write the spelling,
safeParse returns green, and tsc refuses it. That is this card.
The 27, grouped by why they diverge
A. INLINE-LOCALE widening — the mirror takes a locale map the declaration restates as a plain string
BaseSchema's mirror spells the label keys as a plain string OR an inline locale map; these declarations restate the key as a plain string, so the narrowing is on the DECLARED side and the forward comparison reads the pair as clean.
| pair |
keys |
app.zod.ts#AppComponentSchema |
label |
objectql.zod.ts#ObjectGridSchema |
label, description |
layout.zod.ts#PageNodeSchema |
aria (the nested aria label) |
complex.zod.ts#DashboardComponentSchema |
header, globalFilters (both nested one level down) |
B. SINGLE-OR-LIST where the declaration states the list alone — the objectui#6881 toolbar shape, alive
| pair |
keys |
shape |
form.zod.ts#SliderSchema |
defaultValue, value |
mirror z.union([z.number(), z.array(z.number())]), declaration number[] |
⭐ This is the class objectui#7069 was filed to keep alive after PR #7066 retired its instance, and it turned out to have a live one on a pair nobody had looked at. A single number parses green and tsc refuses it.
C. An extra arm the declaration does not admit
| pair |
key |
shape |
form.zod.ts#FormSchema |
layout |
mirror z.enum(['vertical', 'horizontal', 'grid']), declaration states the first two |
layout.zod.ts#ContainerSchema |
maxWidth |
mirror's arm is z.boolean(), declaration admits the FALSE literal alone, so true parses green |
D. DISJOINT vocabularies — already in KnownDrift, now measured from the other side too
Each face refuses something the other admits, so the key is legitimately recorded in both ledgers. 12 keys across 8 pairs; the CONCRETE ones are:
| pair |
keys |
form.zod.ts#FormSchema |
fields, mode |
form.zod.ts#CalendarSchema |
defaultValue, value |
navigation.zod.ts#HeaderBarSchema |
variant |
complex.zod.ts#FilterFieldSchema |
operators |
complex.zod.ts#FilterBuilderSchema |
fields |
complex.zod.ts#ChatbotSchema |
body |
complex.zod.ts#DashboardComponentSchema |
header, globalFilters |
⚠️ FilterFieldSchema.operators and FilterBuilderSchema.fields overlap objectui#7561, which measured the same operator-vocabulary divergence from the RENDERER side. Listed to prevent re-conflation, not re-filed.
E. FUNCTION-SLOT — 8 keys
| pair |
keys |
data-display.zod.ts#DataTableSchema |
renderCellEditor |
data-display.zod.ts#TableColumnSchema |
cell |
form.zod.ts#FieldConditionSchema |
custom |
form.zod.ts#FieldConstraintsSchema |
validate |
form.zod.ts#FormFieldSchema |
condition (nested) |
zod 4 gives a function mirror an opaque input brand that no concrete signature equals, so the mirror accepts ANY callable where the declaration states one signature. ⚠️ These are mirrored runtime slots, so objectui#6152's RuntimeOnlyDeclared ruling does not reach them — that ledger is for keys the mirror never declares. Whether a runtime slot should carry a z.function() mirror at all is the question, and it may be one ruling for all of them rather than five. objectui#7351 records a related z.function() survivor of objectui#6124's sweep.
F. Structural — an inline element shape against a named declaration
| pair |
keys |
data-display.zod.ts#DataTableSchema |
columns |
form.zod.ts#FormFieldSchema |
validation |
views.zod.ts#DetailViewFieldSchema |
options |
complex.zod.ts#DashboardComponentSchema |
dateRange — mirror takes a bare string where the declaration states a closed literal set |
Why the default remedy is NARROW THE MIRROR, and why that is still a ruling
The mirror is the AUTHORING boundary — it validates AI-written metadata — so a wider key hands an author a green parse on a spelling the published types refuse, which is the contract-first direction to close at the producer. But each key needs the renderer read measured before the direction is chosen: group A may be a declaration that forgot the base's locale map rather than a mirror that over-accepts, and group D's disjoint pairs have a dead side to identify first. ⛔ Not decidable in bulk.
Dedup
One targeted semantic search over the parity / mirror / accept-set vocabulary, INCLUDING closed issues, returned 35 substantive results — a live instrument, not a silent zero. Reviewed: objectui#5927 / objectui#6033 are the NARROWER direction's per-key lane, objectui#6152 the unmirrored one, objectui#7069 this direction's class card, objectui#7561 / objectui#7465 / objectui#7735 per-key instances, objectui#6940 and objectui#5853 closed instance cards of this very direction. No card claims the wider direction's per-key dispositions. Channel note, declared: repo-scoped REST is refused for this seat (the session permission layer returns 403), so the dedup ran on the semantic-search channel.
One census card rather than 18 per-pair cards, stated as the dev seat's call: the groups above share remedies within themselves, and 18 cards would fragment a ruling that is really five or six.
Related
Filed unassigned by the dev seat executing objectui#7069 (PR #7758), which added the fifth parity ledger
WiderThanDeclaredand SEEDED it at the debt this direction was already carrying. Seeding is what lets that PR be green on its own head; it is a floor, not a disposition. This card is the disposition lane, the shape objectui#6152 is forUnmirroredDeclaredand objectui#6033 / objectui#5927 are for the NARROWER direction.Recording and grouping only; ⛔ not proposing per-key remedies.
What was measured
packages/types/src/__tests__/zod-mirror-parity.test.ts, onorigin/maine546222bmerged at8e037c81. Of the 157 registered pairs, the new operator reports 36 pairs / 54 keys. Those split into two classes that do NOT share a remedy, and only one of them is a defect:unknownsurvives into the mirror's input face from the recursion-breaking annotation on the schema-node mirrors. These record the ANNOTATION, not an accept-set gap: at runtime the lazy union does validate. ⛔ Not this card, and ⛔ not repairable per key. The instrument limitation behind them is its own card.safeParsereturns green, andtscrefuses it. That is this card.The 27, grouped by why they diverge
A. INLINE-LOCALE widening — the mirror takes a locale map the declaration restates as a plain string
BaseSchema's mirror spells the label keys as a plain string OR an inline locale map; these declarations restate the key as a plain string, so the narrowing is on the DECLARED side and the forward comparison reads the pair as clean.app.zod.ts#AppComponentSchemalabelobjectql.zod.ts#ObjectGridSchemalabel,descriptionlayout.zod.ts#PageNodeSchemaaria(the nested aria label)complex.zod.ts#DashboardComponentSchemaheader,globalFilters(both nested one level down)B. SINGLE-OR-LIST where the declaration states the list alone — the objectui#6881
toolbarshape, aliveform.zod.ts#SliderSchemadefaultValue,valuez.union([z.number(), z.array(z.number())]), declarationnumber[]⭐ This is the class objectui#7069 was filed to keep alive after PR #7066 retired its instance, and it turned out to have a live one on a pair nobody had looked at. A single number parses green and
tscrefuses it.C. An extra arm the declaration does not admit
form.zod.ts#FormSchemalayoutz.enum(['vertical', 'horizontal', 'grid']), declaration states the first twolayout.zod.ts#ContainerSchemamaxWidthz.boolean(), declaration admits the FALSE literal alone, sotrueparses greenD. DISJOINT vocabularies — already in
KnownDrift, now measured from the other side tooEach face refuses something the other admits, so the key is legitimately recorded in both ledgers. 12 keys across 8 pairs; the CONCRETE ones are:
form.zod.ts#FormSchemafields,modeform.zod.ts#CalendarSchemadefaultValue,valuenavigation.zod.ts#HeaderBarSchemavariantcomplex.zod.ts#FilterFieldSchemaoperatorscomplex.zod.ts#FilterBuilderSchemafieldscomplex.zod.ts#ChatbotSchemabodycomplex.zod.ts#DashboardComponentSchemaheader,globalFiltersFilterFieldSchema.operatorsandFilterBuilderSchema.fieldsoverlap objectui#7561, which measured the same operator-vocabulary divergence from the RENDERER side. Listed to prevent re-conflation, not re-filed.E. FUNCTION-SLOT — 8 keys
data-display.zod.ts#DataTableSchemarenderCellEditordata-display.zod.ts#TableColumnSchemacellform.zod.ts#FieldConditionSchemacustomform.zod.ts#FieldConstraintsSchemavalidateform.zod.ts#FormFieldSchemacondition(nested)zod 4 gives a function mirror an opaque input brand that no concrete signature equals, so the mirror accepts ANY callable where the declaration states one signature.⚠️ These are mirrored runtime slots, so objectui#6152's
RuntimeOnlyDeclaredruling does not reach them — that ledger is for keys the mirror never declares. Whether a runtime slot should carry az.function()mirror at all is the question, and it may be one ruling for all of them rather than five. objectui#7351 records a relatedz.function()survivor of objectui#6124's sweep.F. Structural — an inline element shape against a named declaration
data-display.zod.ts#DataTableSchemacolumnsform.zod.ts#FormFieldSchemavalidationviews.zod.ts#DetailViewFieldSchemaoptionscomplex.zod.ts#DashboardComponentSchemadateRange— mirror takes a bare string where the declaration states a closed literal setWhy the default remedy is NARROW THE MIRROR, and why that is still a ruling
The mirror is the AUTHORING boundary — it validates AI-written metadata — so a wider key hands an author a green parse on a spelling the published types refuse, which is the contract-first direction to close at the producer. But each key needs the renderer read measured before the direction is chosen: group A may be a declaration that forgot the base's locale map rather than a mirror that over-accepts, and group D's disjoint pairs have a dead side to identify first. ⛔ Not decidable in bulk.
Dedup
One targeted semantic search over the parity / mirror / accept-set vocabulary, INCLUDING closed issues, returned 35 substantive results — a live instrument, not a silent zero. Reviewed: objectui#5927 / objectui#6033 are the NARROWER direction's per-key lane, objectui#6152 the unmirrored one, objectui#7069 this direction's class card, objectui#7561 / objectui#7465 / objectui#7735 per-key instances, objectui#6940 and objectui#5853 closed instance cards of this very direction. No card claims the wider direction's per-key dispositions. Channel note, declared: repo-scoped REST is refused for this seat (the session permission layer returns 403), so the dedup ran on the semantic-search channel.
One census card rather than 18 per-pair cards, stated as the dev seat's call: the groups above share remedies within themselves, and 18 cards would fragment a ruling that is really five or six.
Related