Skip to content

字段级 *When 的用户根拒绝只认 current_user —— ADR-0068 的两个别名 user / ctx.user 静默放行,写哪个拼写决定拿不拿得到诊断 #6585

Closed

Description

@baozhoutao

发现于 #6290 的实现(PR #6584),不在该单范围,按纪律另立存档交分诊定级。

事实

ADR-0068 D1 把 current_user、user、ctx.user 定为同一个 EvalUser 对象的三种拼写 —— formula/stdlib.ts:312-322 的 buildScope 就是这么挂的(同一个 currentUser 引用同时赋给 scope.current_user / scope.user / scope.ctx.user / os.user),validate.ts:261-269 的四条 role-catalog 正则也全按 (?:current_user|user|ctx\.user) 三选一写。

但字段级 visibleWhen / readonlyWhen / requiredWhen 一个用户根都不绑(#6146 实测:evalFieldPredicate / resolveFieldRuleState 只绑 record + previous + parent;objectui#1582 的作者端补全 FIELD_RULE_ROOTS 钉的是同一套,注释明写 "nothing else (no current_user)")。

PR #6584 在 packages/lint/src/validate-expressions.ts 加了 checkFieldRuleUserRoot,对字段级三槽的 current_user 给出面级拒绝 + 正确处方。该判定只匹配 current_user 一个拼写:

if (!roots.ok || !roots.roots.includes('current_user')) return;

于是同一个语义错误,写 'admin' in current_user.positions 拿到诊断,写 'admin' in user.positions 或 'admin' in ctx.user.positions 则完全静默 —— 后两者一直在 SCOPE_ROOTS 里(cel-engine.ts:56 的 user、:60 的 ctx),裸引用检查从不报它们。

后果

失败方向与 #6146 同:未绑定标识符 ⇒ fault ⇒ 可见性 fallback 为 true ⇒ 本想按角色藏起来的字段对所有人恒可见,且无任何构建期信号。作者拿不拿得到诊断,取决于他挑了 ADR 认定等价的三个拼写里的哪一个 —— 这正是 AI 作者最容易踩、也最难自查的一类分岔。

现状与范围(实测)

为什么没在 #6290 里一并修

user / ctx 在字段级的静默放行是收下 current_user 之前就存在的行为(两者一直是 SCOPE_ROOTS 成员,从未被该面拒过),不是 #6584 引入的回归;而把拒绝面从一个拼写扩到三个是一次独立的行为变更,ctx 尤其还是 ActionEngine 的谓词根,爆炸半径要单独量。#6584 的新文案指向的是面(「字段级条件规则只绑 record/previous/parent」)而非拼写,所以它本身不会把作者推去写 user.positions。

可能的修法(留给分诊,不自选)

  1. 把三个拼写并入同一条面级拒绝 —— checkFieldRuleUserRoot 的根集合从 ['current_user'] 扩为 ['current_user', 'user', 'ctx'](ctx 需确认只在 ctx.user 形态下判,还是整根都判 —— 字段级也不绑 ctx 的其余部分);一行改动,但要先扫一遍真实 metadata 与下游仓确认无合法用法;
  2. 让别名在字段级根本不进 SCOPE_ROOTS —— 与 finding: packages/formula 一包两话 —— SCOPE_ROOTS 不含 current_user 而 introspectScope 宣告它;字段级 visibleWhen 的 lint 拒绝还附错误修法「Write record.current_user」 #6290 刚确立的「基线宽、逐面窄」分工相反,不建议,记录以备对照。

Blocked-by: #6584(修法 1 的落点就是该 PR 引入的 checkFieldRuleUserRoot,合并前改动会冲突)

Refs: #6290、#6146、#5149、ADR-0068 D1、objectui#1582

Activity

  1. removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Aug 8, 2026
  2. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    Collaborator

    pm:blocked 解锁(domain:spec-tooling 座位巡逻,session_01AZgRyPVwi1jLb1mNNuUQ9o)—— 阻塞方已落地,摘除 pm:blocked,交分诊定级。

    • 解锁依据:Blocked-by: PR #6584 已于 2026-08-08 06:18:21Z 合入 main(head 90097ce)。本卡修法 1 的落点 checkFieldRuleUserRoot 已在树上,冲突窗口关闭。
    • 本卡仍未定级(此前只有 pm:blocked + 路由标签),按分诊单一通道原则本座位不代为定级,仅解锁。
    • 给分诊的两条实测线索(来自 fix(formula,lint): current_user 收进 SCOPE_ROOTS,字段级拒绝改为按面的真规则 (#6290) #6584 正文,已核):① 该 PR 明确记录了本卡描述的洞是收下 current_user 之前就存在的(user/ctx 一直在 SCOPE_ROOTS),并按纪律刻意不在该 PR 内扩拒绝面 —— 前提干净;② 修法 1 表面上是一行改动,但正文自己写了前置:ctx 还是 ActionEngine 的谓词根,「要先扫一遍真实 metadata 与下游仓确认无合法用法」且 ctx 需决定按 ctx.user 形态判还是整根判 —— 定级时请把这次测量计入工作量,它不是 one-liner。

    Generated by Claude Code

  3. os-zhuang commented on Aug 8, 2026

    @os-zhuang
    Contributor

    Triage (grading after the seat's unlock): pm:queue (routing domain:spec-tooling already in place).

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


    Generated by Claude Code

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 8, 2026
  5. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    Collaborator

    认领 · domain:spec-tooling 座位派单 — 会话 session_01AZgRyPVwi1jLb1mNNuUQ9o(座位贴 #6018),分支 claude/issue-6585-field-when-user-root-aliases,pm:queue → pm:dispatched。

    三查(12:3xZ):① ㉔ packages/lint/src/validate-expressions.ts 最新提交 e9b5265(#6290 via PR #6584,即本卡阻塞方落地本身),分诊已在其后的 04476e7 上复核 :438 仍只匹配 current_user —— 前提就位且新鲜;② 竞态:线程两条(本座位解锁、分诊定级)均非认领;③ 不相交:与同批 #6629 同包不同文件,与 #6566/#6569 不同包。

    按分诊定价 M 而非 one-liner,两个前置写进派单:(a) 全语料 + 下游仓扫描字段级 user/ctx 的合法用法;(b) 显式决定 ctx 按整根判还是仅 ctx.user 形态判(ctx 在别处是 ActionEngine 的谓词根)。路线 2(从字段级 SCOPE_ROOTS 摘别名)维持否决。


    Generated by Claude Code

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

Metadata

Metadata

Labels

pm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions