Repository navigation
app-schema-renderer 的 mobileNavMode 声明成自由文本 string,实现却是三值联合 —— 写错的值静默回落,且词表里的 'hamburger' 在渲染器零读点 #3985
Description
Activity
Findings triage — re-graded
finding→needs-user-decision(labels updated in the same pass).- Premise verified at objectui
origin/main@0cbdca8: declaration still{ name: 'mobileNavMode', type: 'string' }(packages/layout/src/index.ts:181); the union still carries three values including'hamburger'(AppSchemaRenderer.tsx:57); the only read points are still the default at:430and the=== 'bottom_nav'comparison at:538— so'hamburger'remains declared-but-inert and any misspelled value still falls back silently. All facts hold. - Why decision box, not queue: the fix is blocked on a vocabulary ruling the card itself refuses to guess — (a) publish
enum: ['drawer','bottom_nav','hamburger'], formally shipping a value the renderer does not implement, or (b) publish the two-value enum and thereby rule that'hamburger'goes through ADR-0049 enforce-or-remove (implement collapsed-sidebar or delete it from the type). Either path also newly turns today's silent fallback into an error-levelinvalid-enumfor out-of-repo authors — a tightening of a published authoring surface. Both halves are maintainer calls (contract shape + appetite for implementing vs removing a declared capability), so per the docs(layout): app-shell.mdx 的 AppShellProps 声明块补齐到 7 个 props,并钉到 interface (#4808) #4829 rule this is a pending decision, not dispatchable work. No prior ruling found on the card (0 comments) or in therecord:details的layout发布了auto|custom语义,渲染器唯一的读点只认 spec 已退役的inline|compact—— auto/custom 从未被实装 #3818/page:header.icon与page:card.actions:spec 声明、渲染器零读点 —— 二择一(接线 / 按 showSubscriptionToggle 先例声明并写明 KNOWN GAP) #3829 family threads' visible state. - Dedup: same failure family as
record:details的layout发布了auto|custom语义,渲染器唯一的读点只认 spec 已退役的inline|compact—— auto/custom 从未被实装 #3818 (opposite direction) andpage:header.icon与page:card.actions:spec 声明、渲染器零读点 —— 二择一(接线 / 按 showSubscriptionToggle 先例声明并写明 KNOWN GAP) #3829 (declared, zero read points) — related but none covers this key; no open PR touchesmobileNavMode. - Once decided, execution is mechanical and should come back through the queue (the sub-hour fix is the enum line + validate coverage; option (a) additionally needs the collapsed-sidebar implementation costed separately).
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- Premise verified at objectui
Maintainer ruling (2026-08-10, directed in session
session_01BPWqbmEFU8gJepBJTHESXd): narrow the declaration; retire the dead value.mobileNavMode's declared type becomes the real three-value union — a misspelled value must refuse at validation, not silently fall back.hamburgeris retired under enforce-or-remove: zero read points in the renderer means it never was behavior. If someone wants it as behavior, that is an implementation card first.needs-user-decision→pm:queue.
Generated by Claude Code
认领(objectui 车道分片 PM,会话
session_01GTRjn8xBqp75dk7kFupVRt,批次 17):branchclaude/issue-3985-mobilenavmode-enum。按 2026-08-10 维护者裁定实施:声明收窄为实现了的值的枚举、误拼在校验层拒绝(不再静默回落)、
hamburger按 enforce-or-remove 退休(渲染器零读点,从未是行为;要行为先立实现卡)。文件面:packages/layout/src/index.ts(声明)、packages/app-shell的 AppSchemaRenderer(联合类型与读点)、相关校验/文档/catalog 触点。
Generated by Claude Code
- added a commit that references this issue
on Aug 17, 2026 - added a commit that references this issue
on Aug 24, 2026 - added a commit that references this issue
on Sep 1, 2026
发现于 #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表达力)