Found while measuring #5853 (TableColumn.type's three-way divergence). Filed unassigned, deliberately NOT absorbed into #5853, whose fence is data-display.ts + its zod mirror + data-table.tsx. This card is in plugin-grid and is the structural reason that class of drift stays invisible.
Measured (at 8d3a5294a)
packages/types/src/data-display.ts:487 types the boundary strictly:
But the producer that fills it is untyped — packages/plugin-grid/src/ObjectGrid.tsx:1495:
constgenerateColumns=useCallback(()=>{No return-type annotation, and its call site at :2197 re-widens explicitly:
constcolumns=generateColumns().map((col: any)=>{So every column object ObjectGrid hands to data-table reaches a TableColumn[] slot as any. tsc checks nothing there.
Why it matters
The untyped boundary is not cosmetic — it is what lets producer/consumer vocabularies drift with a green build. Two independently-filed cards are the same hole seen from two sides:
Typing the boundary turns both classes into build errors at the point they are introduced, instead of findings discovered months later by hand.
Suggested direction (not a decision — needs sizing)
Annotate generateColumns(): TableColumn[] and drop the (col: any) at the call site. Expect this to go red immediately and usefully: the type widening decision in #5853 is a prerequisite for the type key specifically, and the extra keys ObjectGrid attaches (headerIcon, options, pinned, wrap, essential) each need a verdict — declare on TableColumn, or stop forwarding. That triage is the substance of the card, so it should be sized before dispatch rather than treated as a one-line annotation.
Related
Generated by Claude Code
Found while measuring #5853 (
TableColumn.type's three-way divergence). Filed unassigned, deliberately NOT absorbed into #5853, whose fence isdata-display.ts+ its zod mirror +data-table.tsx. This card is inplugin-gridand is the structural reason that class of drift stays invisible.Measured (at
8d3a5294a)packages/types/src/data-display.ts:487types the boundary strictly:But the producer that fills it is untyped —
packages/plugin-grid/src/ObjectGrid.tsx:1495:No return-type annotation, and its call site at
:2197re-widens explicitly:So every column object ObjectGrid hands to
data-tablereaches aTableColumn[]slot asany.tscchecks nothing there.Why it matters
The untyped boundary is not cosmetic — it is what lets producer/consumer vocabularies drift with a green build. Two independently-filed cards are the same hole seen from two sides:
TableColumn.typedisagrees three ways — interface declares 8 literals, zod mirror accepts any string, renderer's live read set handles values outside the union via anas anycast #5853 —ObjectGrid.tsx:2206writesnext.type = fieldDef.type, forwarding the@objectstack/specFieldTypevalue verbatim (49 options).TableColumn.typedeclares 8 literals. 42 of those spec spellings are outside the declared union andtschas never said a word — the mismatch only surfaced as anas anycast down indata-table.tsx:2151.wrapinto the DataTable column object, but nothing indata-table.tsxever reads it #5453 — ObjectGrid forwards a per-columnwrapthat nothing indata-table.tsxreads. An undeclared key surviving into a strict-typed slot is the same failure with the arrow reversed.Typing the boundary turns both classes into build errors at the point they are introduced, instead of findings discovered months later by hand.
Suggested direction (not a decision — needs sizing)
Annotate
generateColumns(): TableColumn[]and drop the(col: any)at the call site. Expect this to go red immediately and usefully: thetypewidening decision in #5853 is a prerequisite for thetypekey specifically, and the extra keys ObjectGrid attaches (headerIcon,options,pinned,wrap,essential) each need a verdict — declare onTableColumn, or stop forwarding. That triage is the substance of the card, so it should be sized before dispatch rather than treated as a one-line annotation.Related
TableColumn.typedisagrees three ways — interface declares 8 literals, zod mirror accepts any string, renderer's live read set handles values outside the union via anas anycast #5853 — thetypevalue-vocabulary divergence this hole hid (blocked on a maintainer ruling on the canonical set)wrapinto the DataTable column object, but nothing indata-table.tsxever reads it #5453 — the unreadwrapkey, same untyped boundaryObjectGridSchema.columns上容忍未声明的accessorKey/header拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068 / finding(react): bridgeListView emitsobject-gridcolumns in the undeclaredaccessorKey/headerspelling — the one in-repo producer that depends on ObjectGrid's tolerance branch #5340 — theListColumninput side of ObjectGrid's column tolerance (this card is the output side)Generated by Claude Code