Found while implementing #7082, which corrects the type name on alert-dialog.mdx:30. Filed rather than folded in: #7082 is fenced to docs rows, and this is a declaration/renderer divergence.
Measured on origin/main2c3cd1b7572a8aca2958da3551c990164186c9c1.
The three surfaces
AlertDialogSchema (packages/types/src/overlay.ts:78-127, mirrored at packages/types/src/zod/overlay.zod.ts:42-55) declares, past type/title/description/trigger/defaultOpen/open:
| declared key | read by the renderer? |
|---|
cancelLabel?: string | no |
confirmLabel?: string | no |
confirmVariant?: 'default' | 'destructive' | no |
onConfirm?: () => void | Promise<void> | no |
onCancel?: () => void | no |
packages/components/src/renderers/overlay/alert-dialog.tsx reads, past the ones both agree on:
| key the renderer reads | declared? |
|---|
schema.content (rendered as the dialog body) | no |
schema.cancelText (drives AlertDialogCancel) | no |
schema.actionText (drives AlertDialogAction) | no |
schema.onAction (the action's onClick) | no |
And content/docs/components/overlay/alert-dialog.mdx:33 publishes a third spelling again:
| documented key | declared? | read? |
|---|
actions?: ComponentSchema[] | no — absent from both the TS interface and the mirror | no — schema.actions appears nowhere in the renderer |
So the confirm/cancel affordance has three names on three surfaces and no two of them agree.
Why it matters, in the direction that bites an author
The published TS type is what an author's editor reads. Today:
- authoring
cancelLabel / confirmLabel / onConfirm — the keys the type declares and the ones an editor completes — produces no cancel button, no confirm button and no handler. The renderer only draws AlertDialogCancel when schema.cancelText is truthy, and AlertDialogAction when schema.actionText is. So a document written strictly against the shipped type renders a dialog with an empty footer. - authoring the keys that actually work (
cancelText, actionText, onAction, content) is only accepted because BaseSchema carries [key: string]: any — no editor suggests them, and no page names them. - the renderer's own
defaultProps (same file) ships cancelText / actionText, so the component's registered default is written in the undeclared dialect.
This is the same shape as #6773 and #6788 (documents authoring a key the renderer never reads), with the extra wrinkle that here the declaration is on the losing side too.
Why nothing red covers it
Options
- (a) Make the renderer read the declared keys (
cancelLabel, confirmLabel, confirmVariant, onConfirm, onCancel) and retire the undeclared dialect, updating defaultProps and any fixture. Contract-first: the published type wins, and the docs row for actions is deleted as a phantom. - (b) Declare what the renderer reads (
content, cancelText, actionText, onAction) and retire the inert declared keys under ADR-0049 enforce-or-remove. - (c) Split: keep
content (a real body slot the sibling overlay types all declare) and resolve the button pair one way.
(a) looks right on contract-first grounds — the declared names are also the better ones, and confirmVariant is a capability the actionText dialect cannot express. But it changes shipped runtime behaviour for any document written in the working dialect, so it wants a triage decision rather than a drive-by. Either way alert-dialog.mdx is owed a rewrite of its whole Schema block, not just the two rows #7082 touched.
This is a concrete instance of the general class #4631 names.
Refs: #7082 · #4631 · #6150 · #6773 · #6788.
Found while implementing #7082, which corrects the type name on
alert-dialog.mdx:30. Filed rather than folded in: #7082 is fenced to docs rows, and this is a declaration/renderer divergence.Measured on
origin/main2c3cd1b7572a8aca2958da3551c990164186c9c1.The three surfaces
AlertDialogSchema(packages/types/src/overlay.ts:78-127, mirrored atpackages/types/src/zod/overlay.zod.ts:42-55) declares, pasttype/title/description/trigger/defaultOpen/open:cancelLabel?: stringconfirmLabel?: stringconfirmVariant?: 'default' | 'destructive'onConfirm?: () => void | Promise<void>onCancel?: () => voidpackages/components/src/renderers/overlay/alert-dialog.tsxreads, past the ones both agree on:schema.content(rendered as the dialog body)schema.cancelText(drivesAlertDialogCancel)schema.actionText(drivesAlertDialogAction)schema.onAction(the action'sonClick)And
content/docs/components/overlay/alert-dialog.mdx:33publishes a third spelling again:actions?: ComponentSchema[]schema.actionsappears nowhere in the rendererSo the confirm/cancel affordance has three names on three surfaces and no two of them agree.
Why it matters, in the direction that bites an author
The published TS type is what an author's editor reads. Today:
cancelLabel/confirmLabel/onConfirm— the keys the type declares and the ones an editor completes — produces no cancel button, no confirm button and no handler. The renderer only drawsAlertDialogCancelwhenschema.cancelTextis truthy, andAlertDialogActionwhenschema.actionTextis. So a document written strictly against the shipped type renders a dialog with an empty footer.cancelText,actionText,onAction,content) is only accepted becauseBaseSchemacarries[key: string]: any— no editor suggests them, and no page names them.defaultProps(same file) shipscancelText/actionText, so the component's registered default is written in the undeclared dialect.This is the same shape as #6773 and #6788 (documents authoring a key the renderer never reads), with the extra wrinkle that here the declaration is on the losing side too.
Why nothing red covers it
zod-mirror-parity.test.tscompares the TS declaration to its Zod mirror. These two agree — both carrycancelLabel/confirmLabel/onConfirm. The renderer is not a party to that test.check:doc-snippetscompilests/tsx/typescriptfences; theactionsrow is in aplaintextfence, so no gate parses it (finding: JSON doc snippets are checked by nothing — the ts/tsx gate cannot see them, andBaseSchema.passthrough()makesobjectui validateaccept arbitrary undeclared keys #5250 / finding(docs): TypeScript examples fenced as plaintext escape check-doc-snippet-types — 211 blocks in 122 files, and #5044 proved one of them taught a type error under a gate that reports the file as covered #5867).check:doc-typesreads only thetypestring literals out of docs code blocks.content/docs/componentspages #6150's sweep declared 13 renderer-read keys that no type carried, butalert-dialogis not among the components its ledger (packages/types/src/__tests__/undeclared-but-consumed-keys-6150.test.ts) pins.Options
cancelLabel,confirmLabel,confirmVariant,onConfirm,onCancel) and retire the undeclared dialect, updatingdefaultPropsand any fixture. Contract-first: the published type wins, and the docs row foractionsis deleted as a phantom.content,cancelText,actionText,onAction) and retire the inert declared keys under ADR-0049 enforce-or-remove.content(a real body slot the sibling overlay types all declare) and resolve the button pair one way.(a) looks right on contract-first grounds — the declared names are also the better ones, and
confirmVariantis a capability theactionTextdialect cannot express. But it changes shipped runtime behaviour for any document written in the working dialect, so it wants a triage decision rather than a drive-by. Either wayalert-dialog.mdxis owed a rewrite of its whole Schema block, not just the two rows #7082 touched.This is a concrete instance of the general class #4631 names.
Refs: #7082 · #4631 · #6150 · #6773 · #6788.