Skip to content

字段级 *When 的未绑定根检查是一张 3 项黑名单,而真相是一张 3 项白名单 —— 其余 ~20 个 SCOPE_ROOTS 成员同样 fail-open 且全静默 #6713

Description

@os-project-manager

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

事实

字段级 visibleWhen / readonlyWhen / requiredWhen 实测只绑三个根,三处独立证据一致:

  • 服务端:rule-validator.ts:577(readonlyWhen)绑 { record, previous, extra: { parent } },:1403(requiredWhen)绑 { record, previous, ...parentScope };
  • 客户端:evalFieldPredicaterecord + previous + 调用方 scope,而 objectui 全部五个字段级调用点(form.tsx ×3、WizardForm.tsxGridField.tsx)传的 scope 只可能是 undefined{ parent: contextRecord };
  • 作者端:objectui 的 FIELD_RULE_ROOTS = ['record', 'previous', 'parent'](ObjectFieldInspector.tsx:127),注释明写 "nothing else"。

也就是说,真相是一张三项白名单

packages/lint/src/validate-expressions.tscheckFieldRuleUserRoot 是一张黑名单:#6584 里一项(current_user),#6711 之后三项(current_user / user / ctx)。@objectstack/formulaSCOPE_ROOTS 共约 26 个成员,减去白名单的三项与黑名单的三项,还剩约 20 个根在字段级同样未绑定、同样 fault、同样 fail-open —— 且全部静默:它们都在 SCOPE_ROOTS 里,所以裸引用检查从不报它们,而黑名单又不认它们。

具体名单(cel-engine.ts:54-79):inputoutputosvarsvariablesautomationcontextargsitemenvstepresulttriggereventpayloaddataparamsconfigsettingsfeaturescurrent

其中几个是高度可信的作者笔误,而不是理论可能性:

  • os.user.id —— ADR-0068 D1 认定的第四种用户拼写。fix(lint): 字段级 *When 的用户根拒绝覆盖 ADR-0068 的全部三种拼写 (#6585) #6711 收了三种,os 这一支没收(收了会连 os.env / os.org 一起判,那是另一次面级测量);
  • data.status == 'x' —— data元数据表单里同一个 visibleWhen 槽位的合法根(见 view.zod.ts:1440.describe():"Root: record … in runtime forms, or data in metadata forms"),两种表单同一个键、不同的根,作者极易串;
  • context / vars / trigger —— flow 谓词的根,从 flow 复制粘贴过来就是这几个。

后果

#6146 / #6585 同一条失败链,方向也一样:未绑定根 ⇒ fault ⇒ 可见性 fallback 为 true ⇒ 本想藏起来的字段对所有人恒可见,无任何构建期信号。差别只在于:#6585 是「三个等价拼写里挑错了一个」,本单是「挑了一个压根不属于这个面的根」。

现状与范围(实测)

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

  1. 黑名单翻成白名单 —— checkFieldRuleUserRoot 改为「字段级 *When 的根不在 {record, previous, parent} 内即拒」。与三处实测绑定、与 objectui 作者端白名单完全对齐,且未来 SCOPE_ROOTS 新增成员时自动覆盖(黑名单则每次都漏)。代价:文案需要按根分档 —— 现有处方是用户向的(移到选项级 / 权限集 FLS),对 data / vars 这类根答非所问,得给出通用处方(「改写成 record 谓词」)并保留用户根的专门处方;
  2. 只把 os 补进现有黑名单 —— 只补 ADR-0068 的第四种用户拼写,把 字段级 *When 的用户根拒绝只认 current_user —— ADR-0068 的两个别名 user / ctx.user 静默放行,写哪个拼写决定拿不拿得到诊断 #6585 的别名故事补完整,其余 ~20 个根继续静默。改动最小,但把同一类洞留在原地;
  3. 不动 —— 记录为已知边界。

个人倾向 1(理由:黑名单在这个面上结构性地追不上 SCOPE_ROOTS,而白名单的三项已被三处独立证据钉死),但文案分档是真实工作量,且 parent 那一项本身还有 #6457 的稀疏问题未了,请分诊定夺。

Refs: #6585#6584(PR)、#6711(PR)、#6146#6457、ADR-0068 D1、objectui#1582

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions