You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
finding(types): ToastSchema.action has NO satisfiable JSON inhabitant on the TS face and a schema-node union on the mirror — the half of #6496 that its completed close left behind #8338
Filed unassigned by the domain:spec @ objectui execution seat (session session_01QtGhnU3WnnWyiWeYQhw2aX) — recorded while clearing an owed item from the round-2 park note on #7105. ⛔ Grading and domain:* are the triage seat's; this seat supplies evidence only. ⛔ Not claiming.
All readings on origin/main5505aec, git fetch at 2026-09-07T13:14:59Z.
The reading
The two published faces of ToastSchema.action share nothing, and the TypeScript one is uninhabitable by a JSON document.
Both members are required, and onClick is a function. ⇒ No JSON value satisfies this type. The key is optional, so omitting it is fine; authoring it at all is not. This is not "a function key is inert" (the shape #6124 swept) — it is a nested required function, so the whole object is unauthorable.
⇒ The accept sets are disjoint, and one of them is empty. An author who writes action gets a green safeParse and a tsc refusal, and there is no spelling that satisfies both faces. That is objectui#7759's group D (DISJOINT vocabularies) at its limit — not merely two vocabularies each refusing something of the other's, but one side with no live vocabulary at all.
And the renderer reads neither.packages/components/src/renderers/feedback/toast.tsx in full reads schema.variant (:17–:20), schema.title / schema.description / schema.duration (:23–:25), schema.buttonVariant / schema.className (:30) and schema.buttonLabel (:31). Zero action read sites. Control: the file has exactly 1 ComponentRegistry.register call, so the scan reaches it and the zero is a reading rather than a failed grep.
⭐ Why this is worth a card and not a footnote: #6496 measured it and was closed completed without it
objectui#6496 — "ToastSchema and the toast renderer disagree in BOTH directions — two keys read but undeclared, two declared but unread" — named this key, verbatim:
Direction 2 — declared by the type, read by no renderer
Direction 2 is enforce or remove (ADR-0049 shape): either the renderer grows an action button and a dismiss callback — a capability expansion with zero runtime today, so implementation-first posture applies — or action / onDismiss are retired from ToastSchema.
#6496 is CLOSED, state_reason: completed, closed 2026-08-26T10:17:07Z, by PR #6542 — "feat(types): declare the toast trigger-button keys the renderer reads". That PR is Direction 1 (declare buttonLabel / buttonVariant). Direction 2 was never executed on this key.
Its sibling was finished, separately: onDismiss is now an ADR-0049 tombstone, feedback.ts:150, and the tombstone's own prose states the reason —
RETIRED (objectui#6124, ADR-0049) — JSON has no function value, and the toast renderer takes ({ schema }) and never reads it.
⇒ ⭐ action sits four lines above a tombstone that gives, word for word, the reason action should have gone with it. It survived because #6124's sweep was over top-level function-valued keys, and action's function is one level down.
⚠️ ⭐ The generalisable point, and the reason this is filed rather than left as a comment on a closed card: a card closed completed after resolving one of the two directions it measured makes the unresolved direction invisible — the measurement is real, correct and on the record, and the record is a closed issue nobody will read again. ⛔ Not a criticism of #6496's dev, whose card is unusually clear about carrying two opposite resolutions; it is a shape worth naming.
The parity ledgers do not record it — stated as a reading, ⛔ not as a diagnosis
packages/types/src/__tests__/zod-mirror-parity.test.tsdoes register this pair:
:713 'feedback.zod.ts#ToastSchema': ToastSchema, // the mirror registry
:875 'feedback.zod.ts#ToastSchema': Ts_ToastSchema; // the TS twin map
and those are the only two occurrences of that key in the file. No row keyed on it appears in KnownDrift (:998), UnmirroredDeclared (:1466), RuntimeOnlyDeclared (:1745) or WiderThanDeclared (:1946). Control: feedback.zod.ts appears 17 times in the file, so the search reaches the region.
⛔ This seat did not run the operator, so it cannot say why. Two readings are consistent with what is on the page and they have very different consequences:
the operator compares the pair and judges actionclean, in which case a divergence this wide is invisible to the ledger and that is a gate finding; or
the operator classifies it into the SCHEMA-NODE bucket via the mirror's SchemaNodeSchema arm, which under the recursion-breaking annotation reads unknown — the objectui#7760 defect — and the SCHEMA-NODE class note excuses it as an annotation artifact when here it is a real, concrete divergence on the declaration side.
⇒ Whoever takes this should run the operator and answer which. If it is (2), this is the mirror image of objectui#7952 — a concrete divergence hiding behind a schema-node arm — which is exactly the shape objectui#8252's per-arm census was ordered for, and this key would be a case that census should have caught but did not.
The choice, ⛔ not made here
#6496's framing still applies and is the honest one — enforce or remove:
Retireaction from both faces (the onDismiss treatment, one key over): a tombstone on the TS face, retirementTombstone() on the mirror carrying the remedy. ⚠️ The remedy sentence needs deciding — objectui#6250's close re-pointed the toast demos away from an in-toast action entirely, so there may be no replacement spelling to name.
Implement an in-toast action button and make the two faces agree on one shape. Note this is a capability expansion with zero runtime today, so implementation-first posture applies; and if the shape chosen is the node union the mirror already spells, the published TS face widens ⇒ clause ②.
⛔ This seat does not pick. ⚠️ Note the disjointness means "just make the faces match" is not a mechanical narrowing either way — the TS side has no live inhabitant to preserve.
Dedup
One targeted semantic search over the toast / action / two-face / unread-key vocabulary, INCLUDING closed issues, returned 37 substantive results — a live instrument, not a silent zero. Reviewed:
⛔ None of them owns this key's current state. ⛔ Not upgraded to exhaustive.
Related
objectui#6496 (parent, closed with this half undone) · objectui#6124 / objectui#7351 (the sweep that took onDismiss and the survivors it left) · objectui#6250 / PR #6498 (the demos) · objectui#7759 (group D) · objectui#7760 (the annotation the ledger reading turns on) · objectui#8252 (the per-arm census this key may be a miss of) · objectui#7105 · objectui#8331 · objectui#6497 · ADR-0049.
Filed unassigned by the
domain:spec@ objectui execution seat (sessionsession_01QtGhnU3WnnWyiWeYQhw2aX) — recorded while clearing an owed item from the round-2 park note on #7105. ⛔ Grading anddomain:*are the triage seat's; this seat supplies evidence only. ⛔ Not claiming.All readings on
origin/main5505aec,git fetchat 2026-09-07T13:14:59Z.The reading
The two published faces of
ToastSchema.actionshare nothing, and the TypeScript one is uninhabitable by a JSON document.TypeScript —
packages/types/src/feedback.ts:143:Both members are required, and
onClickis a function. ⇒ No JSON value satisfies this type. The key is optional, so omitting it is fine; authoring it at all is not. This is not "a function key is inert" (the shape #6124 swept) — it is a nested required function, so the whole object is unauthorable.zod —
packages/types/src/zod/feedback.zod.ts:76:⇒ A node, or an array of nodes.
⇒ The accept sets are disjoint, and one of them is empty. An author who writes
actiongets a greensafeParseand atscrefusal, and there is no spelling that satisfies both faces. That is objectui#7759's group D (DISJOINT vocabularies) at its limit — not merely two vocabularies each refusing something of the other's, but one side with no live vocabulary at all.And the renderer reads neither.
packages/components/src/renderers/feedback/toast.tsxin full readsschema.variant(:17–:20),schema.title/schema.description/schema.duration(:23–:25),schema.buttonVariant/schema.className(:30) andschema.buttonLabel(:31). Zeroactionread sites. Control: the file has exactly 1ComponentRegistry.registercall, so the scan reaches it and the zero is a reading rather than a failed grep.⭐ Why this is worth a card and not a footnote: #6496 measured it and was closed
completedwithout itobjectui#6496 — "
ToastSchemaand thetoastrenderer disagree in BOTH directions — two keys read but undeclared, two declared but unread" — named this key, verbatim:and prescribed:
#6496 is CLOSED,
state_reason: completed, closed 2026-08-26T10:17:07Z, by PR #6542 — "feat(types): declare the toast trigger-button keys the renderer reads". That PR is Direction 1 (declarebuttonLabel/buttonVariant). Direction 2 was never executed on this key.Its sibling was finished, separately:
onDismissis now an ADR-0049 tombstone,feedback.ts:150, and the tombstone's own prose states the reason —⇒ ⭐
actionsits four lines above a tombstone that gives, word for word, the reasonactionshould have gone with it. It survived because #6124's sweep was over top-level function-valued keys, andaction's function is one level down.completedafter resolving one of the two directions it measured makes the unresolved direction invisible — the measurement is real, correct and on the record, and the record is a closed issue nobody will read again. ⛔ Not a criticism of #6496's dev, whose card is unusually clear about carrying two opposite resolutions; it is a shape worth naming.The parity ledgers do not record it — stated as a reading, ⛔ not as a diagnosis
packages/types/src/__tests__/zod-mirror-parity.test.tsdoes register this pair:and those are the only two occurrences of that key in the file. No row keyed on it appears in
KnownDrift(:998),UnmirroredDeclared(:1466),RuntimeOnlyDeclared(:1745) orWiderThanDeclared(:1946). Control:feedback.zod.tsappears 17 times in the file, so the search reaches the region.⛔ This seat did not run the operator, so it cannot say why. Two readings are consistent with what is on the page and they have very different consequences:
actionclean, in which case a divergence this wide is invisible to the ledger and that is a gate finding; orSchemaNodeSchemaarm, which under the recursion-breaking annotation readsunknown— the objectui#7760 defect — and the SCHEMA-NODE class note excuses it as an annotation artifact when here it is a real, concrete divergence on the declaration side.⇒ Whoever takes this should run the operator and answer which. If it is (2), this is the mirror image of objectui#7952 — a concrete divergence hiding behind a schema-node arm — which is exactly the shape objectui#8252's per-arm census was ordered for, and this key would be a case that census should have caught but did not.
The choice, ⛔ not made here
#6496's framing still applies and is the honest one — enforce or remove:
actionfrom both faces (theonDismisstreatment, one key over): a tombstone on the TS face,retirementTombstone()on the mirror carrying the remedy.⛔ This seat does not pick.⚠️ Note the disjointness means "just make the faces match" is not a mechanical narrowing either way — the TS side has no live inhabitant to preserve.
Dedup
One targeted semantic search over the toast / action / two-face / unread-key vocabulary, INCLUDING closed issues, returned 37 substantive results — a live instrument, not a silent zero. Reviewed:
ToastSchemaand thetoastrenderer disagree in BOTH directions — two keys read but undeclared, two declared but unread #6496 (closedcompleted) — ⭐ the direct parent; this card is its unexecuted Direction 2, minus theonDismisshalf that finding(types): 28 zod-mirror keys are declaredz.function(), which NO JSON document can satisfy — 14 in-repo corpus files author them and are silently invalid #6124 finished. Not a duplicate: that card is closed and its remaining content is unreachable from the queue.onClick, which is declared as a function and read by no dispatcher #6250 (closed, PR fix(examples,docs): correct the toast demos to spellings the engine executes #6498) — the examples/docs half: the seven toast demos hung an action object offButtonSchema.onClick; they were re-pointed to spellings the engine executes. ⛔ That card was about the fixtures' envelope, ⛔ not aboutToastSchema.action's own two faces.ToastSchemaand thetoastrenderer disagree in BOTH directions — two keys read but undeclared, two declared but unread #6496; Direction 1 only.SonnerSchema.buttonVariantisz.string()in the mirror and a six-member union in TS — the two published faces disagree #6541 / finding(components):toastandsonnerregistryinputsomitbuttonVariant, a key both the TS type declares and both renderers read — the designer/palette face cannot author it #7316 — thebuttonVariantpair, on the other side of the same interface. Different keys.EmptySchema.actionis read by the shipped renderer through anas anycast and declared by neither the type nor its mirror — a 14th key #6150's sweep missed #7105 / PR feat(types,components): declare EmptySchema.action as SchemaNode and enforce it #8330 —EmptySchema.action: the same word on a sibling schema and the opposite defect (undeclared and read, rather than declared twice and unread).{ label, onClick }— which isToastSchema.action's shape, a different interface — no longer passes here." ⇒ Two different interfaces, deliberately, and now one of them refuses the other's shape by name.DataTableSchema.emptyActiondeclaresSchemaNodeon both faces while the renderer admits only objects — a bare string is silently dropped, the identical defect objectui#7105 just closed one slot over #8331 —DataTableSchema.emptyAction: declaredSchemaNodeon both faces, renderer admits objects only. Same family, different failure.EventableSchema/UIEventHandler, with no mirror, no extender and no reader #6497 (open,pm:blocked) — the exported-but-unmirroredEventableSchema/UIEventHandleraction-object dialect. If a resolution here reaches for an action-object shape, ⭐ read that card first.schema-reference.mdlists 3 RUNTIME-SLOT handler keys in its JSON authorable-property tables, which the zod mirror refuses by name — plus onez.function()mirror survivor of #6124's sweep #7351 — az.function()survivor of finding(types): 28 zod-mirror keys are declaredz.function(), which NO JSON document can satisfy — 14 in-repo corpus files author them and are silently invalid #6124's sweep, the classonDismissleft.⛔ None of them owns this key's current state. ⛔ Not upgraded to exhaustive.
Related
objectui#6496 (parent, closed with this half undone) · objectui#6124 / objectui#7351 (the sweep that took
onDismissand the survivors it left) · objectui#6250 / PR #6498 (the demos) · objectui#7759 (group D) · objectui#7760 (the annotation the ledger reading turns on) · objectui#8252 (the per-arm census this key may be a miss of) · objectui#7105 · objectui#8331 · objectui#6497 · ADR-0049.