Skip to content

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

Description

@baozhoutao

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

事实

ADR-0068 D1 把 current_useruserctx.user 定为同一个 EvalUser 对象的三种拼写 —— formula/stdlib.ts:312-322buildScope 就是这么挂的(同一个 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 #6584packages/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:56user:60ctx),裸引用检查从不报它们。

后果

失败方向与 #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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions