Repository navigation
fix(core): compareTo on an already-past date range compares with the period before it, and previousYear from 29 February stays in February - #30246
Conversation
… just before it, not with itself
previousPeriod moved only current_* / today tokens, so a dashboard window of
next_month or next_quarter was compared with itself (a 0 change every time)
and next_30_days moved only its start. A forward window now steps back one
period: next_month_* to this month, next_quarter_* to this quarter, and a
{today} .. {N_days_from_now} pair to the N + 1 days ending yesterday. The
trend label names that window (vsThisMonth, vsThisQuarter, vsPreviousPeriod);
the two new keys are in all ten locale packs. The 13 backward presets keep
their windows and labels.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGufzijmF7yUSk5ga9jRkh
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzijmF7yUSk5ga9jRkh
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzijmF7yUSk5ga9jRkh
…period before it, and previousYear from 29 February stays in February
previousPeriod never moved {yesterday} or the last_* tokens, so yesterday,
last week, last month, last quarter and last year compared the window with
itself, and {N_days_ago} .. {today} moved only its end. The past tokens now
compare with the period before them (computed from the resolved last_*
start, since no token names two periods back; {yesterday} becomes
{2_days_ago}), and a backward rolling window moves back by its own N + 1
days. previousYear clamps the shifted day to the month's length, so a
29 February window compares with February, not March. These comparisons
are labelled vsPreviousPeriod. today, this_* and the forward presets are
unchanged.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGufzijmF7yUSk5ga9jRkh
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzijmF7yUSk5ga9jRkh
|
domain:ui#1 · os-support-ai · session_01WGufzfE4V9fzZgJLrLDmMC 维护者速读(席位终稿)
席位核对 · ACCEPT · head
|
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 41962336936 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Requested by Yibo Wang · project thread
Fixes #30197
维护者速读
compare-to.ts一个文件的逻辑,不动规范、不动服务端。「今天」「本周/本月/本季度/今年」和三个前向预设的环比窗口逐字节不变;变化的只有上述后向预设,以及 2 月 29 日那天的去年同期。回滚即 revert。compare-to.ts的lastPeriodBefore(规范没有「前两期」的宏,窗口是算出来的);② 同文件rollingPair的后向分支(N+1 天整体后移);③previousYear的日期夹取。pnpm --dir ui exec vitest run packages/core/src/utils/__tests__/dashboard-filters.presetWindows-29116.test.ts,预期 16 个预设全部通过,每个预设的上一期都在本期开始前一天结束。Clause-②: no
Metadata-protocol: none
What changes
@object-ui/coreshiftFilterByCompareTo,kind: 'previousPeriod'.{yesterday}andlast_week_*/last_month_*/last_quarter_*/last_year_*were never substituted, so theyesterday,last_week,last_month,last_quarterandlast_yearpresets compared the window with itself. Now{yesterday}becomes{2_days_ago}, and eachlast_*token becomes the period before last.DATE_MACRO_TOKENS(packages/spec/src/data/date-macros.zod.ts) stops atlast_*, and the parameterised grammar ({N_weeks_ago},{N_months_ago}) counts from today, not from a period's first day, so no declared token names the month before last.lastPeriodBeforetherefore computes the day: it resolves thelast_*START throughresolveDateMacros(the display zone, like every other token), moves it back one week / month / quarter / year with UTC calendar arithmetic, and takes the day before thatlast_*start as the end. The result is an ISO day, whichresolveDateMacrospasses through. No token is invented.rollingPair(wasforwardRollingPair) now also matches{N_days_ago}with{today}. That window is N + 1 days (last_7_daysat 2026-07-15 is 07-08..07-15, measured), and moves back by N + 1:{(2N+1)_days_ago}…{(N+1)_days_ago}. It used to become{N_days_ago}…{yesterday}, N days overlapping the current window. The forward branch now writes{1_day_ago}instead of{yesterday}, because{yesterday}is now itself moved; the resolved window is unchanged.substituteTokensnow takes a replacer), sotoday→yesterdayis never carried on to2_days_ago.kind: 'previousYear'builtnew Date(y - 1, 1, 29), which is 1 March, so every window seen from 2028-02-29 was re-resolved at 2027-03-01 (this_monthcompared with March 2027). The day is clamped to the shifted month's length, 28 February.compareToTrendLabelKey: a{yesterday}orlast_*token, and a backward rolling window, readvsPreviousPeriod(they readvsYesterday,vsLastWeek,vsLastMonth,vsLastQuarter,vsLastYear). No existingdashboard.trend.*key names "the month before last", andvsPreviousPeriod("vs previous period", 较上期) is exact for each, so no new key, no locale or fallback change. The check runs first, sincelast_month_startalso containsmonth_start.NEXT_TO_CURRENT_TOKENS(my fix(core): compareTo on a forward date range (next month, next quarter, next 30 days) compares with the period just before it, not with itself #30196 text): it saidnext_week_*/next_year_*have no_endin the macro vocabulary. The spec declaresnext_week_endandnext_year_end; it is this package's resolver (date-macros.ts) that lacks them. The comment now says so; the mapping is unchanged.Why
#30197, filed from #30196's Acceptance notes. Governing text: the
compare-to.tsdocblock, "kind: 'previousPeriod'— the equal-length window immediately before the current one", andpreviousYear= "same week / month / quarter, one year earlier". No spec change, no newcompareTokind, no executor change.Tests
dashboard-filters.presetWindows-29116.test.ts: the compareTo case pins all 16 presets at 2026-07-15 (both kinds and the label); the fivelast_*/yesterdayrows and the threelast_N_daysrows move, the eight others keep fix(core): compareTo on a forward date range (next month, next quarter, next 30 days) compares with the period just before it, not with itself #30196's values. New for every preset on all six reference dates: the previous window ends the day before the current window starts, with the same day count for a day, a week or a rolling window, and from the 1st for a month, quarter or year. New for every preset:previousYearfrom 2028-02-29 equals resolving the filter at 2027-02-28.compare-to.test.ts: yesterday, last week, last month (also from 2026-03-31, February then January), last quarter and last year across a year boundary,{7_days_ago}…{today}and a$between{30_days_ago}…{today}, a mixedlast_month_start…current_month_endwindow moved bound by bound, the leap-daypreviousYearcase, and the labels (a lone{today}still readsvsYesterday).ObjectMetricWidget.compareTo.pastPresets-30197.test.tsx(rendered, the registeredobject-metricblock, the fix(core): compareTo on a forward date range (next month, next quarter, next 30 days) compares with the period just before it, not with itself #30196 harness):last_month(上月),yesterdayandlast_7_dayseach show20%against exactly the expected previous window, under "vs previous period", and not the stale label.Acceptance notes
tsxprobe of 16 presets × 8 reference dates × 2 kinds plus labels,mainff12aed3against this branch. Unchanged:this_quarter,this_year,next_quarterin full;today,this_week,this_month,next_month,next_30_daysin every row exceptpreviousYearat 2028-02-29 (the leap-day fix; e.g.this_month2027-03-01..03-31 → 2027-02-01..02-28). Changed as intended:yesterday,last_week,last_month,last_quarter,last_year,last_7_days,last_30_days,last_90_days(previousPeriod rows and label, plus their 2028-02-29 previousYear row where it moves).last_30_daysat 2026-07-15: this branch 2026-05-15..06-14; the executor (shiftRange, measured on Dashboard compareTo on a forward date preset (下月, 下季度, 未来 30 天) compares the window with itself #30140) 2026-05-15..06-14. On calendar presets the two still differ by design: the executor counts days, the inline path steps whole periods.next_week_end/next_year_end, which the spec declares (see the docblock correction above).Verification
Suites, type-check, lint, ablations
os-verify-lock:pnpm --dir ui exec vitest run --maxWorkers=3 packages/core/exit 0 (232 files, 4,321 passed, 27 skipped);packages/plugin-dashboard/exit 0 (202 files, 1,928 passed, 6 skipped).pnpm run type-checkin core and plugin-dashboard: exit 0.npx eslinton the touched files: 0 errors (warnings only,no-explicit-any, as in the surrounding code).scripts/ablation-replace.mjs, each red then restored to HEAD):lastPeriodBeforenot called): 12 failed, covering the five past-token pins, the five 29116 rows, and the renderedlast_monthandyesterdayrows;ROLLING_DAYS_RElimited tofrom_now): 6 failed (the rolling pin, the label pin, the threelast_N_daysrows, the renderedlast_7_daysrow);previousYearwindow moves);dispatch-gates --commands, 35): see the report on Inline compareTo previousPeriod: backward presets (上月, 上季度, 昨天, 上周, 去年) compare a window with itself, last_N_days compares N+1 days with N #30197.Human Minimum
packages/specholds no runtime logic. (not touched)main, one pull request.packages/spectouched: n/a.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01WGufzijmF7yUSk5ga9jRkh