Skip to content

refactor(spec,lint)!: 退役 dashboard widget 的 action 三键与 aria —— 连同那道「为不存在的按钮做引用完整性」的门 (#5010) - #5255

Merged
xuyushun441-sys merged 4 commits into
mainfrom
claude/issue-5010-dashboard-dead-keys
Aug 4, 2026
Merged

refactor(spec,lint)!: 退役 dashboard widget 的 action 三键与 aria —— 连同那道「为不存在的按钮做引用完整性」的门 (#5010)#5255
xuyushun441-sys merged 4 commits into
mainfrom
claude/issue-5010-dashboard-dead-keys

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

Fixes #5010

#4956DashboardWidgetSchema 的 22 个 widget 级键补上首次逐键裁决,其中 6 个 dead(responsive 已在 #4876 / PR #4995 退休)。本 PR 处置其中 4 个,colorVariant 交回裁决 —— 见末节。

逐键处置

处置 依据(2026-08-04 于 HEAD 复测,objectui@91757a7)
widgets[].actionUrl retired(retiredKey 墓碑) DashboardRenderer 里 14 处 actionUrl 全部限定在 schema.header.actions[](DashboardHeaderAction,另一个 schema)。无任何代码读 widget.actionUrl
widgets[].actionType retired 同上;唯一读它的是 lint 规则,用来给(渲染不出来的)actionUrl 挑解析规则
widgets[].actionIcon retired 最彻底的一个:两仓库里除自身声明与一行 objectui 类型注释外零引用,连 lint 都不看
widgets[].aria retired 两仓库均无 widget.aria 消费者。DashboardRenderer / DatasetWidget 里的 aria-* 是渲染器自己的 DOM 属性;objectui 唯一的 .aria 读取在 plugin-view/ObjectView.tsx:989,那是 view
widgets[].colorVariant kept —— 需裁决 见「不在本 PR 内」

四个键躲过 #3896 sweep 的原因与 responsive 相同:台账当时对 dashboard.widgets 没有 children,widget 级键一个都没被分类过 —— 是仪器有洞,不是键有豁免。

一并处置的二阶成本(本单最值得读的一段)

packages/lint/src/validate-dashboard-action-refs.tswidgets[].actionUrl 做的是 ERROR 级引用完整性校验:目标解析不到就构建失败。它的 docblock 自称 "the per-widget button"、声称 mirrors objectui 运行时派发 —— 而那个按钮不存在

于是今天一个作者可能因为一个永远不会渲染的控件指向一个不存在的 action 而被卡住构建。一条为消灭「假 affordance」而写的规则,自己维持着一个。

这正是为什么本单选择退役键而不是「把这条规则放宽」:widget 分支随键一起删除,并留下两条 pin —— 一条断言它对旧的 widget 目标保持静默,一条(混合 stack)证明 header 目标仍然被检查,即键是被忽略而非被降级。

退役套件(spec-property-retirement)

  • 四个 retiredKey() 墓碑,与同 schema 内 responsive(spec: DashboardWidgetSchema.responsive 按断点建模 —— objectui#3173 维护者已裁决;目标 17.0.0 正式版,带回退条款 #4876)一致。DashboardWidgetSchema .strict(),直接删键也会响 —— 但只会响成泛化的 "unrecognized key";墓碑保留键声明,让拒绝携带处方,并把输入类型定为 never 使 tsc 先失败。action 三键共用一条处方并互相点名,避免作者删掉被告知的那一个后再撞两次。
  • ADR-0087 D2 转换 + D3 链步 dashboard-widget-action-aria-removed(retiredFromLoadPath,expectedNotices: 4 = 键数):os migrate meta --from 16 自动改写,存量看板 replay 干净而非在 load 时撞墓碑。独立条目而非并入 dashboard-inert-keys-removed(后者的身份是 POST /data/sharing/rules 绕过 SharingRuleSchema:criteria 缺失或拼错静默变成"共享该对象全部记录",与 ADR-0049 "never seeded as a permissive match-all" 直接冲突 #3896 sweep)。
  • 台账四行保留(status: dead + verifiedAt + REMOVED note)—— 墓碑令键仍在被遍历的 shape 内(rls.priority 先例);去掉 authorWarn/authorHint,严格 parse 接管。ledger-driven 的 CLI advisory 测试改为断言静默,并保留 colorVariant 作阳性对照(否则「看板遍历整个坏掉」会被读成「退役成功」)。
  • 基线按键级移动:authorable-surface.json 四行转 [RETIRED];json-schema.manifest.json / api-surface.json / api-surface-signatures.json 按构造不动 —— 无 def 停止 emit、无导出移除(与 responsive 同形态)。
  • AriaPropsSchema 未删除 —— 仍活在 app.aria / page.components[].aria,并有 CONTROL 测试守住。i18n.zod.ts 里那句「~30 个 live 载体」的实测快照同步订正(本 PR 让它变旧的)。
  • 手写文档 content/docs/deployment/validating-metadata.mdx 去掉 widget 侧承诺;content/docs/references/**gen:docs 重生成。未触碰 content/docs/releases/

措辞对齐

与今日同期落地的两处保持一个声音:#5175(chartConfig 在 dashboard 面 12 键惰性 11)与 PR #5221(drillDown/drilldown/drill guidance + 「dataset-form drill is derived, not configurable」)。本 PR 的 action 处方因此把「每行可点」指向 dataset-bound table/pivot(其下钻由语义层推导),而不是提示某个 per-widget 配置。

⚠️ 不在本 PR 内:colorVariant 需裁决

#4956 的分诊建议「优先 D2 改写到活位置(widget.colorVariantoptions.colorVariant),不可行再墓碑」。在 HEAD 复测后,D2 的前提不成立:

  • options 只在 inline 路径componentSchema({ type: 'metric', ...options, label, value })到达渲染器;
  • 本 schema 的 dataset必填,DashboardRendererdatasetBound = !!widget.dataset 因此对每一个 spec 可授权 widget 为真,一律走 DatasetWidget;
  • DatasetWidget 完全没有配色能力(只有渲染器自算的 categoryColorsshowLegend)。台账自己的 authorHint 也已写明这一点,却仍指向 options

即:options.colorVariant 对所有可授权 widget 同样是死的。改写只会把 16 处 authored(platform-objects 7 + app-showcase 9,全部 type: 'metric' 且 dataset-bound)从一个死槽搬到另一个死槽,并多造一个惰性键(新台账行按诚实测量仍判 dead)。

剩下两条真分叉,成本不同、且其一跨仓库,故不猜:

  1. 退役 colorVariant(墓碑)—— ADR-0049 字面正确(无特性、无路线图),但删掉 16 处 authored 明确表达的意图,很可能在 v18 被重新加回,是同一大版本内的 churn。
  2. enforce:让 DatasetWidget 支持 accent color(objectui 侧)—— 让键变真,declared = enforced 由构造成立,16 处 authored 立刻名副其实;但属 objectui 净新增 UI 能力 + 跨仓库,超出本单文件面。

验证

pnpm --filter @objectstack/spec test   → 306 files / 7876 tests passed
pnpm --filter @objectstack/lint  test  →  57 files / 1198 tests passed
turbo typecheck: spec / lint / platform-objects / example-showcase / example-crm → 全绿
  (墓碑把 tsc 变成扫描器:examples 全绿 = 全仓零 authored 站点)
check:generated / liveness / empty-state / authorable-surface / api-surface /
spec-changes / upgrade-guide / strictness-ledger / docs / skill-examples / i18n → 全 PASS

台账数字面走 gen:strictness-ledger(counts.md 未变 —— 退役不移动 strip 站点,这正是散文行记下的那一点);仅 dashboard.zod.ts 一行散文手写。已 git merge origin/main(含 #5237/#5251/#5252/#5246)并按 os-regen 四步整体重生成。


🤖 Generated with Claude Code

https://claude.ai/code/session_01Ehu85kbvMcrNTUJjwxvLJ9


Generated by Claude Code

claude added 3 commits August 4, 2026 12:52
…不存在的按钮做引用完整性」的门 (#5010)

#4956 给 `DashboardWidgetSchema` 的 22 个 widget 级键补上首次逐键裁决,
其中 6 个 dead。本单处置其中 4 个(零 authored、零 renderer):

- `actionUrl` / `actionType` / `actionIcon` —— 描述的是一个「每个 widget 自己的
  操作按钮」,而两个仓库里**没有任何渲染器画过它**。DashboardRenderer 里 14 处
  `actionUrl` 全部限定在 `schema.header.actions[]`(DashboardHeaderAction,另一个
  schema);`actionIcon` 更彻底,除自身声明外零引用。
- `aria` —— 声明的 ARIA 属性从未到达 DOM,与 #3896 删掉的看板级 `aria` 是同一种
  「假合规」,只是低一层。

四个键躲过 #3896 sweep 的原因与 `widgets[].responsive` 相同:台账当时对
`dashboard.widgets` 没有 `children`,widget 级键**一个都没被分类过** —— 是仪器有
洞,不是键有豁免。

## 一并处置的二阶成本

`packages/lint` 的 `validate-dashboard-action-refs` 对 `widgets[].actionUrl` 做的是
**ERROR 级**引用完整性校验(目标解析不到就构建失败),docblock 自称
「the per-widget button」并声称镜像 objectui 运行时派发 —— 而那个按钮不存在。
于是作者可能因为一个**永远不会渲染**的控件指向一个不存在的 action 而被卡住构建。
一条为消灭「假affordance」而写的规则,自己维持着一个。widget 分支随键一起删除,
并留下 pin 测试保证它不会回来。

## 退役套件

- 四个 `retiredKey()` 墓碑(与同 schema 内 `responsive` 一致):tsc 报 `never`,
  parse 抛出**处方**而非泛化的 unrecognized key;action 三键共用一条处方并互相点名。
- ADR-0087 D2 转换 + D3 链步 `dashboard-widget-action-aria-removed`
  (`retiredFromLoadPath`),`os migrate meta --from 16` 自动改写。
- 台账四行**保留**(墓碑令键仍在被遍历的 shape 内 —— rls.priority 先例),
  去掉 `authorWarn`/`authorHint`:严格 parse 接管,ledger-driven 的 CLI advisory
  改为断言**静默**,并留 `colorVariant` 作阳性对照。
- `authorable-surface.json` 四行转 `[RETIRED]`;四张 ratchet 按构造不动
  (无 def 停止 emit、无导出移除)。

`AriaPropsSchema` 本身**未删除** —— 仍活在 `app.aria` / `page.components[].aria`。

## 不在本单内

`widgets[].colorVariant`(第 5 个 dead 键)**刻意未动**:其改写目标
`options.colorVariant` 实测同样是死的 —— `options` 只在 inline 路径经
`componentSchema` 到达渲染器,而本 schema 的 `dataset` 是必填,故所有
spec 可授权 widget 均为 dataset-bound、走 DatasetWidget,而后者完全没有配色能力。
改写只会把 16 处 authored 从一个死槽搬到另一个死槽,并多造一个惰性键。交回裁决。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ehu85kbvMcrNTUJjwxvLJ9
合并驱动把 `authorable-surface.json` 记为 pending(它不做文本合并),
从合并后的树整体重生成,补回 #5237 的 `ui/UserFilters:allowAddTab`。
9 张生成物全部 up to date。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ehu85kbvMcrNTUJjwxvLJ9
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 4, 2026 1:04pm

Request Review

@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests protocol:ui tooling and removed size/l labels Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/lint, @objectstack/spec.

107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/lint, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/lint, @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

#5010 退役 widget 级 actionType 后,「a type added to ActionType is
dispatchable from a widget」不再成立;唯一消费者是 DashboardHeaderActionSchema。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ehu85kbvMcrNTUJjwxvLJ9
@github-actions github-actions Bot added the size/l label Aug 4, 2026
@xuyushun441-sys
xuyushun441-sys marked this pull request as ready for review August 4, 2026 13:08
@xuyushun441-sys
xuyushun441-sys added this pull request to the merge queue Aug 4, 2026
Merged via the queue into main with commit eaaf03c Aug 4, 2026
25 checks passed
@xuyushun441-sys
xuyushun441-sys deleted the claude/issue-5010-dashboard-dead-keys branch August 4, 2026 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ui size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

enforce-or-remove: DashboardWidgetSchema 的 5 个 dead 键(#4956 下钻首次给出裁决)

2 participants