Skip to content

liveness: DashboardWidgetSchema 的 ~22 个 widget 级键从未被台账分类,而 dashboard.json 的 _note 声称它们已分类 #4956

Closed

Description

@xuyushun441-sys

在 #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 证据。

建议

二选一,都不大:

  1. 给 dashboard.json 的 widgets 补 children,把 22 个 widget 级键逐个分类(与 view.json 对 list/form 的做法一致——那边正是靠 children 下钻才让 list.responsive 被判 dead 的)。
  2. 若确实想要独立 subtree 文件,那就让 check-liveness.mts 能解析这种引用,并在引用悬空时报错;在那之前 _note 里不该写一句检查器兑现不了的话。

倾向 1——它复用已有机制,且立刻能给 widgets[].responsive 一个有据可查的裁决(#4876 正卡在这个问题上)。

同类排查值得顺带做一遍:其它台账文件里是否还有「声称在别处分类」但无下钻的容器条目。


Generated by Claude Code

Activity

  1. added
    toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface
    pm:queueReady for the PM dispatch loop
    domain:specDomain lane — seat card indexed by label:pm:seat
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Aug 3, 2026
  2. xuyushun441-sys commented on Aug 3, 2026

    @xuyushun441-sys
    CollaboratorAuthor

    🔒 认领:PM 循环补位(#4876 dev 完成腾位;批 14 因与 #4995 同文件须串行,本单顶上)
    会话:session_01Ehu85kbvMcrNTUJjwxvLJ9
    分支:claude/issue-4956-liveness-widget-drill
    Worktree:objectstack-issue-4956
    域:domain:spec(仪器/门禁)
    文件面:packages/spec/scripts/liveness/check-liveness.mts(或按实测的钻取实现位置)、packages/spec/liveness/dashboard.json、新增的 widget 键分类行

    ⚠️ 已知共享面:#4995(在队)也动了 liveness/dashboard.json 两行——合并时双边保留,重跑 check:liveness 为准。仪器修复必须先证红(用一个确知存在且未分类的 widget 键作探针,证明修复前地图外、修复后被要求分类)。


    Generated by Claude Code

  3. xuyushun441-sys commented on Aug 4, 2026

    @xuyushun441-sys
    CollaboratorAuthor

    ✅ 验收通过 —— PR #5012(即刻挂轨;远端 Type Check / Test Core 分片交接时仍在跑,本地同树已绿,auto-merge 会等它们)

    复核要点:

    • 修法是结构性的(任务书第 1 条的高标准达成):台账容器属性此后必须三选一声明处置——children 钻取 / {container, to} 延迟(且门禁解析目标:必须存在、必须恰好分类该容器的子键集)/ 只减不增基线。悬空、漂移、双列、陈旧基线行全部各自证红。
    • 延迟解析器抓到本 PR 自己第一版基线的错:声称 64 容器全部「无处分类」,实际 6 个(248 键)已在别处——不修解析器就会带着与本单同款缺陷发货。仪器咬自己作者,本战役第 N 例,这正是要它存在的理由。
    • 22 个 widget 键闭合调用图分类(16 live / 8 dead 合计后 dashboard 20→41);CLI lint 注册补上,5 条 authorWarn 真能到作者面前;假 _note 修正。
    • RED/GREEN 对照完整:旧门对旧账绿(缺陷复现)→ 新门对旧账红(点名 22 键)→ 分类恢复后绿。

    衍生分诊:


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

domain:specDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch looptoolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions