packages/spec/scripts/check-react-blocks-conformance.ts 的文件头声称(原文大写强调):
Spec ↔ frontend conformance report (ADR-0081 follow-up). Confirms the objectui components ACTUALLY implement the props the spec protocol declares for each curated react block. The spec is the protocol; the frontend must conform.
它不做这件事。 它比对的是两份声明:
| 左 |
右 |
spec zod schema 的 props(specProps() 走 z.toJSONSchema) |
注册表配置声明的 inputs(manifestInputs()) |
右边那份来自 objectui scripts/dump-public-manifest.mjs → manifestFromConfigs(getPublicConfigs()),而 manifestFromConfigs(packages/sdui-parser/src/index.ts)的实现是:
inputs: (c.inputs ?? []).map((i) => ({ name: i.name, type: …, required: i.required, … }))
——直接读注册表配置的 c.inputs。纯声明,与渲染器读不读毫无关系。
已证实的后果:#4413 全程绿灯
#4413 里四个 block 的 objectName/recordId 没有任何渲染器读,页面渲染成空。而合并前(ebb209c 之前)的 packages/spec/react-conformance.baseline.json 长这样:
"RecordDetails": { "frontendOnly": [], "missing": false },
"RecordHighlights": { "frontendOnly": [], "missing": false },
"RecordRelatedList": { "frontendOnly": [], "missing": false },
"RecordPath": { "frontendOnly": [], "missing": false }
四个完全不工作的块,门禁报"零分歧"。 因为两边都老老实实声明了 objectName——两份声明各自都不算撒谎,谎言在于渲染器两份都没实现,而这道门禁的视野里根本没有渲染器。
#4413 是靠人肉读 objectui 渲染器发现的,不是靠它。
为什么这比任何单个 block 重要
这是 Prime Directive #10(declared ≠ enforced)落在门禁自己身上的实例,和 #1475「spec 声明 9 种校验规则、执行器只认 3 种」是同一形状,只不过这次撒谎的是那个本该抓撒谎的东西。
一道报绿的假门禁比没有门禁更危险:没有门禁时人会去人肉核对;有一道自称"ACTUALLY implement"的绿灯时,人不会。#4413 存续期间没人怀疑过这四个块,这就是代价。
公平地说,它并非无用
它能看见的是真的,别一并推翻:
所以问题不是"门禁没用",是它的名字和文件头承诺了一个它给不了的保证,而团队按那个承诺信任了它。
次要发现(一并记录)
- 它在 console 构建里是 warn-only:
scripts/gen-sdui-manifest.sh:71-78 调用时没传 --strict,分歧只打印 ⚠。注释也写明了"Warn-only here — run check:react-conformance --strict to gate"。所以即便它看得见的那部分,也没有真正 gate。
- 只在 console 构建时跑(manifest 只在那时存在),不是 PR 门禁——这是脚本自己写明的成本取舍,本身合理,但和上一条叠加后,"分歧被记录"和"分歧被拦住"之间的距离比读文件头感觉到的更远。
候选方向(不预设结论,检测手段需要设计)
(a) 先把话说回来——本仓库内即可做,最便宜。 改文件头与报告用词,把"ACTUALLY implement"降级为它真正做的事(声明一致性 / declaration parity),并写明它看不见"声明了但不读"这一类。不解决检测问题,但立刻消除误信任——按 #10 的处置顺序(fix it / trim it / file it),这是"trim the claim"。
(b) 行为式冒烟测试——我认为最有希望。 #4413 的症状是渲染器吐出 designer placeholder(record:details — bind a record to preview)。一个"把每个 public block 按其声明的必需绑定挂载在裸 SchemaRendererProvider 下、断言输出不是 placeholder / 不为空"的测试,四个块会全部亮红。它直接命中这一类,不需要静态分析,而且天然属于 objectui 侧。
(c) 让 manifest 携带使用证据。 扩展 objectui 的 manifest,给每个 input 标注"渲染器是否消费"(对渲染器源码做 AST pass,或运行时探针)。能复用现有比对框架,但是启发式——props 可能经 spread / 转发 / helper 读取,假阴性假阳性都要评估。
(d) 只对 kind:'binding' 收紧。 一个不被读的绑定 prop 永远是 bug(块没连上数据),而一个不被读的装饰 prop 可能只是冗余。若检测手段有假阳性成本,先只在 binding 上开火,信噪比最好。
(a) 与 (b)/(c)/(d) 不互斥:(a) 现在就能做且必须做(门禁不该继续撒谎),其余按检测手段的设计结论再选。
参考
/cc objectstack-ai/objectui((b)/(c) 的实现侧)
packages/spec/scripts/check-react-blocks-conformance.ts的文件头声称(原文大写强调):它不做这件事。 它比对的是两份声明:
specProps()走z.toJSONSchema)manifestInputs())右边那份来自 objectui
scripts/dump-public-manifest.mjs→manifestFromConfigs(getPublicConfigs()),而manifestFromConfigs(packages/sdui-parser/src/index.ts)的实现是:——直接读注册表配置的
c.inputs。纯声明,与渲染器读不读毫无关系。已证实的后果:#4413 全程绿灯
#4413 里四个 block 的
objectName/recordId没有任何渲染器读,页面渲染成空。而合并前(ebb209c之前)的packages/spec/react-conformance.baseline.json长这样:四个完全不工作的块,门禁报"零分歧"。 因为两边都老老实实声明了
objectName——两份声明各自都不算撒谎,谎言在于渲染器两份都没实现,而这道门禁的视野里根本没有渲染器。#4413 是靠人肉读 objectui 渲染器发现的,不是靠它。
为什么这比任何单个 block 重要
这是 Prime Directive #10(declared ≠ enforced)落在门禁自己身上的实例,和 #1475「spec 声明 9 种校验规则、执行器只认 3 种」是同一形状,只不过这次撒谎的是那个本该抓撒谎的东西。
一道报绿的假门禁比没有门禁更危险:没有门禁时人会去人肉核对;有一道自称"ACTUALLY implement"的绿灯时,人不会。#4413 存续期间没人怀疑过这四个块,这就是代价。
公平地说,它并非无用
它能看见的是真的,别一并推翻:
spec-only:spec 声明了、注册表没声明 → 前端没实现协议。真信号。missing:manifest 里根本没有这个组件(没注册 / 非 public)。真信号。所以问题不是"门禁没用",是它的名字和文件头承诺了一个它给不了的保证,而团队按那个承诺信任了它。
次要发现(一并记录)
scripts/gen-sdui-manifest.sh:71-78调用时没传--strict,分歧只打印⚠。注释也写明了"Warn-only here — run check:react-conformance --strict to gate"。所以即便它看得见的那部分,也没有真正 gate。候选方向(不预设结论,检测手段需要设计)
(a) 先把话说回来——本仓库内即可做,最便宜。 改文件头与报告用词,把"ACTUALLY implement"降级为它真正做的事(声明一致性 / declaration parity),并写明它看不见"声明了但不读"这一类。不解决检测问题,但立刻消除误信任——按 #10 的处置顺序(fix it / trim it / file it),这是"trim the claim"。
(b) 行为式冒烟测试——我认为最有希望。 #4413 的症状是渲染器吐出 designer placeholder(
record:details — bind a record to preview)。一个"把每个 public block 按其声明的必需绑定挂载在裸SchemaRendererProvider下、断言输出不是 placeholder / 不为空"的测试,四个块会全部亮红。它直接命中这一类,不需要静态分析,而且天然属于 objectui 侧。(c) 让 manifest 携带使用证据。 扩展 objectui 的 manifest,给每个 input 标注"渲染器是否消费"(对渲染器源码做 AST pass,或运行时探针)。能复用现有比对框架,但是启发式——props 可能经 spread / 转发 / helper 读取,假阴性假阳性都要评估。
(d) 只对
kind:'binding'收紧。 一个不被读的绑定 prop 永远是 bug(块没连上数据),而一个不被读的装饰 prop 可能只是冗余。若检测手段有假阳性成本,先只在 binding 上开火,信噪比最好。(a) 与 (b)/(c)/(d) 不互斥:(a) 现在就能做且必须做(门禁不该继续撒谎),其余按检测手段的设计结论再选。
参考
packages/spec/scripts/check-react-blocks-conformance.ts、packages/spec/react-conformance.baseline.json、scripts/gen-sdui-manifest.sha8ad6c0:scripts/dump-public-manifest.mjs、packages/sdui-parser/src/index.ts的manifestFromConfigs/cc
objectstack-ai/objectui((b)/(c) 的实现侧)