Blocked-by: #5149
发现于 #5022 的实施(RelatedList 对象列写回 accessorKey)。Filed unassigned, not claiming。观察类:今天没有用户经已声明的 授权面撞到,记录的是「适配器长出元数据味别名 + 生产端各自为政」这条分叉。基线 objectui main @ d729ce0 。
事实一:适配器容忍一个自己没声明的键 TableColumn(packages/types/src/data-display.ts:218-226)把访问键声明为必填 的 accessorKey: string,没有 name、没有 field。
而 data-table 的访问键归一化读两个键(packages/components/src/renderers/complex/data-table.tsx:777,自动列宽处 :786 同形):
accessorKey: col.accessorKey || col.name
col.name 不在 TableColumn 里。也就是说:声明面只认 accessorKey,运行面额外接受 name —— 与 #5068 记录的形状同族(那边是 ObjectGrid 容忍未声明的 accessorKey/header,方向相反),都属 AGENTS.md #0.1 说的「消费端容忍别名」。
这条别名正是 #5022 那个 bug 的形状成因:legacy name 拼写端到端能用,而 ListColumnSchema 唯一声明的 field 拼写渲染成空格子 —— 不是因为 field 更差,而是因为适配器恰好长了 name 这一条支路、没长 field 那条。#5022 的处置是让生产者 (RelatedList)在交付前把身份写进 accessorKey,刻意不去动适配器(column-identity.ts 的 TABLE_ADAPTER_COLUMN_KEY 边界);别名本身仍在。
事实二:另一个生产者把对象列原样透传,且从不读 field packages/plugin-dashboard/src/ObjectDataTable.tsx:57-65:
export function normalizeColumns(columns) {
return columns.map((col) => {
if (typeof col === 'string') return { header: humanizeFieldKey(col), accessorKey: col };
return col; // 对象条目原样返回
});
}
同文件 :110 的身份读法是 (c.accessorKey || c.name) —— name-first 的 legacy 顺序,完全不读 field ,也没接到 #3104 的 columnIdentity。于是 object-data-table 走的是 #5022 修复前 RelatedList 的老路:对象列若以 field 拼写,访问键为 undefined,格子全空,而 $expand 白名单那一步也解析不出字段。
object-data-table 在 packages/types 里没有对应的 schema 声明类型(插件注册的 widget),所以这里的 field 属未声明输入 ,和 #5068 一样是「声明面与运行面分叉」,不是今天可复现的用户故障 —— 因此定为观察类。
为什么现在记下来 RelatedList object columns: spec-canonical field spelling passes every RelatedList read, then renders header + blank cells at the data-table accessor #5022 只治了一个生产者。同一条 data-table 适配器现在有三个生产者(RelatedList / ObjectGrid / ObjectDataTable),只有 RelatedList 在交付前做身份解析,另两个各有各的拼法。既有门禁看不见这两处 。列身份双读家族:field ?? name 两种优先序并存于 15+ 处——ingestion 归一 + 单键消费 + 禁新增闸门(objectstack#4115) #3104 的 ratchet(packages/core/src/utils/__tests__/column-identity.ratchet.test.ts)要求同一行出现两个以上身份键 的 || / ?? 链才计数,而 accessorKey 被显式列为 COMPANION_KEYS;col.accessorKey || col.name 这一行只有 name 一个身份键,distinct.size 为 1,不进扫描面。ratchet 的 CONVERGED 清单里也没有 plugin-dashboard。和 finding(plugin-grid): ObjectGrid 在 ObjectGridSchema.columns 上容忍未声明的 accessorKey / header 拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068 是同族但不同处:那卡问的是 ObjectGrid 该不该声明 accessorKey;本卡记的是适配器该不该继续读 name、以及第三个生产者该不该接上同一个解析。裁定方向可能一致(向 [fields] grid columns have two incompatible key spellings: declared type says name, GridField reads field — spec-compliant grid metadata renders empty cells #3951 看齐:生产端统一为一种拼法,消费端不留容忍别名),但落点是不同文件,故另立而非并入。 复核方式 sed -n '218,227p' packages/types/src/data-display.ts # TableColumn:accessorKey 必填
sed -n '772,790p' packages/components/src/renderers/complex/data-table.tsx # 未声明的 name 别名
sed -n '49,66p;104,115p' packages/plugin-dashboard/src/ObjectDataTable.tsx # 原样透传 + name-first 读
grep -n "COMPANION_KEYS\|CONVERGED" packages/core/src/utils/__tests__/column-identity.ratchet.test.ts
分级 finding,不入 pm:queue。要不要动、往哪边动(退役 name 别名 / 让另两个生产者接上 columnIdentity / 两者都做),取决于维护者对 #5068 同一个二选一的裁定;本卡只把分叉与门禁盲区记在案。
Generated by Claude Code
Blocked-by: #5149
发现于 #5022 的实施(RelatedList 对象列写回 accessorKey)。Filed unassigned, not claiming。观察类:今天没有用户经已声明的授权面撞到,记录的是「适配器长出元数据味别名 + 生产端各自为政」这条分叉。基线 objectui
main@ d729ce0。事实一:适配器容忍一个自己没声明的键
TableColumn(packages/types/src/data-display.ts:218-226)把访问键声明为必填的accessorKey: string,没有name、没有field。而 data-table 的访问键归一化读两个键(
packages/components/src/renderers/complex/data-table.tsx:777,自动列宽处:786同形):col.name不在TableColumn里。也就是说:声明面只认accessorKey,运行面额外接受name—— 与 #5068 记录的形状同族(那边是 ObjectGrid 容忍未声明的accessorKey/header,方向相反),都属 AGENTS.md #0.1 说的「消费端容忍别名」。这条别名正是 #5022 那个 bug 的形状成因:legacy
name拼写端到端能用,而ListColumnSchema唯一声明的field拼写渲染成空格子 —— 不是因为field更差,而是因为适配器恰好长了name这一条支路、没长field那条。#5022 的处置是让生产者(RelatedList)在交付前把身份写进accessorKey,刻意不去动适配器(column-identity.ts的TABLE_ADAPTER_COLUMN_KEY边界);别名本身仍在。事实二:另一个生产者把对象列原样透传,且从不读
fieldpackages/plugin-dashboard/src/ObjectDataTable.tsx:57-65:同文件
:110的身份读法是(c.accessorKey || c.name)—— name-first 的 legacy 顺序,完全不读field,也没接到 #3104 的columnIdentity。于是object-data-table走的是 #5022 修复前 RelatedList 的老路:对象列若以field拼写,访问键为 undefined,格子全空,而$expand白名单那一步也解析不出字段。object-data-table在packages/types里没有对应的 schema 声明类型(插件注册的 widget),所以这里的field属未声明输入,和 #5068 一样是「声明面与运行面分叉」,不是今天可复现的用户故障 —— 因此定为观察类。为什么现在记下来
fieldspelling passes every RelatedList read, then renders header + blank cells at the data-table accessor #5022 只治了一个生产者。同一条 data-table 适配器现在有三个生产者(RelatedList / ObjectGrid / ObjectDataTable),只有 RelatedList 在交付前做身份解析,另两个各有各的拼法。packages/core/src/utils/__tests__/column-identity.ratchet.test.ts)要求同一行出现两个以上身份键的||/??链才计数,而accessorKey被显式列为COMPANION_KEYS;col.accessorKey || col.name这一行只有name一个身份键,distinct.size为 1,不进扫描面。ratchet 的CONVERGED清单里也没有plugin-dashboard。ObjectGridSchema.columns上容忍未声明的accessorKey/header拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068 是同族但不同处:那卡问的是 ObjectGrid 该不该声明accessorKey;本卡记的是适配器该不该继续读name、以及第三个生产者该不该接上同一个解析。裁定方向可能一致(向 [fields] grid columns have two incompatible key spellings: declared type saysname, GridField readsfield— spec-compliant grid metadata renders empty cells #3951 看齐:生产端统一为一种拼法,消费端不留容忍别名),但落点是不同文件,故另立而非并入。复核方式
分级
finding,不入pm:queue。要不要动、往哪边动(退役name别名 / 让另两个生产者接上columnIdentity/ 两者都做),取决于维护者对 #5068 同一个二选一的裁定;本卡只把分叉与门禁盲区记在案。Generated by Claude Code