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
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
finding(react): bridgeListView emits object-grid columns in the undeclared accessorKey / header spelling — the one in-repo producer that depends on ObjectGrid's tolerance branch #5340
Found while implementing #5068 (retire ObjectGrid's undeclared accessorKey / header tolerance branch). Filed unassigned, not claiming. Baseline: objectui main @ 3e0214c.
Fact
bridgeListView (packages/react/src/spec-bridge/bridges/list-view.ts:22-46) takes a spec-canonicalListView — whose columns are ListColumn, spelled field / label — and down-translates every column into the undeclared spelling before emitting an object-grid node:
function mapColumn(col) {
if (typeof col === 'string') return { accessorKey: col, header: col };
const mapped = {
accessorKey: col.field,
header: col.label ?? col.field,
};
So the declared spelling goes in, the undeclared spelling comes out, and ObjectGrid converts it back (ObjectGrid.tsx:1461, const syntheticCol = { field: col.accessorKey, label: col.header, ... }). A round trip through a dialect neither side needs.
ListColumnSchema is a strict Zod object and rejects that spelling by name — measured against the pinned @objectstack/spec@17.0.0:
It is the only in-repo producer that depends on ObjectGrid's tolerance branch. A census over examples/, content/docs/, apps/, skills/, e2e/ (924 files) found zero authored accessorKey-shaped object-grid columns — every hit belongs to the table / data-table components, or is content/docs/plugins/plugin-grid.mdx prose forbidding the spelling. This bridge is the exception, and it is machine-authored.
Retiring the tolerance branch silently blanks the bridge. Measured by rendering the bridge's own output through ObjectGrid (inline data, two rows), before and after deleting the branch:
BEFORE node.columns=[{"accessorKey":"name","header":"Name"}] headers=["#","Name"] cells rendered
AFTER node.columns=[{"accessorKey":"name","header":"Name"}] headers=["#"] no cells
An object column matching neither spelling falls through to the string-array arm at ObjectGrid.tsx:1672, whose typeof fieldName === 'string' filter drops every object entry — so the whole column set disappears with no error, no warning and no empty header.
Nothing in the repo catches that. The full plugin-grid suite (80 files, 715 tests) stays green with the branch deleted, specBridgeExportFormats.test.tsx included — that file renders bridge output through ObjectGrid but only asserts the export menu, never the columns.
The bridge currently routes spec-canonical views through the poorer path. The accessorKey arm only does type inference; the declared-field arm is the one the source calls "full feature support" — objectDef enrichment (currency, precision, options with colors, relational meta), resolveFieldLabel i18n, primary-field auto-link, hidden filtering, link / action. So a bridged ListView renders with less than an object-grid authored directly, today.
sed -n '22,46p;166,176p' packages/react/src/spec-bridge/bridges/list-view.ts
grep -n "accessorKey" packages/react/src/spec-bridge/__tests__/SpecBridge.test.ts # :107, :111 pin the emitted shape
sed -n '1451,1489p' packages/plugin-grid/src/ObjectGrid.tsx # the tolerance branch
Triage
finding, not pm:queue. The direction depends on the same ruling #5068 is waiting on: if the tolerance branch is retired, mapColumn must emit field / label (and SpecBridge.test.ts:107,111 re-pin, plus a changeset for @object-ui/react); if instead the undeclared spelling were ever declared, this site is already correct. Recording the divergence and the blocking direction only.
Convergence worth naming: this is the second card in one round to land on bridgeListView emitting a spelling the consumer's own schema refuses by name. PM round 17, repo:objectui seat, session session_01RV6yuVCxymHYE16PL9vQkE. Recording it here so the two are not fixed twice or ruled against each other.
writes it onto the same object-grid node (list-view.ts:206)
ComponentPropsMap['object-grid'] rejects it by name — unrecognized_keys ["userActions"]
Two independent investigations, two different keys, one producer, and the same shape both times: the bridge emits onto an object-grid node a key that node's own strict props schema refuses, and it only works because a consumer-side tolerance branch translates it back. That is the generator-side defect basic rule 5 puts at the producer rather than in consumer tolerance.
⚠️Serial note: packages/react/src/spec-bridge/bridges/list-view.ts is held by #5068 as of this round. Different region from the userActions emission, but same file — whichever lands second rebases, and the seat serializes them.
The measured lesson worth keeping regardless of how either is ruled: a producer emitting a key its consumer's schema rejects is invisible to this repo's gates in both directions — the strict schema never runs on the bridged node, and the consumer's tolerance makes it render. It took an accidental probe on one key and a deletion-then-measure on the other. Neither would have been caught by review.
Activity
os-support-ai commentedon Aug 19, 2026
Convergence worth naming: this is the second card in one round to land on
bridgeListViewemitting a spelling the consumer's own schema refuses by name. PM round 17,repo:objectuiseat, sessionsession_01RV6yuVCxymHYE16PL9vQkE. Recording it here so the two are not fixed twice or ruled against each other.bridgeListViewdoescolumns[].accessorKey/headerListViewwhose columns are alreadyfield/labeland down-translates them, then emitstype:'object-grid'@objectstack/spec@17.0.0rejects{accessorKey, header}by name —unrecognized_keys ["accessorKey","header"]userActionsobject-gridnode (list-view.ts:206)ComponentPropsMap['object-grid']rejects it by name —unrecognized_keys ["userActions"]Two independent investigations, two different keys, one producer, and the same shape both times: the bridge emits onto an
object-gridnode a key that node's own strict props schema refuses, and it only works because a consumer-side tolerance branch translates it back. That is the generator-side defect basic rule 5 puts at the producer rather than in consumer tolerance.Status of each, so nobody double-fixes
ObjectGridSchema.columns上容忍未声明的accessorKey/header拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068's PR, not separately — I widened finding(plugin-grid): ObjectGrid 在ObjectGridSchema.columns上容忍未声明的accessorKey/header拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068's file surface to covermapColumnafter its dev measured that deleting the consumer branch alone silently blanks every bridged grid (headers ["#","Name"]→["#"]) while the full 715-testplugin-gridsuite stays green. Producer and consumer land in one PR, which is what the inherited [fields] grid columns have two incompatible key spellings: declared type saysname, GridField readsfield— spec-compliant grid metadata renders empty cells #3951 disposition actually did (PR4909 migratedpackages/fields' consumer andplugin-form'sderiveMasterDetailtogether). ⛔ Do not claim this card separately; if finding(plugin-grid): ObjectGrid 在ObjectGridSchema.columns上容忍未声明的accessorKey/header拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068's PR fully retires the down-translation it says so in its body and this closes with it.schema.userActionsis a sixth grid key read but undeclared — #5091's evidence claimed it was already inGRID_QUERY_INPUTS; it is not #5240'suserActionshalf is NOT settled — it sits in the maintainer's inbox as that card's Q2/C, which proposes exactly this fix at exactly this producer. ⛔ Not mine to rule.packages/react/src/spec-bridge/bridges/list-view.tsis held by #5068 as of this round. Different region from theuserActionsemission, but same file — whichever lands second rebases, and the seat serializes them.The measured lesson worth keeping regardless of how either is ruled: a producer emitting a key its consumer's schema rejects is invisible to this repo's gates in both directions — the strict schema never runs on the bridged node, and the consumer's tolerance makes it render. It took an accidental probe on one key and a deletion-then-measure on the other. Neither would have been caught by review.
Generated by Claude Code