objectui#3275 逐条清了 AgentPreview / SkillPreview / AppPreview / DatasourcePreview 里的宽容消费者,但 ValidationPreview.tsx 不在那张表里。在做 objectui#3276(修 validation 样例)时读到它,里面有同型的问题,单独记这里。
1. ?? d.expression —— 给一个从来不存在的键做别名回退
packages/app-shell/src/views/metadata-admin/previews/ValidationPreview.tsx,TypeBody() 的 script / conditional 分支(约 176 行),Condition 区块渲染的值是:
celText(d.condition) ?? celText(d.expression)
(原文是 JSX:一个 Section title="Condition" 里包着 CelBlock value={上面这个表达式}。这里只贴表达式 —— GitHub 的 body sanitizer 会把 < 开头的标签整行吃掉。)
expression不是任何一支 validation 分支上的键 —— script / cross_field 用 condition,conditional 用 when + then。它不是被退役的键(那样至少曾经合法过),是从来就没有过。
这个回退不是无害的:#3276 之前,validation 样例同时写了 condition: 'amount <= 0' 和 expression: 'amount > 0',预览照样画得出来,于是没人发现 expression 是假的。#3276 把样例里的 expression 删了之后,这条回退成了死代码,但仍然在向作者承诺「写 expression 也行」—— 而它 parse 完就被剥掉,发布时静默失效。这正是 AGENTS.md #0.1 说的那种把错误约定固化成第二契约的 ??。
2. case 'unique' —— spec 17 没有这个 validation 类型
同文件里有一整个 unique 分支(渲染 fields 芯片 + celText(d.scope) ?? celText(d.where) 的 Scope 区块)。而 ValidationRuleSchema 的判别联合只有六支:script / state_machine / format / cross_field / json_schema / conditional。
unique 不只是「没了」,是被明确裁掉的 —— validation.zod.ts 顶部 "Deliberately NOT validation rules" 一节写着:
Uniqueness → a unique index (ObjectSchema.indexes, { fields, unique: true } …). A SELECT-then-INSERT "rule" is inherently racy (TOCTOU); a DB unique constraint is not.
所以预览里画着一个作者永远存不下去的规则类型,而且是个已经有正确替代品的类型。scope ?? where 两个键也都不存在。
3. 顺带:d.object / d.field 的读取
建议
按 #3275 / #3258 的做法:
- 删掉
?? celText(d.expression),只读 condition(conditional 分支应改读 when,并考虑渲染嵌套的 then); - 删掉整个
case 'unique' 分支;如果想给作者指路,替换成一句「唯一性用 ObjectSchema.indexes 的 unique: true」的提示,而不是继续画那个界面; d.object 芯片:确认没有别的调用方会传 object-scoped 的草稿之后删掉;- 补上缺的分支 —— 目前
cross_field(有 condition + fields)似乎没有专门渲染,而它恰恰是「把错误指到某个字段」的正解。
相关
⚠️ 未指派 —— 由 #3276 顺带发现并记录(Prime Directive #10),不在那个 PR 里修:scope fence 是 apps/console,本单全在 packages/app-shell(且与 #3275 同目录,建议合并处理或等它落地后再动)。
objectui#3275 逐条清了
AgentPreview/SkillPreview/AppPreview/DatasourcePreview里的宽容消费者,但ValidationPreview.tsx不在那张表里。在做 objectui#3276(修validation样例)时读到它,里面有同型的问题,单独记这里。1.
?? d.expression—— 给一个从来不存在的键做别名回退packages/app-shell/src/views/metadata-admin/previews/ValidationPreview.tsx,TypeBody()的script/conditional分支(约 176 行),Condition 区块渲染的值是:(原文是 JSX:一个
Section title="Condition"里包着CelBlock value={上面这个表达式}。这里只贴表达式 —— GitHub 的 body sanitizer 会把<开头的标签整行吃掉。)expression不是任何一支 validation 分支上的键 ——script/cross_field用condition,conditional用when+then。它不是被退役的键(那样至少曾经合法过),是从来就没有过。这个回退不是无害的:#3276 之前,
validation样例同时写了condition: 'amount <= 0'和expression: 'amount > 0',预览照样画得出来,于是没人发现expression是假的。#3276 把样例里的expression删了之后,这条回退成了死代码,但仍然在向作者承诺「写expression也行」—— 而它 parse 完就被剥掉,发布时静默失效。这正是 AGENTS.md #0.1 说的那种把错误约定固化成第二契约的??。2.
case 'unique'—— spec 17 没有这个 validation 类型同文件里有一整个
unique分支(渲染fields芯片 +celText(d.scope) ?? celText(d.where)的 Scope 区块)。而ValidationRuleSchema的判别联合只有六支:script/state_machine/format/cross_field/json_schema/conditional。unique不只是「没了」,是被明确裁掉的 ——validation.zod.ts顶部 "Deliberately NOT validation rules" 一节写着:所以预览里画着一个作者永远存不下去的规则类型,而且是个已经有正确替代品的类型。
scope ?? where两个键也都不存在。3. 顺带:
d.object/d.field的读取const object = d.object as string | undefined;(约 85 行)→ 渲染object: xxx芯片。校验规则挂在宿主对象的validations[]上,自身不带object(consolevalidation预览样例的condition语义写反了(spec 里 condition 为 TRUE 表示校验失败),另带两个会被静默剥掉的键 #3276 已把样例里这个键删掉),所以这个芯片对合规草稿永远不显示;TypeBody里非 script 分支读的d.field是合法的(state_machine/format/json_schema三支确实有field),这条没问题,别顺手删了。建议
按 #3275 / #3258 的做法:
?? celText(d.expression),只读condition(conditional分支应改读when,并考虑渲染嵌套的then);case 'unique'分支;如果想给作者指路,替换成一句「唯一性用ObjectSchema.indexes的unique: true」的提示,而不是继续画那个界面;d.object芯片:确认没有别的调用方会传 object-scoped 的草稿之后删掉;cross_field(有condition+fields)似乎没有专门渲染,而它恰恰是「把错误指到某个字段」的正解。相关
expression/object/field,修反了的condition)ToolPreview的先例)apps/console,本单全在packages/app-shell(且与 #3275 同目录,建议合并处理或等它落地后再动)。