Skip to content

fix(spec)!: dashboard widget compareTo 收敛为执行器契约 { kind, dimension? } (#5011) - #5147

Merged
xuyushun441-sys merged 5 commits into
mainfrom
claude/issue-5011-compareto-converge
Aug 4, 2026
Merged

fix(spec)!: dashboard widget compareTo 收敛为执行器契约 { kind, dimension? } (#5011)#5147
xuyushun441-sys merged 5 commits into
mainfrom
claude/issue-5011-compareto-converge

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

Fixes #5011

按 2026-08-04 维护者裁决执行:方案 1 + 执行器决议规则。⛔ 不重议。

问题

widget 声明了三个对比分支,TSDoc 写得很具体;分析执行器实现的是另一份契约,而且从来不是同一份。于是在 ADR-0021 dataset 路径(spec 自称「唯一面向作者的分析形态」)上三个分支全废,而且是两种不同的废法:

  • compareTo: 'previousPeriod' / 'previousYear' —— 被 dataset 渲染器静默丢弃。基础数值照常渲染,作者要的对比列不存在
  • compareTo: { offset: '7d' } —— 被原样转发进 DatasetSelection.compareTo,而那个契约是 { kind, dimension },里面根本没有 offset 这个概念,于是执行器抛 compareTo requires a timeDimension "undefined",整块 widget 报错。

三个分支只在遗留内联图表路径上真的能跑。同一个键两种命运,失败的那条恰是 spec 自己推荐的规范路径 —— 这比普通的「declared but unread」更靠后一档:文档在自信地教一个会崩的形状

改法

compareTo 变成已实现的那份契约的薄投影:

compareTo?: { kind: 'previousPeriod' | 'previousYear'; dimension?: string }

DatasetSelection.compareTo。widget 侧不再有第二套词表可以漂移,declared = enforced构造保证,而不是靠人盯。DashboardWidgetOptionsSchema(有意的 passthrough)与 responsive 墓碑均未触碰。

dimension 可省略 —— 决议规则在执行器,不在渲染器

省略时由 dataset-executor.tsresolveCompareDimension 决议,判据沿用执行器自己一直在用的那条(timeDimensions 条目带 dateRange):

  • 恰好一个候选 → 用它;
  • 零个 → 响亮报错:对比只在有界窗口上才有定义;
  • 两个及以上 → 响亮报错并逐个列出候选名,绝不静默取第一个。

最后一条是最要紧的:作者想比 close_date 而系统挑了 created_at,得到的对比列是错的而不是缺的 —— 后者会被发现,前者不会。这是生产端决议规则,不是 PD#12 反对的消费端宽容映射:dashboard widget、report、裸 queryDataset 三个调用方拿到同一个维度或同一个报错,没有任何渲染器处在「自己猜一个」的位置上。

offset 退休(ADR-0087)

先实测存量(裁决要求):全仓 4 处 compareTo 作者实例,全部是字符串形态,全在 examples/app-crm;两个仓库里 { offset } 实例为 0。符合预期 —— 规范路径上用过 { offset } 的早就崩了,它根本无法在那里沉淀。

v16 v17 处理
compareTo: 'previousPeriod' { kind: 'previousPeriod' } D2 确定性改写
compareTo: 'previousYear' { kind: 'previousYear' } D2 确定性改写
compareTo: { offset: '1y' } { kind: 'previousYear' } D2 确定性改写 —— 1y 就是 previousYear
compareTo: { offset: '7d' / '1M' / … } 无忠实目标 不改写,登记为 dashboard-widget-compareto-offset 语义迁移

最后一行是刻意不改写:previousPeriod 按 filter 解析出的窗口自身长度位移,只有当那个窗口恰好是 7 天时才等于 7d。机械改写会悄悄改变对比列统计的是哪些行 —— 把一个响亮的失败换成一个错误的数字,正是本次收敛要终结的失败类。

retiredFromLoadPath: true:旧拼法不给接受窗口。自动转换的 loader 会让 compareTo: 'previousPeriod' 继续解析通过,那就是 PD#12 禁止的宽容消费者,也正是让两套词表悄悄漂移一整个大版本的那个动力学。存量 sys_metadata 行仍被覆盖 —— 每个再水化缝都会通过 applyConversionsToStoredItem 重放已退休条目(#3903)。

三个值得单说的点

1. 新形状不含联合,这不是外观问题。 zod 把失败的联合塌缩成一条裸 Invalid input,zodIssuesToFields 只映射顶层 issue —— 所以本战役写进联合 arm 里的每一条精心措辞的处方,都是写给一个收不到它的读者的(#5014)。批 14 的台账行为 compareTo 记下了这个限制;本 PR 消解了它(而不是绕过),处方现在就在顶层。#5014 对其他所有联合 arm 仍然成立 —— 台账行改成了「一个槽位的更正」,不是该 finding 的撤回。

2. 字符串形态的处方按 issue.input 分派(HookBodyCapability / object.managedBy: 'system' 先例):只有真的合法过的两个拼法拿到「was removed」文案;写 previosPeriod 的人被告知的是拼错,而不是被告知一个他从没用过的东西「被移除了」。为此给 strictObject 加了一个窄的 retiredForms 钩子 —— guidance 到不了这个 case,因为输入根本不是对象时 unrecognized_keys 不会触发。

3. 台账更正而非重写。 liveness 的 compareTo 判定仍是 live,这点值得停一下:它从来就不是「declared but unread」—— 消费者一直都在,缺的是对它消费什么的共识。这是台账此前没有词汇描述的一类失败,它自己的 compareTo 行不得不用一整段散文来记录。_note 里写清楚了。

跨分片交接(#4876 式)

objectui 遗留内联图表路径不在本 PR 内,已按裁决未认领开单:objectstack-ai/objectui#3337,映射逐条写明:CompareToConfig 改型、shiftFilterByCompareTo.kind 分派、compareToTrendLabelKey、以及功能性的那一半 —— DatasetWidget 需要把已解析的日期窗口降成 selection.timeDimensions[].dateRange,否则执行器无窗口可移。该 issue 也记明:DatasetWidget.tsx:163-168 的字符串丢弃 workaround 在新形状下不再需要,应一并删除。

验证

  • check:generated 8/8 up to date;十条 source-audit gate(check:liveness / check:empty-state / check:strictness-ledger / check:skill-examples / check:skill-refs / check:skill-docs / check:react-declaration-parity / check:variant-docs / check:exported-any / check:dual-source-exports)全 PASS。
  • @objectstack/spec 7745 tests、service-analytics 538 tests、example-crm 20 tests、CLI migrate-meta.e2e 12 tests 全绿;全仓 pnpm typecheck 124/124。
  • 三个 example app objectstack validate 通过(残留 warning 均为既有、与本改动无关)。
  • 每一个断言类先做过 sabotage-red:spec 侧 17 条中 13 条在改前 schema 上红(其余 4 条是双边都成立的护栏);执行器侧 9 条中 8 条红(唯一绿的是刻意的 control)。
  • ADR-0087 直解探针走 BUILT 产物、按 carrier slot 路径(getMetadataTypeSchema('dashboard')),负控先证绿再断言退休形态不过关 —— dashboards 确实被 validate 覆盖,仍照 objectstack build / validate 从不按 PageSchema 解析页面元数据:ADR-0089 D3a 早就该拒绝的键一路通过,#4001 的「三个示例应用 validate 全过」对 page 面是空证 #5000 的纪律探一遍。
  • os-regen 四步已做:git merge origin/main(⛔ 未 rebase / 未 force-push)→ 把 os-regen 路径 checkout 回 origin/main → 整体重生成 → 实测 sibling 条目全部存活(spec-changes.json 相对 origin/main 的增量恰好只有我这两条;dashboard-widget-responsive-removed / view-inert-keys-removed / hook-body-crypto-hash-removed 等各 2 处均在)。

changeset:major(spec + service-analytics),含 FROM → TO 映射与一行修法。


🤖 Generated with Claude Code

https://claude.ai/code/session_01Ehu85kbvMcrNTUJjwxvLJ9


Generated by Claude Code

@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 6:16am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests protocol:ui tooling 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/service-analytics, @objectstack/spec.

108 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/data-api.mdx (via @objectstack/service-analytics)
  • 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/service-analytics, @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 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/service-analytics, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @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/service-analytics, @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/service-analytics, @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/service-analytics, @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/service-analytics, @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/service-analytics, @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.

@xuyushun441-sys
xuyushun441-sys marked this pull request as ready for review August 4, 2026 06:34
@xuyushun441-sys
xuyushun441-sys added this pull request to the merge queue Aug 4, 2026
Merged via the queue into main with commit d17df80 Aug 4, 2026
25 checks passed
@xuyushun441-sys
xuyushun441-sys deleted the claude/issue-5011-compareto-converge branch August 4, 2026 06:45
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/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dashboard widget compareTo:三个声明分支在 ADR-0021 dataset 路径上全部无效(两个静默丢弃,一个抛错)

2 participants