现象
packages/spec/src/ui/view.zod.ts 的字段级与 section 级 visibleWhen 文档(origin/main):
:1410-1412(JSDoc)与 :1414(describe):「Root: record+current_user (runtime forms) or data (metadata forms)」
:1505-1508:FormSection 级同样宣称
但 字段级条件规则的实际求值面没有任何一处绑定 current_user:
- objectui 侧:
resolveFieldRuleState 的三个生产调用点(packages/components/src/renderers/form/form.tsx 渲染门与 error-clearing effect、packages/plugin-form/src/WizardForm.tsx 必填门)都不传 scope,evalFieldPredicate 只绑 record / previous /(经 extra 的)parent。objectui 的授权 autocomplete 也是这么钉的:packages/app-shell/src/views/metadata-admin/celAuthoring.ts 的 FIELD_RULE_ROOTS = ['record', 'previous', 'parent'],注释明说 "nothing else (no current_user)"(objectui#1582 的决定);
- 服务端:
packages/objectql/src/validation/rule-validator.ts 的 EvaluateRulesOptions.currentUser 按其 JSDoc 只供 per-option visibleWhen(objectui#2284,ADR-0068);readonlyWhen 求值(isReadonlyWhenLocked)绑 record/merged + parent,不含 current_user。
per-option visibleWhen(选项级)确实绑 current_user——文档对「选项级」为真,对「字段级/section 级」为假。
后果
照 describe 写 visibleWhen: "current_user.positions.exists(p, p == 'admin')" 的字段级谓词,引用未绑定根 → fault → fail-open(字段恒可见)。这正是 #5149 的「文档诱导写出永不生效谓词」类别(Repro 1 是裸标识符,这里是文档亲自点名的根)。objectui PR objectstack-ai/objectui#3541(#5149 诉求 2)落地后该 fault 会以每谓词一条 console.warn 显形(undeclared reference to current_user 一类),不再静默,但谓词本身依旧不工作。
两个修法方向(留给分诊)
- 文档收窄:describe 与 JSDoc 把字段级/section 级的 runtime 根改为
record(+previous/parent),current_user 只保留在 per-option visibleWhen 的文档上——与 objectui#1582 钉的授权面一致,改动最小;
- 实现补齐:让字段级规则求值面(客户端
resolveFieldRuleState 调用点传 host predicate scope;服务端 rule-validator 同步)真的绑 current_user——有真实业务拉力(按角色显隐字段)时才值得,且需两端同时落,否则客户端/服务端 verdict 漂移。
按仓规不自选方向,留 PM 分诊。发现于 #5149 诉求 4 验收(该验收本身成立:record./data. 绑定说明与示例齐全,本单只针对 current_user 这一半句的过度宣称)。
Refs: #5149、objectstack-ai/objectui#3541、objectui#1582、objectui#2284、ADR-0068
现象
packages/spec/src/ui/view.zod.ts的字段级与 section 级visibleWhen文档(origin/main)::1410-1412(JSDoc)与:1414(describe):「Root:record+current_user(runtime forms) ordata(metadata forms)」:1505-1508:FormSection 级同样宣称但 字段级条件规则的实际求值面没有任何一处绑定
current_user:resolveFieldRuleState的三个生产调用点(packages/components/src/renderers/form/form.tsx渲染门与 error-clearing effect、packages/plugin-form/src/WizardForm.tsx必填门)都不传 scope,evalFieldPredicate只绑record/previous/(经 extra 的)parent。objectui 的授权 autocomplete 也是这么钉的:packages/app-shell/src/views/metadata-admin/celAuthoring.ts的FIELD_RULE_ROOTS = ['record', 'previous', 'parent'],注释明说 "nothing else (nocurrent_user)"(objectui#1582 的决定);packages/objectql/src/validation/rule-validator.ts的EvaluateRulesOptions.currentUser按其 JSDoc 只供 per-optionvisibleWhen(objectui#2284,ADR-0068);readonlyWhen求值(isReadonlyWhenLocked)绑record/merged +parent,不含current_user。per-option
visibleWhen(选项级)确实绑current_user——文档对「选项级」为真,对「字段级/section 级」为假。后果
照 describe 写
visibleWhen: "current_user.positions.exists(p, p == 'admin')"的字段级谓词,引用未绑定根 → fault → fail-open(字段恒可见)。这正是 #5149 的「文档诱导写出永不生效谓词」类别(Repro 1 是裸标识符,这里是文档亲自点名的根)。objectui PR objectstack-ai/objectui#3541(#5149 诉求 2)落地后该 fault 会以每谓词一条console.warn显形(undeclared reference to current_user一类),不再静默,但谓词本身依旧不工作。两个修法方向(留给分诊)
record(+previous/parent),current_user只保留在 per-optionvisibleWhen的文档上——与 objectui#1582 钉的授权面一致,改动最小;resolveFieldRuleState调用点传 host predicate scope;服务端 rule-validator 同步)真的绑current_user——有真实业务拉力(按角色显隐字段)时才值得,且需两端同时落,否则客户端/服务端 verdict 漂移。按仓规不自选方向,留 PM 分诊。发现于 #5149 诉求 4 验收(该验收本身成立:
record./data.绑定说明与示例齐全,本单只针对current_user这一半句的过度宣称)。Refs: #5149、objectstack-ai/objectui#3541、objectui#1582、objectui#2284、ADR-0068