Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

[fields] grid columns have two incompatible key spellings: declared type says name, GridField reads field — spec-compliant grid metadata renders empty cells #3951

Closed

Description

@yinlianghui

Found while implementing #3910 (converting the docs field catalog to form hosting). Out of that card's scope — filed rather than fixed, because picking the surviving spelling is a contract decision with a live blast radius.

The divergence

A grid field's columns are declared by GridColumnDefinition in packages/types/src/field-types.ts:677, which is also the declared type of GridFieldMetadata.columns (field-types.ts:651):

export interface GridColumnDefinition {
  /** Column field name */
  name: string;
  label?: string;
  type: string;
  // ...
}

But the widget that renders those columns, packages/fields/src/widgets/GridField.tsx:41, declares its own local interface and reads a different key:

export interface GridColumn {
  field: string;
  // ...
}

Every read in GridField is c.field — key={c.field} (:558, :590, :620), blank[c.field] (:399), applyCell(rowIdx, col.field, …) (:449), columns.findIndex((c) => c.field === totalField) (:528), extraShown.has(c.field) (:361). There is no normalization from name.

Consequence

Metadata authored against the declared type renders a grid whose cells are all empty, plus a React key warning (because key={c.field} is undefined for every column).

Measured by rendering GridField directly — no form, no docs wrapper, identical rows, only the column key spelling differs:

name-spelled  (GridColumnDefinition / catalog): key-warnings=1  rows=[["1","IN[]","IN[]","IN[]"],["2","IN[]","IN[]","IN[]"],["3","IN[]","IN[]","IN[]"]]
field-spelled (GridField GridColumn)          : key-warnings=0  rows=[["1","IN[Widget A]","IN[2]","IN[29.99]"],["2","IN[Widget B]","IN[1]","IN[49.99]"],["3","IN[]","IN[]","IN[]"]]

(IN[x] = the cell input's value; row 3 is the ghost/new row.)

Which side each producer is on:

  • name — GridColumnDefinition (the declared type), the three fields-grid catalog examples, and the prose on content/docs/fields/grid.mdx ("name: string; // Column field name").
  • field — GridField itself, and the master-detail derivation in packages/plugin-form/src/deriveMasterDetail.ts (hydrateColumns reads fields[col.field] at :261).

So real app paths that go through deriveMasterDetail work, and anything authored from the published type or the documentation does not. That is the worst direction for this repo's second axis: an AI author reading GridColumnDefinition or the grid docs page produces a grid that silently renders nothing in every cell.

Visible today

The three demos on /docs/fields/grid render tables with the correct row COUNT and every cell empty (browser-verified during #3910). This predates #3910 — the old docs-demo wrapper passed the same name-spelled columns through, so the cells were empty there too. #3910 deliberately did not re-spell the examples to field: that would fossilize into the documentation a key the declared type does not have, which is the exact failure class #3798 ruling B set out to remove.

Two resolutions, and why this needs a maintainer

  1. Make GridField read the declared name (contract-first, AGENTS.md #0.1 — the consumer is the divergent side). Cost: must migrate deriveMasterDetail/hydrateColumns and any app metadata already passing field, or accept both during a deprecation window, which is itself the tolerant-alias smell.
  2. Change the declared type to field and fix GridColumnDefinition, the catalog examples and the grid docs prose. Cost: breaks any metadata authored against the currently published type.

Option 1 matches the stated contract and the documentation; option 2 matches what the live code actually does. Either way the fix must land on ONE side — a renderer-side col.field ?? col.name alias is the thing AGENTS.md #0.1 forbids, and would leave two dialects in the catalog forever.

Related family (types-vs-spec drift, not the same key): #2231, #2890.

Reproduce

pnpm exec vitest run packages/fields/src/widgets/  # existing tests all pass — nothing covers this

Render GridField with value set to two row objects and columns spelled name, and observe empty cells plus the key warning; re-spell to field and both go away.

Activity

  1. yinlianghui commented on Aug 9, 2026

    @yinlianghui
    ContributorAuthor

    PM 分诊(session_01GTRjn8xBqp75dk7kFupVRt):挂 needs-user-decision 入决策箱 —— 收敛到哪边拼写是契约方向题,两案 blast radius 已在正文实证齐备,PM 不代裁。

    给维护者的决策材料摘要:

    • 案 1(GridField 改读声明的 name):契约优先,符合 AGENTS.md #0.1 与现行文档/类型/catalog 三处一致的 name;成本是迁移 deriveMasterDetail/hydrateColumns 及存量按 field 授权的 app 元数据。
    • 案 2(声明改成 field):符合现行代码实际行为(真实 app 路径经 deriveMasterDetail 均为 field);成本是破坏按已发布类型授权的元数据,且要改类型+catalog+文档三处。
    • 两案共同底线:只能落一边,渲染器侧 col.field ?? col.name 别名是 AGENTS.md #0.1 明令禁止的容忍写法。
    • 倾向仅供参考:案 1 与「文档是第一手转写源」的第二轴一致(AI 作者照声明类型/文档写出的 grid 应当能渲染),但案 2 迁移面更小 —— 取舍在存量 app 元数据的兼容承诺,这正是需要维护者拍板的部分。

    裁定后实施单可直接派(正文已含双向复现方法与全部读写站点清单)。


    Generated by Claude Code

  2. os-zhuang commented on Aug 10, 2026

    @os-zhuang
    Contributor

    Maintainer ruling (2026-08-10, directed in session session_01BPWqbmEFU8gJepBJTHESXd): the published spec spelling wins — fix the reader.

    GridField aligns to the declared vocabulary and reads name; spec-compliant metadata must render. Before landing: grep stored/example metadata for in-the-wild field usage and put the count in the PR — if nonzero, handle it with an explicit conversion, not a tolerant dual-read; a permanent second spelling is exactly what AGENTS.md #0.1 forbids. Same pin discipline as objectui#4041: metadata written in the declared spelling must produce populated cells.

    needs-user-decision → pm:queue.


    Generated by Claude Code

  3. self-assigned this
    on Aug 17, 2026
  4. yinlianghui commented on Aug 17, 2026

    @yinlianghui
    ContributorAuthor

    认领(objectui 车道分片 PM,会话 session_01GTRjn8xBqp75dk7kFupVRt,批次 16):branch claude/issue-3951-grid-column-name。

    按 2026-08-10 维护者裁定实施:声明拼写 name 胜出,修 reader(GridField 及 deriveMasterDetail/hydrateColumns),先普查存量 field 拼写用量并在 PR 写明计数,非零走显式转换 ⛔ 容忍双读;pin 纪律同 #4041(按声明拼写授权的元数据必须渲染出非空单元格)。文件面:packages/fields/src/widgets/GridField.tsx、packages/plugin-form/src/deriveMasterDetail.ts、fields-grid catalog 三例、content/docs/fields/grid.mdx。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions