越界发现,来自 objectstack#6331 的开发会话(objectui PR objectstack-ai/objectui#3923)。不在该 PR 范围内,单独立单交 PM 分诊;未认领。
事实
packages/app-shell/src/views/metadata-admin/predicate.ts 的文件头明确承诺:
On any parse error → returns true (fail-open): better to show a field than to silently hide it.
evaluatePredicate 的 try/catch 确实对抛错兜成 true。但「标识符解析不到」不走抛错路径:resolveValue 从 ctx 根开始逐段下钻,取不到就返回 undefined,然后
path in ['a','b'] → ['a','b'].includes(undefined) → falsepath == 'x' → undefined === 'x' → false
于是一条引用了不存在路径的谓词把字段静默隐藏,与文件自述的方向正好相反。文档承诺 fail-open,实现是 fail-closed。
为什么现在才可观测
在 objectstack#6331 修好之前,metadata-admin 根本没读到过任何 spec 下发的谓词(五个站点只读已被 ADR-0089 归一化掉的 visibleOn),所以这条求值语义从来没有被执行到。#6331 的读取器修复让它第一次可达。
具体的踩法(objectui PR #3923 已用浏览器探针两向实测):谓词必须写成 data. 作用域才能对着草稿求值(objectstack#6254 修正了 object.form.ts 里 16 处裸拼法)。若后端仍在下发 #6254 之前的裸拼法 type in ['text',...],而前端已带 #6331 的读取器修复,则求值器把裸 type 在 { data: row } 作用域里解析成 undefined → 判假 → Studio 对象字段列表里那 16 个类型相关子字段(Min / Max / Precision / Scale / Max Length / Min Length / reference / deleteBehavior / expression / returnType / autonumberFormat / language …)全部消失。实测读数:
B1 objectForm fields(#6254 后的 data. 拼法)
row currency → Min, Max, Precision, Scale (正确)
row text → Max Length, Min Length (正确)
B2 objectForm fields(安装版 spec 17.0.0-rc.5 的裸拼法)
row currency → 16 条条件子字段一条都不出
row text → 16 条条件子字段一条都不出
也就是说这是一个版本错配窗口内的静默功能消失:v17 前后端同步升级时不会命中,前端先于后端升级时会命中,而症状是「配置项不见了」,用户无从判断是权限、是类型不支持、还是 bug。
为什么不在 #6331 的 PR 里顺手改
改动求值语义是有后果的取舍,不该由读取器修复夹带:
- A. 未解析路径 → 判真(与文件承诺一致):配置项恒显,与修复前的现状同向,坏谓词不再致命 —— 但真正想隐藏的字段在拼错时也会露出来。
- B. 未解析路径 → 判假(现状):拼错即静默隐藏,最难诊断。
- C. 未解析路径 → 判真 + 一条开发期
console.warn / 诊断项:既不静默,也不吞配置项。
倾向 C(与 objectstack#5149 fail-open 一族的处理方向一致,且把「谓词引用了不存在的路径」变成可发现的事实而不是不可见的行为),但这是 metadata 表单渲染语义,应由维护者定。真正的长期解法在生产端:谓词表达式应在发布期被校验(引用的路径必须存在于对应 schema),而不是让渲染器在运行期猜 —— 那属于另一个更大的口子,这里只记录读数。
关联
查重说明(如实记录局限)
按关键词 + 文件路径搜过 open issues:evaluatePredicate 0 命中、predicate.ts metadata-admin unresolved identifier hidden 0 命中;继续搜时 GitHub search API 触发本座位限流(API rate limit already exceeded),未能完成更宽的关键词面。#6331 的分诊评论此前对三仓 463 个 open issue 做过全量 REST 分页并列出邻居,其中没有本条。若 PM 发现同小时的孪生单,按惯例 race-close 本单。
越界发现,来自 objectstack#6331 的开发会话(objectui PR objectstack-ai/objectui#3923)。不在该 PR 范围内,单独立单交 PM 分诊;未认领。
事实
packages/app-shell/src/views/metadata-admin/predicate.ts的文件头明确承诺:evaluatePredicate的 try/catch 确实对抛错兜成true。但「标识符解析不到」不走抛错路径:resolveValue从 ctx 根开始逐段下钻,取不到就返回undefined,然后path in ['a','b']→['a','b'].includes(undefined)→ falsepath == 'x'→undefined === 'x'→ false于是一条引用了不存在路径的谓词把字段静默隐藏,与文件自述的方向正好相反。文档承诺 fail-open,实现是 fail-closed。
为什么现在才可观测
在 objectstack#6331 修好之前,metadata-admin 根本没读到过任何 spec 下发的谓词(五个站点只读已被 ADR-0089 归一化掉的
visibleOn),所以这条求值语义从来没有被执行到。#6331 的读取器修复让它第一次可达。具体的踩法(objectui PR #3923 已用浏览器探针两向实测):谓词必须写成
data.作用域才能对着草稿求值(objectstack#6254 修正了object.form.ts里 16 处裸拼法)。若后端仍在下发 #6254 之前的裸拼法type in ['text',...],而前端已带 #6331 的读取器修复,则求值器把裸type在{ data: row }作用域里解析成undefined→ 判假 → Studio 对象字段列表里那 16 个类型相关子字段(Min / Max / Precision / Scale / Max Length / Min Length / reference / deleteBehavior / expression / returnType / autonumberFormat / language …)全部消失。实测读数:也就是说这是一个版本错配窗口内的静默功能消失:v17 前后端同步升级时不会命中,前端先于后端升级时会命中,而症状是「配置项不见了」,用户无从判断是权限、是类型不支持、还是 bug。
为什么不在 #6331 的 PR 里顺手改
改动求值语义是有后果的取舍,不该由读取器修复夹带:
console.warn/ 诊断项:既不静默,也不吞配置项。倾向 C(与 objectstack#5149 fail-open 一族的处理方向一致,且把「谓词引用了不存在的路径」变成可发现的事实而不是不可见的行为),但这是 metadata 表单渲染语义,应由维护者定。真正的长期解法在生产端:谓词表达式应在发布期被校验(引用的路径必须存在于对应 schema),而不是让渲染器在运行期猜 —— 那属于另一个更大的口子,这里只记录读数。
关联
data.拼法;两边都落地后本条的踩法关闭。visibleWhen/visibleOn) fail OPEN and silently — a broken predicate is indistinguishable from no predicate #5149 是「谓词抛错 → 静默显示」,本条是「谓词路径解析不到 → 静默隐藏」,方向相反、代码路径不同(catch 分支 vsresolveValue返回undefined)。查重说明(如实记录局限)
按关键词 + 文件路径搜过 open issues:
evaluatePredicate0 命中、predicate.ts metadata-admin unresolved identifier hidden0 命中;继续搜时 GitHub search API 触发本座位限流(API rate limit already exceeded),未能完成更宽的关键词面。#6331 的分诊评论此前对三仓 463 个 open issue 做过全量 REST 分页并列出邻居,其中没有本条。若 PM 发现同小时的孪生单,按惯例 race-close 本单。