fix(plugin-dashboard): a dataset widget labels its comparison from compareTo.kind, not the filter's macro tokens (objectui#11632) - #11647
Merged
objectstack-fleet[bot] merged 2 commits intoOct 5, 2026
Conversation
…mpareTo.kind, not the filter's macro tokens (objectui#11632) On the ADR-0021 dataset path the executor shifts the whole resolved window (previousPeriod = the equal-length window before it, previousYear = the same window a year back), so the label is read off the kind. The filter-token guess in compareToTrendLabelKey stays on the inline path, where it is faithful. Claude-Session: https://claude.ai/code/session_015W8GBu6sBiqus2L2xjMsAL Co-authored-by: Claude <noreply@anthropic.com>
…compareTo.kind; changeset (objectui#11632)
Replaces the pin that held the filter-token guess on the dataset path
("vs last quarter" off quarter macros) with pins that previousPeriod over a
{today} window reads "vs previous period" on the KPI delta and the chart's
comparison series, and that every compareTo kind the spec declares has its
own label.
Claude-Session: https://claude.ai/code/session_015W8GBu6sBiqus2L2xjMsAL
Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contributor
Author
ACCEPT: PR objectui#11647, head
|
objectstack-fleet
Bot
deleted the
claude/issue-11632-dataset-compare-label
branch
October 5, 2026 08:20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #11632
Clause-②: no
What changed
On the ADR-0021 dataset path,
DatasetWidgetnow names a comparison window fromcompareTo.kindalone.previousPeriodreads "vs previous period" andpreviousYearreads "vs last year". It no longer callscompareToTrendLabelKey, which guesses the window from the RAW filter's date-macro tokens ({today}gives "vs yesterday", quarter macros give "vs last quarter").A module-local
COMPARE_KIND_TREND_KEYmaps each kind to its existingdashboard.trend.*key. It is typed withsatisfiesagainst a Record keyed byCompareToConfig['kind'], so a third kind added to that type is a compile error there.TREND_LABEL_DEFAULTSis unchanged: it stays the vocabularycheck:i18n-keysreads for thedashboard.trend.family.compareToTrendLabelKeyin@object-ui/coreand the inline path that uses it are unchanged, per triage's direction.Why the guess was wrong here and right inline
On the inline path,
shiftFilterByCompareToreally does rewrite the filter ({today}becomes{yesterday},current_*becomeslast_*), so a label read off those tokens names what was queried. On the dataset path no token is rewritten. The widget lowers the resolved window intotimeDimensions[].dateRange, and the executor'sshiftRange(objectstackservice-analytics,dataset-executor.ts, read at objectstack07bf21ff) moves the whole window.previousPeriodbecomes the equal-length window ending the day before, andpreviousYearthe same window a year back. The kind is all there is to know about which window was compared, so the label comes from the kind.Every surface this label reaches
The fix changes one call. Its result,
compareLabel, is the only window label inDatasetWidget, and every comparison surface reads it: the KPI delta (dataset-compare-trend), the flat table's comparison column header and its CSV export header, the cross-tab caption and cell title, and the chart's comparison series label (the line legend in the card). None of them needs a change of its own.Other callers of
compareToTrendLabelKey, none of them changed:ObjectMetricWidget: the inline object metric. It compares throughshiftFilterByCompareTo, so its label is faithful there.ObjectChart(plugin-charts): its comparison series is built only for anaggregatechart on the inline path. Its dataset branch forwards nocompareTotoqueryDataset, so the label call never runs for a dataset-bound chart. See Acceptance notes."And the resolved window": what the window would add, and why the kind is enough
The card's Done-when names "the compareTo kind and the resolved window". The kind decides the window: for every window,
previousPeriodis "the equal-length window before it". So "vs previous period" is true of a 30-day range, a quarter and a single day alike, and the window adds no correctness to the label. What it could add is specificity, in one of two ways:dashboard.trend.*key in ten locales. That is outside this dispatch's Clause-② fence (no new i18n key).shiftRangearithmetic in the renderer: a second copy of the producer's logic, which can drift from it.Neither is needed for a faithful label, so this PR takes the kind. The report raises it as an open question so the Done-when reading is confirmed rather than assumed.
Tests
packages/plugin-dashboard/src/__tests__/DatasetWidget.compareTo.test.tsx:labels the window from the RAW filter's macros, which resolution erased. It asserted the removed branch:previousPeriodover quarter macros reading "vs last quarter" on the dataset path. That label is wrong there, because the executor compares the equal-length window, not the calendar quarter.the comparison label comes from compareTo.kind (objectui#11632), using the card's shape (a dashboardlast_30_daysrange,{30_days_ago}to{today}):previousPeriodreads "vs previous period" and not "yesterday" on the KPI delta. The whole resolved window is lowered for the executor to shift.previousPeriodover quarter macros reads "vs previous period", with no calendar unit.@objectstack/specdeclares for a widget'scompareTogets its own label. The kinds are read fromDashboardWidgetSchemaitself, and a coverage test fails if the spec gains a kind this table lacks.compareToTrendLabelKey's{today}givesvsYesterdayinpackages/core/src/utils/__tests__/compare-to.test.ts, andObjectMetricWidget.compareTo's "labels vs last quarter".Reverse verification (one-off, from committed state)
DatasetWidget.tsxwas reverted to the base commit76993f8. The blob hash matched the base blob.COMPARE_KIND_TREND_KEYcounted 0, and the oldcompareToTrendLabelKey(compareTo, rawFilter)call counted 1. A trap then restored HEAD, and the restore was proved by blob hash and an emptygit diff HEAD.95f2df9:Tests 31 passed (31).Tests 4 failed | 27 passed (31), all four in the new block. The failures received "Revenue · vs yesterday", "20%vs yesterday" and "20%vs last quarter".previousYearwas already labelled by its kind.Live before/after
The live run used objectstack
main07bf21ff(showcase,objectstack dev --fresh, own port) and the card's probe dashboard: alast_30_daysdate range oncreated_at, apreviousPeriodmetric, apreviousYearmetric and apreviousPeriodline overshowcase_task_metrics. Two consoles were served from source and pointed at that one backend.76993f8800%vs yesterday100%vs last year800%vs previous period100%vs last yearBoth consoles sent identical dataset queries:
timeDimensionscreated_at["2026-09-05","2026-10-05"]with thecompareTokind, and nothing else. The server answeredtask_count 9,task_count__compare 1.A discriminating probe on the same server shows the executor compares the preceding window, not yesterday. The 8-day window
2026-09-28..2026-10-05withpreviousPeriodansweredtask_count 4,task_count__compare 3. Queried alone,2026-09-20..2026-09-27counts 3 and yesterday (2026-10-04) counts 1.Gates (HEAD
95f2df9)pnpm exec vitest run --maxWorkers=2 packages/plugin-dashboard/ packages/core/src/utils/__tests__/compare-to.test.ts:Test Files 171 passed (171),Tests 1699 passed | 6 skipped (1705).pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-dashboard^...' build(the dependency closure, 13 packages): exit 0.pnpm --filter @object-ui/plugin-dashboard type-check(tsc --noEmit && tsc -p tsconfig.test.json): exit 0.pnpm --filter @object-ui/plugin-dashboard lint: exit 0, 0 errors. No warning falls on a line this PR touches.check:i18n-keys,check:i18n-dead-keys(nodashboard.trend.*key reported),check:spec-symbols,check:new-line-citations(0 new),check:control-bytes,check:changeset-claims,check:pending-changeset-literals,check:test-path-roots,check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape,check:phantom-deps,check:unused-deps,scripts/check-changeset-presence.mjsandscripts/check-changeset-no-major.mjs.origin/mainwas still at the base76993f8before this PR opened. Theorigin/mainmerge was a no-op ("Already up to date"), so the runs above are of the tree that would have resulted.Changeset:
.changeset/11632-dataset-compare-label.md, apatchfor@object-ui/plugin-dashboard.Acceptance notes
These are read-only observations. Neither has been run through a public door, so neither is carded.
previousPeriodover a rolling range.shiftFilterByCompareTorewrites{today}to{yesterday}but leaves{30_days_ago}alone. Over alast_30_daysfilter, the inline comparison window is therefore 30 days ago to yesterday. That window overlaps the current one almost entirely, and it is labelled "vs yesterday". The label is faithful to the rewrite, but the window is not "the equal-length window before", which is whatCompareToConfig's docblock and the spec'sDatasetCompareTodescribe forpreviousPeriod. This PR leaves the inline path alone, per triage. No one carries this.ObjectChartwithcompareTo. Its dataset branch sends nocompareTotoqueryDataset, and it builds the comparison series only for anaggregatechart. Read from source, achartblock bound to a dataset withcompareTowould draw no comparison and say nothing. No producer of that shape was looked for. No one carries this.Generated by Claude Code