Skip to content

feat(runtime)!: 退役 ctx.user 的 roles 别名,positions 成为唯一拼法 (#6011) - #6048

Draft
qq9340100 wants to merge 1 commit into
mainfrom
claude/issue-6011-actor-user-roles-retire
Draft

feat(runtime)!: 退役 ctx.user 的 roles 别名,positions 成为唯一拼法 (#6011)#6048
qq9340100 wants to merge 1 commit into
mainfrom
claude/issue-6011-actor-user-roles-retire

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Fixes #6011

按维护者 2026-08-06 14:49Z 的就地裁决执行:方向 2「直接退役」—— 立即删除 ctx.user 上的 roles 别名,不设弃用窗口、不双发。

改了什么

ActorUser(action body 的 ctx.user / AI 路由处理器的 req.user)此前同时声明并发出两个键,值由同一次赋值产生、逐字相同:

  • 声明:packages/runtime/src/security/actor-user.tsroles: string[]
  • 构造:同文件 buildActorUser() 里的 roles: core.positions

两处一并删除,positions 成为该面唯一的位置拼法。原注释声称该别名 "kept for the REST/AI shapes" —— 这一说法在删除前被核实并证伪(见下)。

消费方核实(删除的硬前置)

一律以 origin/main(>= 739f496,即 #5991 合并后)为准做 git grep,不读工作树;零命中结果都用已知存在的邻近词 positions 做了反证,确认 grep 本身有效。

消费面 结果
本仓全仓 user.roles / req.user.roles(所有文件类型) 仅 4 处,全部在测试里,即本 PR 翻转的那几个钉子
ActorUser 的四个生产点 action-execution.ts / dispatcher-plugin.ts / domains/actions.ts / domains/ai.ts —— 构造的都是服务端 body / 路由处理器信封,不进入任何 HTTP 响应体
REST / AI 路由 未见任何处理器读 .roles
examples/(showcase / CRM 的 action body) 零命中
objectui(/home/user/objectui,origin/main) .roles 命中全部落在另外两个独立生产者上:better-auth 会话的 user.roles / user.role(AuthGuard / useIsWorkspaceAdmin),以及 /api/v1/auth/me/permissions 响应体(由 plugin-hono-server/src/current-user-endpoints.ts 自行构造)。没有一处消费 ActorUser
文档 / skills 没有任何手写文档教 ctx.user.roles;唯一相关的一处 (content/docs/permissions/permission-metadata.mdx:201) 恰恰在申明「不存在 current_user.roles

⚠️ cloud 仓在本会话不可达,因此它是未经核实的消费面。changeset 里的迁移处方(rolespositions,值不变)即为该面的处置说明。

钉子:翻转而非删除

三个文件里的断言都同批翻转并继续承载,既断言新语义的实质,又钉住方向:

  • action-ctx-user-shape.test.ts —— 原「aliases stay in lockstep」整条替换(它钉的正是被删的那条肢,留着会因「什么都没产生」而空绿):现在断言 positions 逐字承载调用者位置, 'roles' in ctx.user === false
  • http-dispatcher.test.ts —— 两处 user.roles 断言改为其反面(键不存在),而非删掉。
  • ai-request-user-capability-channel.test.ts —— user.roles 改读 user.positions(该用例的实质是「位置是与两条权限通道互不合并的第三条通道」,实质保留),并补键不存在断言。

断言用 'roles' in user 而不是 toBeUndefined():后者无法区分「键已删除」与「键还在、值为空」的半吊子退役。

反向验证(方向预先判定为「红」,结果一致):把删掉的 roles: core.positions 恢复回去后,7 条断言转红 —— 2 条键集断言(8 键 vs 7 键)、1 条 value-for-value toEqual、4 条 expected true to be false(新的键不存在钉子)。恢复后即刻回退。

⛔ 范围外(已刻意不动)

测试证据

pnpm --filter @objectstack/runtime typecheck   → 干净通过(tsc --noEmit,无输出)
pnpm --filter @objectstack/runtime test        → Test Files 102 passed (102)
                                                 Tests 1476 passed (1476)
pnpm check:role-word                           → OK (43 baselined, no new occurrences)
node scripts/check-nul-bytes.mjs               → OK (5779 files, no raw control bytes)
eslint(4 个改动文件)                          → exit 0

关于待定的 spec 半边(回答派发时的必答问题)

本改动使 spec 半边的 ADR-0087 台账条目更简单,并不使其变得不必要。

理由:台账条目要记录的「FROM → TO」事实已经在本 PR 里被确定并固定了 —— 退役已发生、迁移映射是纯改键(值不变)、消费面已扫清且证据在案、positions 唯一拼法已有钉子守住。因此 spec 座位写条目时不必再自行判定退役范围或复核消费方,只需把既成事实登记入册。它仍然必要:没有条目,这次退役在台账上不可见,与同族 session 侧已有的三条(data.hookContext.session.rolesui.actionSession.rolesCEL/formula: current_user.roles)不对称,而这种不对称正是本 issue 立单的原因。

需要提醒 spec 座位的一点:ctx.user至今没有 spec schema,只有 runtime 的 TS interface —— 所以该条目登记的是一个 spec 从未声明过的键的退役,这与 session 侧「schema 里有声明可改」的情形不同,条目的 surface 写法需要相应处理。


🤖 Generated with Claude Code

https://claude.ai/code/session_01Wbxm29qPKnLf44AbSxizqW


Generated by Claude Code

ActorUser 同时声明并发出 `positions` 与 `roles`,两者由同一次赋值产生、值
逐字相同。`roles` 是 ADR-0090 D3 保留并禁用的词,且从未有关闭日期 —— 与
#5613 给 ctx.session 装上迁移窗口的同族面相比,这一面既无 spec 契约、也无
ADR-0087 台账条目、也无移除路径。维护者 2026-08-06 就地裁决:立即退役,
不设弃用窗口、不双发。

消费方核实(删除的前置条件,因为旧注释声称该别名 "kept for the REST/AI
shapes"):全仓 + objectui 扫描未见任何活体读取 `ActorUser.roles` 的代码。
四个生产点(action-execution / dispatcher-plugin / domains.actions /
domains.ai)构造的都是服务端 body / 路由处理器信封,不进入任何响应体;
objectui 的 `.roles` 读取全部落在 better-auth 会话与
`/api/v1/auth/me/permissions` 两个独立生产者上。

钉子同批翻转而非删除:三处断言改为既断言新语义的实质(`positions` 逐字
承载),又钉住方向(`roles` 键不存在)。反向验证已做:恢复被删的构造分支
后 7 条断言转红,方向与预期一致。

⛔ 不含 ctx.session:该面按 #5613 保留其弃用窗口,双发不动。
⛔ 不含 packages/spec:ADR-0087 台账条目另行落地。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wbxm29qPKnLf44AbSxizqW
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 6, 2026 3:41pm

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/runtime.

21 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/api/client-sdk.mdx (via packages/runtime)
  • content/docs/api/index.mdx (via @objectstack/runtime)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/runtime)
  • content/docs/concepts/north-star.mdx (via packages/runtime)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime)
  • content/docs/kernel/cluster.mdx (via @objectstack/runtime)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime)
  • content/docs/plugins/packages.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime)
  • content/docs/releases/implementation-status.mdx (via @objectstack/runtime)
  • content/docs/releases/v17.mdx (via @objectstack/runtime)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

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

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants