Found while implementing #6004 (typing ObjectGrid.generateColumns()'s emit). Filed unassigned. #6004's fence is what this producer writes; this is the same producer's READ of its authored input, and it is the exact mirror of #6425 — which recorded this shape for ObjectDataTable, the other column producer. #6004 named only the write side.
Measured (at 129c7a9e7)
packages/plugin-grid/src/ObjectGrid.tsx, inside generateColumns()'s ListColumn branch, reads five keys off the authored column through a cast:
| line | read | declared by ListColumn? |
|---|
:1815 | (col as any).format | no |
:1840, :1841 | (col as any).options | no |
:1846 | (col as any).appearance | no |
:1925 | (col as any).prefix | yes — the cast is unnecessary |
:1951 | (col as any).essential | no |
ListColumn (@objectstack/spec@17.2.0, re-exported by packages/types/src/objectql.ts:74) declares exactly: field, label, width, align, hidden, sortable, resizable, wrap, type, pinned, summary, prefix, link, action.
So four of the five are honoured at runtime and refused by the schema — ListColumnSchema is a strict object, so an author who wrote essential: true or appearance: … on a list column would get unrecognized_keys at publish while the renderer happily reads them. That is the declared != enforced split AGENTS.md #0.1 exists to stop, and the as any is the tell — the same tell #5853 removed for type.
The fifth (prefix) is the opposite bug and free to fix: it is declared, so the cast is pure noise hiding the other four among lookalikes.
Not dormant
These are live limbs, so this is a different adjudication from #6004's — retiring an inert write costs nothing, while removing a read is a behaviour change:
format promotes a text column to a richer renderer via resolveCellRendererType (e.g. format: 'phone' → PhoneCellRenderer).options overrides the object schema's select options (:1840-1842).appearance drives badge styling (:1846-1849).essential decides the mobile hidden sm:table-cell class (:1951).
Census correction to #6004, recorded here
#6004's suggested key list named essential among the keys "ObjectGrid attaches". It does not: essential is read off the input and turned into a className, and it is never emitted. It is also not a ListColumn member. It belongs on this card, not that one.
Suggested disposition (not a decision)
Per key: declare it on ListColumn in @objectstack/spec (if the capability is wanted at the authoring surface), or stop reading it (if the object-schema-level spelling is the intended one). Contract-first says the answer cannot be a renderer-side tolerance either way. Drop the prefix cast regardless.
Related
Generated by Claude Code
Generated by Claude Code
Found while implementing #6004 (typing
ObjectGrid.generateColumns()'s emit). Filed unassigned. #6004's fence is what this producer writes; this is the same producer's READ of its authored input, and it is the exact mirror of #6425 — which recorded this shape forObjectDataTable, the other column producer. #6004 named only the write side.Measured (at
129c7a9e7)packages/plugin-grid/src/ObjectGrid.tsx, insidegenerateColumns()'sListColumnbranch, reads five keys off the authored column through a cast:ListColumn?:1815(col as any).format:1840,:1841(col as any).options:1846(col as any).appearance:1925(col as any).prefix:1951(col as any).essentialListColumn(@objectstack/spec@17.2.0, re-exported bypackages/types/src/objectql.ts:74) declares exactly:field,label,width,align,hidden,sortable,resizable,wrap,type,pinned,summary,prefix,link,action.So four of the five are honoured at runtime and refused by the schema —
ListColumnSchemais a strict object, so an author who wroteessential: trueorappearance: …on a list column would getunrecognized_keysat publish while the renderer happily reads them. That is thedeclared != enforcedsplit AGENTS.md #0.1 exists to stop, and theas anyis the tell — the same tell #5853 removed fortype.The fifth (
prefix) is the opposite bug and free to fix: it is declared, so the cast is pure noise hiding the other four among lookalikes.Not dormant
These are live limbs, so this is a different adjudication from #6004's — retiring an inert write costs nothing, while removing a read is a behaviour change:
formatpromotes atextcolumn to a richer renderer viaresolveCellRendererType(e.g.format: 'phone'→PhoneCellRenderer).optionsoverrides the object schema's select options (:1840-1842).appearancedrives badge styling (:1846-1849).essentialdecides the mobilehidden sm:table-cellclass (:1951).Census correction to #6004, recorded here
#6004's suggested key list named
essentialamong the keys "ObjectGrid attaches". It does not:essentialis read off the input and turned into aclassName, and it is never emitted. It is also not aListColumnmember. It belongs on this card, not that one.Suggested disposition (not a decision)
Per key: declare it on
ListColumnin@objectstack/spec(if the capability is wanted at the authoring surface), or stop reading it (if the object-schema-level spelling is the intended one). Contract-first says the answer cannot be a renderer-side tolerance either way. Drop theprefixcast regardless.Related
generateColumns()is untyped (any[]), so nothing type-checks what it writes intoDataTableSchema.columns: TableColumn[]— the hole that hid #5853 and #5453 #6004 — the WRITE side of this same seam (parent card)ObjectDataTable, the other producerTableColumn.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 — thetypekey, where this exact cast-shaped tell was removedObjectGridSchema.columns上容忍未声明的accessorKey/header拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068 /ObjectGridrenders a header-only grid in total silence when no column resolves — one wrong first column used to take the whole set down, now every wrong column does #5349 — ObjectGrid's column-spelling input tolerance, the same boundaryGenerated by Claude Code
Generated by Claude Code