在 rc.2 抬 pin(objectui#3235 的 PR)中实测发现。该 PR 已按「跟随退役」落地,此单记录事实前提问题并请维护者复核那个取舍。
上游怎么说
@objectstack/spec 17.0.0 从 NavigationAreaSchema 移除了 area 级的 visible、requiredPermissions(外加 order),墓碑常量 AREA_VISIBLE_RETIRED / AREA_REQUIRED_PERMISSIONS_RETIRED。rc.2 里 NavigationAreaSchema 的键集只剩 id / label / icon / description / navigation。docblock 的理由:
An area is a LAYOUT grouping, not an access boundary: it carries no gate of its own. Gate the items inside it (visible / requiredPermissions on a navigation item) or gate the app (requiredPermissions on the AppSchema).
实际情况
「it carries no gate of its own」在本仓不成立。packages/layout/src/AppSchemaRenderer.tsx 的 AreaSwitcher 在 rc.1 下是这么写的:
// Filter areas by visibility & permissions
const visibleAreas = areas.filter((a) => {
if (!evalVis(a.visible)) return false;
if (a.requiredPermissions?.length && !checkPerm(a.requiredPermissions)) return false;
return true;
});
if (visibleAreas.length <= 1) return null;
也就是说 area 级的两个键都有真实消费者,而且消费它的是官方渲染器里决定「区域切换器显示哪些区域」的那一段。这与 objectstack#4667 app.homePageId 的「no shell ever read it」是同一类前提错误(objectui#3287 / objectstack#4709 已就那一处更正文案)。
补充一点:packages/types/src/app.ts 的 NavigationArea 与 packages/types/src/zod/app.zod.ts 的 NavigationAreaSchema 还专门本地重钉了 visible(objectui 用裸谓词 boolean | string,spec 用 ExpressionInput 信封),并有 page-nav-misc-spec-parity.test.ts 的绊线守着 —— 这三处一致地说明这个键在本仓是被当作活契约维护的,不是残留。
PR 里怎么处置的(请复核)
pin-bump PR 采取跟随退役,理由:
- spec 的 area 对象是
.strict(),v17 之后任何合法 app 都写不出这三个键 —— 该过滤分支对平台接受的元数据已不可达(ADR-0078 要清的死分支);
- 反向做法(本仓保留
visible / requiredPermissions)等于分叉契约:objectui 接受平台拒绝的 area,正是 AGENTS.md #0.1 禁止的第二方言;
- 能力没有消失,只是下移了一层 —— item 级
visible / requiredPermissions 原封不动,且 NavigationRenderer 用的就是 AreaSwitcher 原来那两个 evalVis / checkPerm。
行为差异(需要知情):一个区域内所有 item 都被 gate 掉时,以前整块区域从切换器消失,现在会渲染成「可见但空」的区域。数据访问不受影响(服务端强制 + item 级 gate 仍在),变的是导航面的观感。
packages/layout/src/__tests__/AppSchemaRenderer.test.tsx 里原来两条 area 级断言已改写为 item 级的同场景断言,语义是「gate 下移了,没有丢失」。
需要维护者拍板的
跟随退役这一步是实施侧按 #0.1 + 「strict 使分支不可达」推出来的,不是既有裁决。如果维护者认为 area 级 gating 是想要的能力:
个人倾向 A + 把 C 作为后续增强:A 立刻消除方言,C 用派生规则把「空区域不显示」这个真实诉求补回来,且无需任何新的 authorable key。
相关
- objectui#3235(rc.2 抬 pin PR)
- objectui#3287 / objectstack#4667 / #4709(同型前提错误)
- objectui#3310(本轮另一处同型前提错误:notification 词汇)
- ADR-0049 enforce-or-remove、ADR-0078
⚠️ 未指派 —— 记录 + 待复核。
Generated by Claude Code
在 rc.2 抬 pin(objectui#3235 的 PR)中实测发现。该 PR 已按「跟随退役」落地,此单记录事实前提问题并请维护者复核那个取舍。
上游怎么说
@objectstack/spec17.0.0 从NavigationAreaSchema移除了 area 级的visible、requiredPermissions(外加order),墓碑常量AREA_VISIBLE_RETIRED/AREA_REQUIRED_PERMISSIONS_RETIRED。rc.2 里NavigationAreaSchema的键集只剩id/label/icon/description/navigation。docblock 的理由:实际情况
「it carries no gate of its own」在本仓不成立。
packages/layout/src/AppSchemaRenderer.tsx的AreaSwitcher在 rc.1 下是这么写的:也就是说 area 级的两个键都有真实消费者,而且消费它的是官方渲染器里决定「区域切换器显示哪些区域」的那一段。这与 objectstack#4667
app.homePageId的「no shell ever read it」是同一类前提错误(objectui#3287 / objectstack#4709 已就那一处更正文案)。补充一点:
packages/types/src/app.ts的NavigationArea与packages/types/src/zod/app.zod.ts的NavigationAreaSchema还专门本地重钉了visible(objectui 用裸谓词boolean | string,spec 用ExpressionInput信封),并有page-nav-misc-spec-parity.test.ts的绊线守着 —— 这三处一致地说明这个键在本仓是被当作活契约维护的,不是残留。PR 里怎么处置的(请复核)
pin-bump PR 采取跟随退役,理由:
.strict(),v17 之后任何合法 app 都写不出这三个键 —— 该过滤分支对平台接受的元数据已不可达(ADR-0078 要清的死分支);visible/requiredPermissions)等于分叉契约:objectui 接受平台拒绝的 area,正是 AGENTS.md #0.1 禁止的第二方言;visible/requiredPermissions原封不动,且NavigationRenderer用的就是AreaSwitcher原来那两个evalVis/checkPerm。行为差异(需要知情):一个区域内所有 item 都被 gate 掉时,以前整块区域从切换器消失,现在会渲染成「可见但空」的区域。数据访问不受影响(服务端强制 + item 级 gate 仍在),变的是导航面的观感。
packages/layout/src/__tests__/AppSchemaRenderer.test.tsx里原来两条 area 级断言已改写为 item 级的同场景断言,语义是「gate 下移了,没有丢失」。需要维护者拍板的
跟随退役这一步是实施侧按 #0.1 + 「strict 使分支不可达」推出来的,不是既有裁决。如果维护者认为 area 级 gating 是想要的能力:
app.homePageId,但 objectui 的AppContent正在读它 —— 升级前需要拍板 #3287 当初那样先回上游主张「前提有误,不该退」,本仓暂时保留读取(但要接受 objectui 接受平台拒绝的 area 这一分叉,且作者已无法合法写出这两个键)。homePageId记录的同款思路,走 enforce-first 把能力以不会悬空的形状提回 spec(例如 area 自身不 gate,而是由「区域内是否存在可见 item」派生可见性 —— 这恰好就是 A 之后的自然行为,只差「全空则隐藏」这一条)。个人倾向 A + 把 C 作为后续增强:A 立刻消除方言,C 用派生规则把「空区域不显示」这个真实诉求补回来,且无需任何新的 authorable key。
相关
Generated by Claude Code