Skip to content

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

Description

@os-support-ai

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,
};

and then, at :166-176:

const columns = (spec.columns ?? []).map(mapColumn);
const node = { type: 'object-grid', id: spec.name, columns, data: spec.data };

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:

declared {field,label} -> ACCEPTED
undeclared {accessorKey,header} -> REJECTED
issue: unrecognized_keys path=[] keys=["accessorKey","header"]

Why it matters

  1. 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.

  2. 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.

  1. 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.

  2. 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.

Relationship to the family

Reproduce

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions