Found while implementing #5852 (out of scope there; recorded, not touched).
Measured on origin/main at 0c282d979, against built dist/
This package's ADR-0049 retirement convention writes a tombstone as
z.never().optional().describe('RETIRED (objectui#NNNN) — <why, and what to use instead>').
packages/types/src/zod/data-display.zod.ts carries nine of them on
StaticTableColumnSchema (minWidth, align, fixed, type, sortable,
filterable, resizable, editable, cell), and its doc block states the
intent:
The z.never().optional() members are ADR-0049 retirement tombstones (the
convention crud.zod.ts confirm set): an authored value is REFUSED at
parse time with the key named in the error path, instead of being silently
stripped the way an undeclared key would be. Loud refusal is the ruled
outcome — these keys were accepted-and-inert for as long as the static
table shared the rich column type.
The refusal half is real and works. The remediation text does not reach the
author at runtime. Measured:
StaticTableColumnSchema.safeParse({ header:'H', accessorKey:'a', align:'right' })
success: false
path: ["align"]
message: "Invalid input: expected never, received string"
The carefully written .describe() string — "RETIRED (objectui#5474) — never
read by the static table; use data-table, or a cellClassName like text-right" —
appears nowhere in the issue. .describe() is schema metadata (it surfaces
in generated JSON-Schema / docs), not an error message, so an author who trips
the tombstone is told only that the key expected never. That names which key
is wrong via the path, but says nothing about why it was retired or what to
use instead, which is the part the convention's doc block was written to
deliver.
Why this is worth recording
The whole point of choosing loud refusal over silent stripping is that the author
learns something. Half the payload currently gets dropped: an AI or human author
who writes align: 'right' on a static table column sees expected never, received string and has no path to cellClassName: 'text-right' without reading
the source.
Candidate remedy (not applied here)
zod 4 (this repo pins zod@4.4.3) accepts a custom error on z.never(), and it
does reach the issue. Verified in this repo's own node_modules:
z.never({ error: 'RETIRED (objectui#5852) — delete the key.' })
-> path: ["k"], message: "RETIRED (objectui#5852) — delete the key."
So the fix shape is to carry the text in both places —
z.never({ error: '…' }).optional().describe('…') — keeping .describe() for
generated docs while making the runtime refusal explanatory. #5852 lands one
instance of that spelling (DashboardConfigSchema.aria), which is what surfaced
the gap in the older ones.
Scope, honestly stated: this is a message-quality finding, not a
correctness one. Every one of these tombstones already refuses the right keys at
the right paths; no validation outcome is wrong. Sizing the sweep (nine keys in
data-display.zod.ts plus the crud.zod.ts confirm set that established the
convention, and any others) is triage's call, not measured here.
Generated by Claude Code
Found while implementing #5852 (out of scope there; recorded, not touched).
Measured on
origin/mainat0c282d979, against builtdist/This package's ADR-0049 retirement convention writes a tombstone as
z.never().optional().describe('RETIRED (objectui#NNNN) — <why, and what to use instead>').packages/types/src/zod/data-display.zod.tscarries nine of them onStaticTableColumnSchema(minWidth,align,fixed,type,sortable,filterable,resizable,editable,cell), and its doc block states theintent:
The refusal half is real and works. The remediation text does not reach the
author at runtime. Measured:
The carefully written
.describe()string — "RETIRED (objectui#5474) — neverread by the static table; use data-table, or a cellClassName like text-right" —
appears nowhere in the issue.
.describe()is schema metadata (it surfacesin generated JSON-Schema / docs), not an error message, so an author who trips
the tombstone is told only that the key expected
never. That names which keyis wrong via the path, but says nothing about why it was retired or what to
use instead, which is the part the convention's doc block was written to
deliver.
Why this is worth recording
The whole point of choosing loud refusal over silent stripping is that the author
learns something. Half the payload currently gets dropped: an AI or human author
who writes
align: 'right'on a static table column seesexpected never, received stringand has no path tocellClassName: 'text-right'without readingthe source.
Candidate remedy (not applied here)
zod 4 (this repo pins
zod@4.4.3) accepts a custom error onz.never(), and itdoes reach the issue. Verified in this repo's own
node_modules:So the fix shape is to carry the text in both places —
z.never({ error: '…' }).optional().describe('…')— keeping.describe()forgenerated docs while making the runtime refusal explanatory. #5852 lands one
instance of that spelling (
DashboardConfigSchema.aria), which is what surfacedthe gap in the older ones.
Scope, honestly stated: this is a message-quality finding, not a
correctness one. Every one of these tombstones already refuses the right keys at
the right paths; no validation outcome is wrong. Sizing the sweep (nine keys in
data-display.zod.tsplus thecrud.zod.tsconfirmset that established theconvention, and any others) is triage's call, not measured here.
Generated by Claude Code