Skip to content

NavigationArea 的 area 级 visible / requiredPermissions 退役前提也不成立 —— AppSchemaRenderer.AreaSwitcher 一直在按它过滤 #3311

Description

@xuyushun441-sys

在 rc.2 抬 pin(objectui#3235 的 PR)中实测发现。该 PR 已按「跟随退役」落地,此单记录事实前提问题并请维护者复核那个取舍。

上游怎么说

@objectstack/spec 17.0.0 从 NavigationAreaSchema 移除了 area 级的 visiblerequiredPermissions(外加 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.tsxAreaSwitcher 在 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.tsNavigationAreapackages/types/src/zod/app.zod.tsNavigationAreaSchema专门本地重钉visible(objectui 用裸谓词 boolean | string,spec 用 ExpressionInput 信封),并有 page-nav-misc-spec-parity.test.ts 的绊线守着 —— 这三处一致地说明这个键在本仓是被当作活契约维护的,不是残留。

PR 里怎么处置的(请复核)

pin-bump PR 采取跟随退役,理由:

  1. spec 的 area 对象是 .strict(),v17 之后任何合法 app 都写不出这三个键 —— 该过滤分支对平台接受的元数据已不可达(ADR-0078 要清的死分支);
  2. 反向做法(本仓保留 visible / requiredPermissions)等于分叉契约:objectui 接受平台拒绝的 area,正是 AGENTS.md #0.1 禁止的第二方言;
  3. 能力没有消失,只是下移了一层 —— 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(PR 现状):跟随退役,gating 只在 item / app 两层。
  • B:像 spec 17.0.0 正式版会退役 app.homePageId,但 objectui 的 AppContent 正在读它 —— 升级前需要拍板 #3287 当初那样先回上游主张「前提有误,不该退」,本仓暂时保留读取(但要接受 objectui 接受平台拒绝的 area 这一分叉,且作者已无法合法写出这两个键)。
  • C:按上游给 homePageId 记录的同款思路,走 enforce-first 把能力以不会悬空的形状提回 spec(例如 area 自身不 gate,而是由「区域内是否存在可见 item」派生可见性 —— 这恰好就是 A 之后的自然行为,只差「全空则隐藏」这一条)。

个人倾向 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpm:queue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions