发现于 #4814 的前置消费者测量(方案 A 退役 owner 别名)。不在该卡范围内,且无论 #4814 最终裁 A 还是 B 都独立存在,故单独立此单。
观察类(observation-class):今天没有用户碰得到 —— 两条别名都还在,守卫没有在保护一个已经破的东西。它记录的是守卫本身的覆盖洞。
事实(实读 origin/main @ 1ef236e18)
packages/fields/src/field-type-coverage.test.ts 是「field-type → renderer 注册表」的回归守卫,文件头自陈它防的正是这个失效模式:
These mappings regressed once already: ~25 specialized field types silently fell back to a plain text input (form) and the raw text cell renderer (read), because the mapping tables were incomplete.
它有两张名单,分别钉两条路径:
CELL_RENDERER_TYPES(:48)—— 含'user' 与 'owner',断言二者解析到专用 cell renderer 而非 TextCellRenderer。FORM_WIDGET_TYPES(:19-32)—— 既不含 user,也不含 owner。
所以表单那一半对 person-picker 家族是空的:packages/fields/src/field-type-alias.ts 里的 user: 'field:user'(:104)与 owner: 'field:owner'(:105)任意一条被删,mapFieldTypeToFormType 会走 :155 的 return typeMap[fieldType] || 'field:text'; 静默兜到文本框,而这个守卫不会红。lookup / master_detail / tree 等其余引用类型都在 FORM_WIDGET_TYPES 里,唯独 person-picker 这一支不在。
为什么是「单向失明」而不是「对称缺失」
同一个守卫的 cell 半边是钉住的。于是删 registerFieldRenderer('user'|'owner', UserCellRenderer) 会红,删对应的表单别名不会红 —— 同一个家族、同一个文件、两条路径,红绿方向相反。#4814 的测量就是在这个不对称上撞出来的:按字面执行退役,cell 那半立刻红、表单那半静默降级,读起来像「测试通过了所以退役是安全的」。
影响
今天为零 —— 两条别名都在,field:user / field:owner 都能解析。这条记录的是守卫的可信度:一份自称防「静默退化成文本框」的名单,恰恰在最容易被当成冗余别名删掉的两个键上没有覆盖(owner 正在 #4814 被提议删除,user 是 #4790 一族刚动过的邻居)。
建议(不预设结论)
把 user 加进 FORM_WIDGET_TYPES 是显然的一半。owner 那一半取决于 #4814 的重裁结果 —— 若 owner 退役,它就不该进这张名单,而该进「已退役键」的反向断言(参照 index.tsx 里 field:capability-multiselect 的 TOMBSTONE 约定)。因此这张单建议排在 #4814 重裁之后,或者先只补 user、把 owner 留给 #4814 收口。
参考
发现于 #4814 的前置消费者测量(方案 A 退役
owner别名)。不在该卡范围内,且无论 #4814 最终裁 A 还是 B 都独立存在,故单独立此单。观察类(observation-class):今天没有用户碰得到 —— 两条别名都还在,守卫没有在保护一个已经破的东西。它记录的是守卫本身的覆盖洞。
事实(实读 origin/main @
1ef236e18)packages/fields/src/field-type-coverage.test.ts是「field-type → renderer 注册表」的回归守卫,文件头自陈它防的正是这个失效模式:它有两张名单,分别钉两条路径:
CELL_RENDERER_TYPES(:48)—— 含'user'与'owner',断言二者解析到专用 cell renderer 而非TextCellRenderer。FORM_WIDGET_TYPES(:19-32)—— 既不含user,也不含owner。所以表单那一半对 person-picker 家族是空的:
packages/fields/src/field-type-alias.ts里的user: 'field:user'(:104)与owner: 'field:owner'(:105)任意一条被删,mapFieldTypeToFormType会走:155的return typeMap[fieldType] || 'field:text';静默兜到文本框,而这个守卫不会红。lookup/master_detail/tree等其余引用类型都在FORM_WIDGET_TYPES里,唯独 person-picker 这一支不在。为什么是「单向失明」而不是「对称缺失」
同一个守卫的 cell 半边是钉住的。于是删
registerFieldRenderer('user'|'owner', UserCellRenderer)会红,删对应的表单别名不会红 —— 同一个家族、同一个文件、两条路径,红绿方向相反。#4814 的测量就是在这个不对称上撞出来的:按字面执行退役,cell 那半立刻红、表单那半静默降级,读起来像「测试通过了所以退役是安全的」。影响
今天为零 —— 两条别名都在,
field:user/field:owner都能解析。这条记录的是守卫的可信度:一份自称防「静默退化成文本框」的名单,恰恰在最容易被当成冗余别名删掉的两个键上没有覆盖(owner正在 #4814 被提议删除,user是 #4790 一族刚动过的邻居)。建议(不预设结论)
把
user加进FORM_WIDGET_TYPES是显然的一半。owner那一半取决于 #4814 的重裁结果 —— 若owner退役,它就不该进这张名单,而该进「已退役键」的反向断言(参照index.tsx里field:capability-multiselect的 TOMBSTONE 约定)。因此这张单建议排在 #4814 重裁之后,或者先只补user、把owner留给 #4814 收口。参考
packages/fields/src/field-type-coverage.test.ts:19-32(FORM_WIDGET_TYPES)、:34-49(CELL_RENDERER_TYPES)packages/fields/src/field-type-alias.ts:104-105、:155ownerwidget 拿不到表单下发的 dataSource,而 plugin-grid 认为它需要 —— 且owner根本不在 spec 的 FieldType 里(enforce-or-remove 待判) #4814(owner别名退役,前置测量已证伪零消费者)、DATA_SOURCE_FIELD_TYPES(form 层)与 core 的 EXPANDABLE_FIELD_TYPES 已知不同集且零 gate —— 同 #4770 的第二张允许表待收敛 #4790