Skip to content

finding(react): the spec-bridge still forwards a per-column wrap after #5453 retired the only forward downstream of it — ListColumn.wrap is now authorable end-to-end with no renderer anywhere #6650

Description

@os-sales

Found while implementing objectui#5453 (retire the dead per-column wrap forward in ObjectGrid). Out of that card's fence — it named packages/plugin-grid and packages/components' data-table.tsx — so it is filed rather than fixed there.

What

packages/react/src/spec-bridge/bridges/list-view.ts, in mapColumn():

if(col.wrap!=null)mapped.wrap=col.wrap;

@objectstack/spec (17.2.0) declares wrap on ListColumnwrap: z.ZodOptional(z.ZodBoolean) — so an author may legitimately write it on a spec list view. The bridge forwards it into the object-grid schema. Until #5453, ObjectGrid.generateColumns() then forwarded it once more into the TableColumn[] slot, where data-table.tsx never read it.

#5453 removed that second hop, on the measurement that data-table.tsx has zero reads of a column-level wrap and offers no clamp / expand / wrap affordance for long cell text at all. So the chain is now one hop shorter and still terminates in nothing:

author writes ListColumn.wrap (spec-declared, valid)
-> spec-bridge mapColumn() forwards it <- this line
-> object-grid schema column
-> [#5453 deleted the hop that used to be here]
-> nothing reads it, anywhere

Evidence

Repo-wide, on f241a4df plus #5453's branch, every .wrap read outside wrapper / nowrap / flex-wrap:

sitewhat it is
react/spec-bridge/bridges/list-view.ts:71the forward above
react/spec-bridge/__tests__/SpecBridge.test.ts:180pins the forward (expect(col.wrap).toBe(true))
components/renderers/layout/flex.tsx, stack.tsxschema.wrap on flex/stack layout — unrelated key
core/actions/ActionRunner.ts, app-shell action runtimebodyShape.wrap — unrelated key

No renderer resolves a column-level wrap. The pin test asserts only that the bridge passes the key through; it would stay green if every consumer vanished, which is what has now happened.

Why it is worth a card rather than a silent deletion

The bridge's own docblock states its contract deliberately: "A spec ListColumn in, the same column out — in the spelling the spec declares", and "Nothing is invented on the way through". Under that contract, forwarding wrap is the bridge doing its job faithfully, not a bug in the bridge. That is exactly why #5453 stopped at the plugin-grid hop and did not reach in here: deleting this line would make the bridge deliberately lossy for a spec-declared key, which is a different judgement from "a producer must not write keys its consumer never reads".

So the real question is one level up and it is a spec question: should @objectstack/spec keep declaring ListColumn.wrap when no renderer in the ecosystem implements it? That is ADR-0049 enforce-or-remove on a spec property, and the resolution likely lands in objectstack/packages/spec rather than here, with this repo's bridge line and pin test following it. Routing that is triage's call, not this seat's — hence a finding, unassigned, with no pm:queue.

Two honest resolutions, in the order the enforce-or-remove default suggests:

Related: #5453 (the forward that was retired), #6458 (ObjectGrid honours four undeclared authored column keys), #6004 (the untyped emit that hid both).

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepm:queuepriority:p2

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions