Repository navigation
Description
从 #4722 的实现中记录的越界发现(未认领)。
现象
#4722 让服务端权威闸门 filterAppForUser 走 areas[].navigation,area 内导航项的
requiredPermissions / requiresService 现在由服务端剥离。但 packages/spec 里两处
仍然陈述改前的事实:
-
packages/spec/src/ui/app.zod.ts:662(AREA_REQUIRED_PERMISSIONS_RETIRED处方正文):requiredPermissions/requiresServiceon a navigation ITEM are stripped server-side
from the app's top-levelnavigationtree and re-checked in the shell. Items nested
underareas[]are gated in the shell only — the server does not walkareas— so
anything that must never reach the browser belongs in the top-level tree, or in its own app.这段话是作者写错 area 级键时唯一能读到的处方(strict schema 的 unknown-key 报错正文),
现在它把一个已经关闭的缺口描述成仍然存在。方向上是「过度保守」而非不安全(它劝作者把
敏感项挪到顶层树,这仍然可行),但它是错的,而且是说给作者听的那一份。 -
packages/spec/src/ui/app.test.ts:1374有一条断言把这个措辞钉死:// The honest caveat: the server does not walk areas, so an item gate // INSIDE an area is shell-side only. expect(msg).toMatch(/shell only|does not walk/is);所以改处方正文必须同时改这条 pin —— 两者是一个耦合改动。
为什么没在 #4722 里顺手改
#4722 的派发约束是 packages/spec/** 零改动(单文件例外只开给
packages/spec/liveness/app.json 的账本 note,已按预案改写)。处方正文是 .describe 级别的
用户可见字符串,改它要连带 pin 与 spec 生成物(gen:schema / gen:docs)一起动,正是
发布窗口里该避开的涟漪。故按 Prime Directive #10 独立记录。
建议的修法(一次改完)
- 改
AREA_REQUIRED_PERMISSIONS_RETIRED正文:项级requiredPermissions/requiresService
在两棵树(顶层navigation与areas[].navigation)都由服务端剥离(filterAppForUser 只走 app 顶层 navigation —— areas[] 里的 nav 项权限过滤仅客户端生效(#4651 移除假闸门后剩下的真缺口) #4722);仍然只在
客户端求值的是visible(CEL)与requiresObject—— 必须永不到达浏览器的东西写
requiredPermissions,不要写visible。 - 同步改
app.test.ts那条断言(改成钉新的正确措辞,别只是删掉)。 - 跑
pnpm --filter @objectstack/spec check:generated,按它报的 stale 项重新生成。 - 顺带核对
AREA_VISIBLE_RETIRED正文:它指向项级visible,那一层依然只在客户端求值,
所以那段大概率不用改 —— 确认一下即可。
区分清楚:退役的 area 级键(areas[].visible / areas[].requiredPermissions)不复活,
本单只是把处方里关于 area 内部项级闸门的那句事实改对。
参考:#4722(实现)、#4651(退役裁决)、packages/spec/liveness/app.json 的
areas.navigation note(已在 #4722 里改写,可作为正确措辞的蓝本)。
Activity
os-zhuang commentedon Aug 4, 2026
认领:PM 循环第 1 轮(v17 ci-tooling 工作集 / C 包 #5163)
会话:
session_01FTszibd6C8sUCCZnM4VcrL分支:
claude/issue-4749-area-prescription-staleWorktree:
objectstack-issue-4749域:
domain:spec-tooling文件面:
packages/spec/src/ui/app.zod.ts(仅AREA_REQUIRED_PERMISSIONS_RETIRED处方正文)、packages/spec/src/ui/app.test.ts(pin 断言换钉)、spec 生成物(check:generated整体重生成,含content/docs/references/ui/*)、.changeset/*app.zod.ts今日已被 #5250 / #5246 改动,派发词含「先核对 origin/main 现状,issue 引用的行号可能已移位」。Generated by Claude Code
os-zhuang commentedon Aug 4, 2026
PM 复核(第 1 轮):PR #5336 —— 主体通过,一处扩范围返工中
会话
session_01FTszibd6C8sUCCZnM4VcrL。逐条对 GitHub 与origin/main实况核验(不取报告自述):通过项
app.zod.ts:690(issue 写 662)、pin 在app.test.ts:1439(issue 写 1374),行号因今日 feat(spec)!: object 内层块拒绝未知键 —— 13 站点收紧,2 个站点依据实测保留 (#4001 批 19/20) #5250 / docs(spec,skills): 文档与 skill 追平端点执行器(#5040 E9) #5246 移位,dev 基于合并后的代码工作。packages/rest/src/rest-server.ts:1811注释[#4722] Applies the SAME item gate to every areas[].navigation tree,1890 行filterAreas对每棵areas[].navigation跑同一个filterNav。(记一条给后来者:该文件 4800 行另有一处「does not walk」,是无关的 FSM 注释,别误判。)/BOTH trees/、/areas\[\]\.navigation/、/#4722/),并保住 filterAppForUser 只走 app 顶层 navigation —— areas[] 里的 nav 项权限过滤仅客户端生效(#4651 移除假闸门后剩下的真缺口) #4722 没有改变的那一半(visibleCEL 与requiresObject仍只在客户端求值),外加对旧说法的负向断言。这一点判断正确 —— 一份对areas[]闭口不谈的处方,作者读到的默认结论仍是旧边界。expected … to match /BOTH trees/s、1 failed | 97 skipped,还原后复绿。app.test.ts98 passed、全量 spec 312 files / 8022 tests passed、typecheck clean、check:generated9/9。check:api-surface首轮红已正确识别为 AGENTS.md §9 的 stale-dist 幻影(全新 worktree 未 build),build 后复绿。content/docs/releases/零改动,未手改任何生成物。返工项(一处,已回派同一 dev、同 worktree 续做)
AREA_VISIBLE_RETIRED的收尾句把服务端强制落点枚举成「app 本身 + 顶层navigation的项」两处,#4722 之后漏了areas[].navigation的项。dev 按派发的文件面(仅AREA_REQUIRED_PERMISSIONS_RETIRED一个字符串)没改,并如实报告 —— 这是 PM 派发时把文件面收窄过头,不是 dev 越界,本单正文本就要求「确认AREA_VISIBLE_RETIRED」,确认结果是需要改,那它就在本单范围内。已扩范围折进 PR #5336:同文件、同常量块、约六个词,另开 PR 按同文件串行规则要等本 PR 合入,为六个词付一整轮;更要紧的是留着它 = 一条处方改对、紧邻的另一条留错。越界发现 #5337:已核验属实并入队(收窄为
migrations/registry.ts的 protocol-17 rationale + 其投影docs/protocol-upgrade-guide.md:173+ 未发布 changeset;PM 已裁定 changeset 一并改口径)。返工提交与 CI 全绿后转 ready 入队。
Generated by Claude Code
fix(spec): fold the sibling prescription in — AREA_VISIBLE_RETIRED's …
os-zhuang commentedon Aug 4, 2026
PM 复核(返工轮):ACCEPT → PR #5336
会话
session_01FTszibd6C8sUCCZnM4VcrL。返工项已按裁定落地(提交23ace2690),对 GitHub diff 逐条核验:AREA_VISIBLE_RETIRED的枚举补全为「app 本身 + 两棵导航树的项」,app.test.ts对应 case 换钉不是删钉(钉either navigation tree/areas[].navigation/#4722),并对旧枚举加负向断言。AREA_VISIBLE_RETIRED一块(保留第 1 轮修复)→AssertionError: expected … to match /either navigation tree/s,Tests 1 failed | 97 skipped,还原后复绿。第 1 轮/BOTH trees/那次仍然有效。.changeset/area-prescription-both-trees.md,未新增第二份。check:api-surface首轮红仍是全新 worktree 的 stale-dist 幻影,build 后 9/9 全绿。visible的口径未被带歪(filterAppForUser 只走 app 顶层 navigation —— areas[] 里的 nav 项权限过滤仅客户端生效(#4651 移除假闸门后剩下的真缺口) #4722 只碰了requiredPermissions/requiresService),area 级键保持退役、措辞未读成复活。两处 dev 的主动判断,我认为都对且值得记下:
visible与requiredPermissions的分工写死了 ——「visible隐藏的是已经发出去的条目,requiredPermissions才让条目根本不被发出」。理由是走到这条报错前的作者正攥着一个 CEL 表达式,「就近改写成项级visible」是此刻最顺手也最危险的落点。这是提前堵掉一条安全语义的误读路径,不是文案润色。areas」,并投影进生成的升级指南 #5337,把发现 (a) 标注为已落地并加了「勿重复实现」——否则下一个被派到 protocol-17 的 migration rationale 仍写着「the server does not walkareas」,并投影进生成的升级指南 #5337 的 dev 会返工刚合入的代码。PM 补了一处:该改写把「未发布 changeset 的口径请维护者定」恢复成了原始措辞,而我在分诊评论里已裁定一并改;已在 protocol-17 的 migration rationale 仍写着「the server does not walkareas」,并投影进生成的升级指南 #5337 正文更正,免得留下一个假的未决项。worktree 处置也正确:按磁盘纪律拆除后,以同路径同分支恢复(
git worktree add <同路径> <同分支>),未新建任何东西,认领/分支/PR 三者不变。CI 在
23ace2690上重跑中,全绿后转 ready 入队。Generated by Claude Code
os-zhuang commentedon Aug 5, 2026
已落地 —— PR #5336 经合并队列合入 main(
553a47fda)会话
session_01FTszibd6C8sUCCZnM4VcrL。落地后复核判据本身:app.zod.ts查either navigation tree会零命中,看起来像AREA_VISIBLE_RETIRED的改动没落地。反查邻近词后真相是它被字符串拼接拆在两行:运行期组装后才完整,所以
app.test.ts:1472的/either navigation tree/断言是通过的。处方正文一律是拼接字符串,行式 grep 天然看不见跨行短语 —— 与 #5337 里migrations/registry.ts672–674 行完全同形。零命中必须用确定存在的邻近词反查,否则会得出「改动没落地」的错误结论。两条处方(
AREA_REQUIRED_PERMISSIONS_RETIRED与扩范围折入的AREA_VISIBLE_RETIRED)都完好落地,退役裁决未被读成复活。剩余半边 #5337 仍然成立,已复核
origin/main:packages/spec/src/migrations/registry.ts:674那句「walk `areas`」还在,并且仍在投影进docs/protocol-upgrade-guide.md。该单已入队,派发时以本 PR 落地的措辞为蓝本。Generated by Claude Code
fix(spec): 两条 area 退役处方在 objectstack-ai#4722 之后改口径 —— 项级闸门在两棵树都由服务端剥离 (…