越界发现,来自 objectstack#6936 的开发会话(objectui PR objectstack-ai/objectui#3937)。不在该 PR 范围内(#6936 的裁决只覆盖「解析不到的路径 → fail-open + 告警」),单独立单交 PM 分诊;未认领。
事实
packages/app-shell/src/views/metadata-admin/predicate.ts 的 == / != 分支左侧走 resolveValue(解析路径),右侧走 parseLiteral。parseLiteral 对「既不是引号串、也不是数字/布尔/null/数组」的输入原样返回该字符串(该函数末尾 return s;)。于是右侧写路径时,比较的是路径的字面文本,不是它的值。
实测读数(objectui worktree,origin/main @ 230ffd8 + PR #3937 分支;临时 vitest 探针,已删):
ctx = { data: { a: 'x', b: 'x' } } // 两侧值相等
data.a == data.b -> false // 期望 true
data.a != data.b -> true // 期望 false
ctx = { data: { a: 'x', b: 'y' } } // 两侧值不等
data.a == data.b -> false // 恰好"对",但理由是错的
data.a == 'x' -> true // 字面量对照组,正常
即 data.a == data.b恒假、data.a != data.b恒真,与两侧实际值无关:'x' === 'data.b'。
为什么是 observation-class(建议 finding,未打 pm:queue)
今天没有生产者踩到:安装版 @objectstack/spec 17.0.0-rc.5 里 metadata-admin 会渲染的四张表单(objectForm / pageForm / viewForm / actionForm)的谓词全部是 path == 字面量 / path in [字面量…] 形状,右侧无路径。文件头也明确写了它只支持一个子集("Supported subset (covers everything used in spec *.form.ts today)"),所以严格说这是已声明的子集边界,不是违约。
但它与 #6936 刚修掉的那条同族、且不被#6936 的新告警覆盖:告警挂在 resolveValue 的根标识符检查上,而右侧根本不经过 resolveValue。所以一旦将来 spec 下发一条 data.a == data.b 形状的谓词,症状仍然是静默的错误结论(字段该显示时不显示),控制台一片安静 —— 正是 #6936 花一整张卡换掉的那种不可诊断形状。严重度按 filing-time 判断不可靠,交 PM 分诊定级。
可能的方向(不在此单里做决定)
倾向 B + D(渲染器只把边界说清,语义修正交给 C/D,避免在消费端加宽容),但这是求值语义取舍,应由维护者定。
查重说明
搜过 open issues:evaluatePredicate(仅命中 #6936 本身)、parseLiteral predicate.ts 0 命中、metadata-admin predicate right-hand identifier 0 命中、谓词 求值器 字面量 仅命中 PM 登记表 #4604、objectui 仓 predicate literal right side 0 命中。若有同小时孪生单,按惯例 race-close 本单。
越界发现,来自 objectstack#6936 的开发会话(objectui PR objectstack-ai/objectui#3937)。不在该 PR 范围内(#6936 的裁决只覆盖「解析不到的路径 → fail-open + 告警」),单独立单交 PM 分诊;未认领。
事实
packages/app-shell/src/views/metadata-admin/predicate.ts的==/!=分支左侧走resolveValue(解析路径),右侧走parseLiteral。parseLiteral对「既不是引号串、也不是数字/布尔/null/数组」的输入原样返回该字符串(该函数末尾return s;)。于是右侧写路径时,比较的是路径的字面文本,不是它的值。实测读数(objectui worktree,
origin/main@230ffd8+ PR #3937 分支;临时 vitest 探针,已删):即
data.a == data.b恒假、data.a != data.b恒真,与两侧实际值无关:'x' === 'data.b'。为什么是 observation-class(建议
finding,未打pm:queue)今天没有生产者踩到:安装版
@objectstack/spec17.0.0-rc.5 里 metadata-admin 会渲染的四张表单(objectForm/pageForm/viewForm/actionForm)的谓词全部是path == 字面量/path in [字面量…]形状,右侧无路径。文件头也明确写了它只支持一个子集("Supported subset (covers everything used in spec*.form.tstoday)"),所以严格说这是已声明的子集边界,不是违约。但它与 #6936 刚修掉的那条同族、且不被#6936 的新告警覆盖:告警挂在
resolveValue的根标识符检查上,而右侧根本不经过resolveValue。所以一旦将来 spec 下发一条data.a == data.b形状的谓词,症状仍然是静默的错误结论(字段该显示时不显示),控制台一片安静 —— 正是 #6936 花一整张卡换掉的那种不可诊断形状。严重度按 filing-time 判断不可靠,交 PM 分诊定级。可能的方向(不在此单里做决定)
parseLiteral认不出的裸标识符改为按路径解析,解析不到则复用 objectui: metadata-admin 谓词求值器对「无法解析的路径」静默判假(fail-CLOSED),与文件自述的 fail-open 承诺相反 #6936 的 fail-open + 告警。风险:data.type == text这种「本意是字符串却漏了引号」的写法从"恰好能用"变成 fail-open 判真。parseLiteral走到末尾那条return s且输入长得像路径(含.或匹配标识符文法)时发 dev 告警,点名「右侧被当作字符串字面量」。语义零变化,把子集边界变成可发现的事实。@objectstack/formula的临时替身(ROADMAP M9),换成真 CEL 求值器后本条自动消失。倾向 B + D(渲染器只把边界说清,语义修正交给 C/D,避免在消费端加宽容),但这是求值语义取舍,应由维护者定。
查重说明
搜过 open issues:
evaluatePredicate(仅命中 #6936 本身)、parseLiteral predicate.ts0 命中、metadata-admin predicate right-hand identifier0 命中、谓词 求值器 字面量仅命中 PM 登记表 #4604、objectui 仓predicate literal right side0 命中。若有同小时孪生单,按惯例 race-close 本单。