Skip to content

[runtime] action body 的 ctx.session 仍在生产 roles(值是 ec.positions)—— 自称「mirroring hook ctx.session」,而 hook 侧该键已按 ADR-0049 退役 #5613

Description

@os-zhuang

事实

packages/runtime/src/action-execution.ts 的 buildActionSession()(第 689-695 行)构造 action body 的 ctx.session:

return {
    ...(ec.userId != null ? { userId: String(ec.userId) } : {}),
    ...(ec.tenantId != null ? { organizationId: String(ec.tenantId) } : {}),
    ...(Array.isArray(ec.positions) && ec.positions.length ? { roles: ec.positions } : {}),
};

它的文档注释原话是:"Build the action-body ctx.session from the request ExecutionContext, mirroring the hook ctx.session shape (#3280) so an action author reads the caller's active org under the SAME blessed name as a hook author."

调用点两处:packages/runtime/src/domains/actions.ts:296 与 packages/runtime/src/action-execution.ts:920。

三个问题叠在一起

  1. 它把 ADR-0090 D3 明令禁止的拼法重新引入了。 值取自 ec.positions —— ExecutionContext 已经在 ADR-0090 D3 把 roles 改名为 positions(packages/spec/src/kernel/execution-context.zod.ts:118,注释原话 "Formerly roles"),这里等于在边界上又把 positions 翻译回 roles 交给作者。ADR-0090 D3 禁的正是这个拼法;plugin-approvals 的 admin 豁免读 session.roles,而 ObjectQL 的 buildSession() 从不填充它 —— 记录锁/delegation 守卫的 admin 覆盖在真实引擎路径上永不生效 #4839 删掉 plugin-approvals 两处 roles.includes('admin') 时,理由也正是「不要第二套权限方言」。

  2. 「mirroring hook ctx.session」这句注释现在是错的,而且是危险方向的错。 [spec] 退役 HookContext session.roles —— #4839 双删后零消费方零生产方(ADR-0049) #5050 已按 ADR-0049 把 HookContext.session.roles 退役(墓碑 + 语义迁移)。所以现在两张面对同一个键名给出两种现实:hook 侧 —— 键已退役、写它会 tsc 报错 + parse 拒收;action 侧 —— 键还在,而且真的有值。同一个平台里同名同位的字段,一个作者在 hook 里读到 undefined(以前)/ 报错(现在),在 action 里读到一串 position 名。

  3. 没有任何 schema 声明 action ctx。 actionContext 是裸 any(两处调用点都是 const actionContext: any = {...}),沙箱侧 ScriptContext.session?: unknown(packages/runtime/src/sandbox/script-runner.ts:71)。所以这个键既没有契约、没有文档表、也没有闸门 —— 它只存在于运行时对象里,是 declared-nowhere / produced-anyway,连 liveness 台账都够不着它。

需要裁定(不要直接猜)

三条路,选哪条影响 action body 的公开契约:

  • A. 改名为 positions,值不变。 与 ExecutionContext / sharing service / ADR-0090 D3 词汇统一,一处方言消失。代价:breaking —— 现存 action body 里 ctx.session.roles 的读会静默变 undefined(裸 any,没有任何东西会报错),所以必须配 ADR-0087 语义迁移 + changeset;而且因为没有 schema,连墓碑都无处可挂,处方只能落在 changeset 和文档上。
  • B. 直接删。 如果结论是「action body 本就不该拿到任职信息、要判权限就走 security service」,那就删掉这条 spread。同样 breaking、同样静默。
  • C. 先给 action ctx 立 schema(声明 = 强制),再在其上做 A 或 B。 最贵,但这是唯一能让下一次同类漂移被闸门看见的路 —— 现状之所以能长这么久,正是因为 action ctx 完全在契约之外。

我倾向 C 的骨架 + A 的语义(先声明 action 上下文契约,同时把键正名为 positions),理由是两条轴都指向它:长期看,一个每天被客户 action body 读、却没有任何 schema 的运行时上下文,就是下一个 #5050 的温床;而「让 AI 写的元数据/代码难写错」这条更直接 —— 现在一个模型作者在 hook 里被硬拒、在 action 里被放行,它学到的是「roles 有时候能用」,这正是最坏的一课。但这是公开契约 + 安全词汇的双重决定,按 AGENTS.md Prime Directive #12 / #13 应由维护者裁定,故只登记不实现。

与其他单的关系

按 Prime Directive #10 登记,不在 #5050 的 PR 内修。

Blocked-by: #5779

Activity

  1. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    ContributorAuthor

    分诊:needs-user-decision + domain:cli(预挂)。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    维护者裁定(2026-08-06,经 spec 车道 PM session_018fxLGQdatPbBUvCgiVxg6D 誊写):契约先行(C 骨架 + A 语义)——先给 action body 的 ctx.session 立 schema(按现状声明,裸 any 面是本类漂移的根因),再在有类型面的前提下做 roles → positions 更名(带弃用窗口 + ADR-0087 语义迁移)。

    执行拆分(contract-first):

    • 第一阶段(spec 车道):action ctx.session 契约 schema,按现状声明(含 roles 现状键,describe 标注 deprecated → positions)——另立单派发,见下方关联。
    • 第二阶段(本单,cli 车道):Blocked-by: 第一阶段;schema 落地后做更名 + 弃用窗口 + 迁移处方(changeset/文档),buildActionSession 注释同步修正。

    摘 needs-user-decision 转 pm:blocked 等第一阶段。


    Generated by Claude Code

  3. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    解锁通知(spec 车道 PM,session_018fxLGQdatPbBUvCgiVxg6D,2026-08-06):第一阶段 #5697 已落地(PR #5721,02:4xZ 合并)——action ctx.session 契约已按现状声明(ActionSessionSchema @ packages/spec/src/ui/action-params.zod.ts,roles 键已标 deprecated 并在 .describe() 里写明值为 ADR-0090 D3 positions)。第二阶段(更名 + 弃用窗口 + ADR-0087 语义迁移 + buildActionSession() 两句错注释修正)可依的类型面已就位:

    • 承重翻转点已预埋:packages/runtime/src/action-session-shape-contract.test.ts 中 expect(Object.keys(built!).sort()).toEqual(['organizationId', 'roles', 'userId']) 即第二阶段要翻的断言,文件内已注明。
    • ScriptContext.session 维持 unknown 的理由与代价记录在 sandbox/script-runner.ts 注释里,收窄属第二阶段下游自然工作,未重复立单。

    标签 pm:blocked → pm:queue,归 cli 车道自扫排程。


    Generated by Claude Code

  4. baozhoutao commented on Aug 6, 2026

    @baozhoutao
    Contributor

    第二阶段再拆分(spec 半边转座)(cli 车道 PM,session_01DWUR56YsttL5sTF72Q75TQ,2026-08-06 05:3xZ):派发前实读 ActionSessionSchema 发现其 roles docstring 自带约定——「do NOT add a positions key here ahead of it,The rename is #5613 phase 2」——即第二阶段必然触碰 packages/spec(补 positions 键、roles 弃用对、ADR-0087 语义迁移条目、生成物重生)。按「shared contract surfaces have one owner」,spec 半边已立 #5779 转 spec 座位队列(contract-first,spec 先行);本单收缩为 runtime 半边(buildActionSession() 双发改造 + 注释修正 + 翻 action-session-shape-contract.test.ts 键集断言 + changeset major + 文档),正文已补 Blocked-by: #5779,挂 pm:blocked,#5779 落地后即派。


    Generated by Claude Code

  5. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    前置解除(spec 车道 PM,session_018fxLGQdatPbBUvCgiVxg6D,2026-08-06):Blocked-by: #5779 已随 PR #5849 MERGED 解除,pm:blocked → pm:queue,归 cli 车道队列自扫。

    runtime 半边可依的契约面(全部已上主干):ActionSessionSchema.positions 权威键 + roles 弃用别名对(ui/action-params.zod.ts)、ADR-0087 语义迁移条目 action-session-roles-to-positions(step17)。半边工序清单照 #5779 PR 正文「后续」节:buildActionSession() 双发同值、两句错注释修正、翻转 packages/runtime/src/action-session-shape-contract.test.ts 的键集断言(锚点未动,失败信息即指引)、major changeset、文档。窗口期读法(读 positions 回落 roles,回落随别名过期)已写进 schema JSDoc——runtime 半边落地越快,该临时回落固化风险越小。


    Generated by Claude Code

  6. baozhoutao commented on Aug 6, 2026

    @baozhoutao
    Contributor

    解锁(cli 车道 PM,session_01DWUR56YsttL5sTF72Q75TQ):Blocked-by: #5779 已解除——spec 半边 PR #5849 已合入 origin/main(d4e080937,ActionSessionSchema 已有 positions 权威键 + roles 弃用别名对)。摘 pm:blocked 回 pm:queue。派发时点:等 #5563(独占窗口,占 runtime 包)落地后,runtime 半边即派——双发改造 + 注释修正 + 翻 action-session-shape-contract.test.ts 键集断言(预埋的翻转点)+ changeset major + 文档。


    Generated by Claude Code

  7. self-assigned this
    on Aug 6, 2026
  8. baozhoutao commented on Aug 6, 2026

    @baozhoutao
    Contributor

    认领:PM 循环第 7 轮(cli 车道)
    会话:session_01DWUR56YsttL5sTF72Q75TQ
    分支:claude/issue-5613-action-session-positions-rename
    Worktree:objectstack-issue-5613
    域:domain:cli(第二阶段 runtime 半边)
    文件面:packages/runtime/src/action-execution.ts(buildActionSession() 双发改造 + 两句错注释修正)+ packages/runtime/src/action-session-shape-contract.test.ts(预埋键集断言翻转)+(如需)sandbox/script-runner.ts 的 ScriptContext.session 收窄 + changeset(major)+ 文档;⛔ 不动 packages/spec(spec 半边 #5779/PR #5849 已合)

    执行依据:维护者裁「C 骨架 + A 语义」;spec 侧已就位(ActionSessionSchema 含 positions 权威键 + roles 弃用别名对,弃用窗口 = runtime 双发同值)。churn:runtime 近日被 #5774/#5895/#5951 多轮动过(均不触 action-execution.ts,以最新 origin/main 为准)。


    Generated by Claude Code

  9. baozhoutao commented on Aug 6, 2026

    @baozhoutao
    Contributor

    验收:ACCEPT(第二阶段 runtime 半边,三阶段接力收官)(cli 车道 PM,session_01DWUR56YsttL5sTF72Q75TQ,2026-08-06 15:0xZ)→ PR #5991

    转 ready + 挂 auto-merge,两读数跟到 MERGED——落地即 cli 车道队列见底。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions