在 #4876 的实测过程中发现,与该单的裁决无关,独立存在。
现象
packages/spec/liveness/dashboard.json 的 _note 写明:
Widget-level props are classified in the DashboardWidgetSchema subtree, not drilled here.
但不存在这个 subtree。packages/spec/liveness/ 下 28 个台账文件里,提到 DashboardWidget 的只有 dashboard.json 自己和 README.md。
而 check-liveness.mts 只按显式 children 下钻一层(:375-387):
if (led?.children) {
// drill one level
dashboard.json 的 widgets 条目是:
{ "status": "live",
"note": "objectui: the widget grid — DashboardRenderer maps each to DatasetWidget/metric/etc. Per-widget props live in the DashboardWidgetSchema subtree (strict, ADR-0021)." }
没有 children。所以检查器把整个 widgets 记作一个 live 属性就收工,DashboardWidgetSchema 的 ~22 个可授权键(dataset / values / dimensions / filterBindings / responsive / aria / compareTo / colorVariant / actionUrl / suppressWarnings / …)一个都没进过分类,unclassified 计数也不会报——因为没声明 children 就根本不走那条分支。
为什么这是「声明 ≠ 强制」
台账的 _note 是一句断言:这些键在别处分类了。检查器不校验这句断言,读台账的人(和 agent)会据此认为覆盖完整。这正是 Prime Directive #10 的形状,只不过发生在审计系统自身身上。
实际后果(已经发生了一次)
2026-07-30 的 #3896 close-out sweep 按审计文档移除了 dashboard.aria / dashboard.performance / widgets[].performance,却把 widgets[].responsive 留下了。台账说不出为什么——因为它对这两个键都没有裁决记录。同一个 sweep 在 view 侧移除 list.responsive 时,理由是「authorable and inert — no renderer in either repo read them」;widgets[].responsive 的实测状态与之相同(objectui@91757a7 全仓 grep 无任何读取点),只是没人被要求去看。
换句话说:这个键躲过审计靠的是台账覆盖缺口,不是任何 liveness 证据。
建议
二选一,都不大:
- 给
dashboard.json 的 widgets 补 children,把 22 个 widget 级键逐个分类(与 view.json 对 list/form 的做法一致——那边正是靠 children 下钻才让 list.responsive 被判 dead 的)。
- 若确实想要独立 subtree 文件,那就让
check-liveness.mts 能解析这种引用,并在引用悬空时报错;在那之前 _note 里不该写一句检查器兑现不了的话。
倾向 1——它复用已有机制,且立刻能给 widgets[].responsive 一个有据可查的裁决(#4876 正卡在这个问题上)。
同类排查值得顺带做一遍:其它台账文件里是否还有「声称在别处分类」但无下钻的容器条目。
Generated by Claude Code
在 #4876 的实测过程中发现,与该单的裁决无关,独立存在。
现象
packages/spec/liveness/dashboard.json的_note写明:但不存在这个 subtree。
packages/spec/liveness/下 28 个台账文件里,提到DashboardWidget的只有dashboard.json自己和README.md。而
check-liveness.mts只按显式children下钻一层(:375-387):dashboard.json的widgets条目是:{ "status": "live", "note": "objectui: the widget grid — DashboardRenderer maps each to DatasetWidget/metric/etc. Per-widget props live in the DashboardWidgetSchema subtree (strict, ADR-0021)." }没有
children。所以检查器把整个widgets记作一个 live 属性就收工,DashboardWidgetSchema的 ~22 个可授权键(dataset/values/dimensions/filterBindings/responsive/aria/compareTo/colorVariant/actionUrl/suppressWarnings/ …)一个都没进过分类,unclassified计数也不会报——因为没声明children就根本不走那条分支。为什么这是「声明 ≠ 强制」
台账的
_note是一句断言:这些键在别处分类了。检查器不校验这句断言,读台账的人(和 agent)会据此认为覆盖完整。这正是 Prime Directive #10 的形状,只不过发生在审计系统自身身上。实际后果(已经发生了一次)
2026-07-30 的 #3896 close-out sweep 按审计文档移除了
dashboard.aria/dashboard.performance/widgets[].performance,却把widgets[].responsive留下了。台账说不出为什么——因为它对这两个键都没有裁决记录。同一个 sweep 在view侧移除list.responsive时,理由是「authorable and inert — no renderer in either repo read them」;widgets[].responsive的实测状态与之相同(objectui@91757a7 全仓 grep 无任何读取点),只是没人被要求去看。换句话说:这个键躲过审计靠的是台账覆盖缺口,不是任何 liveness 证据。
建议
二选一,都不大:
dashboard.json的widgets补children,把 22 个 widget 级键逐个分类(与view.json对list/form的做法一致——那边正是靠children下钻才让list.responsive被判 dead 的)。check-liveness.mts能解析这种引用,并在引用悬空时报错;在那之前_note里不该写一句检查器兑现不了的话。倾向 1——它复用已有机制,且立刻能给
widgets[].responsive一个有据可查的裁决(#4876 正卡在这个问题上)。同类排查值得顺带做一遍:其它台账文件里是否还有「声称在别处分类」但无下钻的容器条目。
Generated by Claude Code