发现于 #3972 的实施(PR #3984 ),不在该 PR 处理 —— #3972 的完成范围是"对正确写法报假诊断"那一类(page-header 漏 icon/actions、navigation-renderer.items 类型写错),这一条相反:声明面比实现更宽 ,于是该报的一条 invalid-enum 从来没报过。而且它的修法需要先定词表,不该由实施 agent 猜。未认领,交 PM triage。
与 #3818 同一失效家族(声明的语义与渲染器实际读点不符),但方向相反:#3818 是发布了 auto|custom 而渲染器只认已退役的旧词表;这里是根本没发布词表 ,而实现只兑现三值中的一个。
机制
packages/layout/src/index.ts 的 app-schema-renderer 声明:
{ name: 'mobileNavMode', type: 'string' },
而实现是三值联合(packages/layout/src/AppSchemaRenderer.tsx:57):
export type MobileNavMode = 'drawer' | 'bottom_nav' | 'hamburger';
ManifestInputType 有 'enum',ManifestInput 有 enum 数组字段(packages/sdui-parser/src/types.ts:51-73),checkType 对 'enum' 会给出 error 级的 invalid-enum(validate.ts:130-140)—— 所以这个词表是完全表达得了的,和 #3832 的联合类型表达力问题无关。
后果是两条,都无诊断:
写错值静默回落。 作者(尤其 AI 作者)写 mobileNavMode: "bottom-nav"(连字符,而实现要的是下划线 bottom_nav)拿不到任何诊断:type: 'string' 判的只是 typeof value === 'string',于是通过;渲染器 :538 的 showBottomNav = mobileNavMode === 'bottom_nav' 不成立,静默走 drawer。设计器那边同样把它渲染成自由文本输入框,而不是三选一。
词表里的 'hamburger' 本身零读点。 全文件对 mobileNavMode 的读只有 :430 的默认值(= 'drawer')与 :538 的 === 'bottom_nav',所以 'hamburger' 与 'drawer' 行为完全一致 —— 而 :411 的 JSDoc 把它写成 "hamburger(collapsed sidebar)",是个已发布却未实装的语义(page:header.icon 与 page:card.actions:spec 声明、渲染器零读点 —— 二择一(接线 / 按 showSubscriptionToggle 先例声明并写明 KNOWN GAP) #3829 / record:details 的 layout 发布了 auto|custom 语义,渲染器唯一的读点只认 spec 已退役的 inline|compact —— auto/custom 从未被实装 #3818 的同一类)。
为什么不在 #3972 的 PR 里顺手改
"声明成 enum"这个动作要求先回答"三个值里哪些是真的",而两条路的公开契约不同:
另外任一条路都会新增 error 级诊断 :今天写了词表外值的仓外消费者会从"静默回落"变成"校验报错"。方向上这是对的(declared = enforced,让 AI 作者当场被拦),但它是收紧决定,得有人拍。
可达性诚实标注
仓内没有任何 JSON 元数据把 app-schema-renderer 当 schema 节点写(全仓 grep 只命中注册本身);React 调用侧受 TS 约束,mobileNavMode 传错值编译期就红。所以今天的实际受害者只有仓外按 inputs / packages/layout/README.md 作 schema 驱动的消费者,以及"以为 'hamburger' 有效"的任何调用方(仓内是 0 个:唯一传值处是 __tests__/AppSchemaRenderer.test.tsx:513 传的 'bottom_nav')。因此按 observation-class 打 finding、不挂 pm:queue,定级请分诊时自行判断。
参考位置
packages/layout/src/index.ts —— app-schema-renderer 的 mobileNavMode input
packages/layout/src/AppSchemaRenderer.tsx:57 —— MobileNavMode 三值联合
packages/layout/src/AppSchemaRenderer.tsx:430 / :538 —— 全部两个读点
packages/layout/src/AppSchemaRenderer.tsx:411 —— 把 hamburger 写成 collapsed sidebar 的 JSDoc
packages/sdui-parser/src/validate.ts:130-140 —— invalid-enum(error 级)
关联:#3972 (发现于此实施)、#3984 (该单的 PR)、#3818 (同族、方向相反)、#3829 (声明了却零读点)、#3832 (不同根因:ComponentInput.type 表达力)
发现于 #3972 的实施(PR #3984),不在该 PR 处理 —— #3972 的完成范围是"对正确写法报假诊断"那一类(
page-header漏icon/actions、navigation-renderer.items类型写错),这一条相反:声明面比实现更宽,于是该报的一条invalid-enum从来没报过。而且它的修法需要先定词表,不该由实施 agent 猜。未认领,交 PM triage。与 #3818 同一失效家族(声明的语义与渲染器实际读点不符),但方向相反:#3818 是发布了
auto|custom而渲染器只认已退役的旧词表;这里是根本没发布词表,而实现只兑现三值中的一个。机制
packages/layout/src/index.ts的app-schema-renderer声明:而实现是三值联合(
packages/layout/src/AppSchemaRenderer.tsx:57):ManifestInputType有'enum',ManifestInput有enum数组字段(packages/sdui-parser/src/types.ts:51-73),checkType对'enum'会给出 error 级的invalid-enum(validate.ts:130-140)—— 所以这个词表是完全表达得了的,和 #3832 的联合类型表达力问题无关。后果是两条,都无诊断:
mobileNavMode: "bottom-nav"(连字符,而实现要的是下划线bottom_nav)拿不到任何诊断:type: 'string'判的只是typeof value === 'string',于是通过;渲染器:538的showBottomNav = mobileNavMode === 'bottom_nav'不成立,静默走 drawer。设计器那边同样把它渲染成自由文本输入框,而不是三选一。'hamburger'本身零读点。 全文件对mobileNavMode的读只有:430的默认值(= 'drawer')与:538的=== 'bottom_nav',所以'hamburger'与'drawer'行为完全一致 —— 而:411的 JSDoc 把它写成 "hamburger(collapsed sidebar)",是个已发布却未实装的语义(page:header.icon与page:card.actions:spec 声明、渲染器零读点 —— 二择一(接线 / 按 showSubscriptionToggle 先例声明并写明 KNOWN GAP) #3829 /record:details的layout发布了auto|custom语义,渲染器唯一的读点只认 spec 已退役的inline|compact—— auto/custom 从未被实装 #3818 的同一类)。为什么不在 #3972 的 PR 里顺手改
"声明成 enum"这个动作要求先回答"三个值里哪些是真的",而两条路的公开契约不同:
enum: ['drawer', 'bottom_nav', 'hamburger']—— 与 TS 类型一致,但把一个渲染器不实装的值正式发布成合法作者面(page:header.icon与page:card.actions:spec 声明、渲染器零读点 —— 二择一(接线 / 按 showSubscriptionToggle 先例声明并写明 KNOWN GAP) #3829 的方向);enum: ['drawer', 'bottom_nav']—— 与渲染器实际行为一致,但与MobileNavMode类型矛盾,等于同时宣布'hamburger'该按 ADR-0049 enforce-or-remove 处理(实装 collapsed-sidebar,或从类型里删掉)。另外任一条路都会新增 error 级诊断:今天写了词表外值的仓外消费者会从"静默回落"变成"校验报错"。方向上这是对的(declared = enforced,让 AI 作者当场被拦),但它是收紧决定,得有人拍。
可达性诚实标注
仓内没有任何 JSON 元数据把
app-schema-renderer当 schema 节点写(全仓 grep 只命中注册本身);React 调用侧受 TS 约束,mobileNavMode传错值编译期就红。所以今天的实际受害者只有仓外按inputs/packages/layout/README.md作 schema 驱动的消费者,以及"以为'hamburger'有效"的任何调用方(仓内是 0 个:唯一传值处是__tests__/AppSchemaRenderer.test.tsx:513传的'bottom_nav')。因此按 observation-class 打finding、不挂pm:queue,定级请分诊时自行判断。参考位置
packages/layout/src/index.ts——app-schema-renderer的mobileNavModeinputpackages/layout/src/AppSchemaRenderer.tsx:57——MobileNavMode三值联合packages/layout/src/AppSchemaRenderer.tsx:430/:538—— 全部两个读点packages/layout/src/AppSchemaRenderer.tsx:411—— 把hamburger写成 collapsed sidebar 的 JSDocpackages/sdui-parser/src/validate.ts:130-140——invalid-enum(error 级)关联:#3972(发现于此实施)、#3984(该单的 PR)、#3818(同族、方向相反)、#3829(声明了却零读点)、#3832(不同根因:
ComponentInput.type表达力)