You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Dashboard compareTo on a forward date preset (下月, 下季度, 未来 30 天) compares the window with itself #30140
Filing gate: ③ a should-fix from the contract review of PR #30133 (#30076, review 6634808446), carried as a follow-up so the spec PR stays in scope. ⛔ Not a claim. Suggested-grade: p2, because a dashboard shows a wrong number and a wrong label once #30133 lands. Route: domain:ui.
What a user sees.#30133 adds three forward presets: next_month (下月), next_quarter (下季度) and next_30_days (未来 30 天). A dashboard widget that picks one of them and turns on "compare to previous period" shows a change of 0 every time. The trend label also names the wrong comparison, "vs last month".
Why. On PR #30133's head, ui/packages/core/src/utils/compare-to.ts ≈:55-62 builds previousPeriod by substituting current_* and today tokens with last_* and yesterday. A forward window is spelled in next_* or {N_days_from_now} tokens, so nothing is substituted, and the "previous" window is the window itself. The label is taken from the token text (≈:129-132): month → vsLastMonth. The PR's dashboard-filters.presetWindows-29116.test.ts runs its compareTo case over the 13 earlier presets only (RETIRED_PRESETS, ≈:135-165), so nothing pins the three new ones.
Wanted
Decide what "previous period" means for a forward window. The natural reading is the equal-length window just before it. For 下月 that is this month, for 下季度 this quarter, and for 未来 30 天 the 31 days ending yesterday. Implement it, and make the trend label name that comparison.
Extend the 29116 compareTo case to all 16 presets.
Claim: PM loop round 1
Session: session_01WGufzijmF7yUSk5ga9jRkh
Account: os-support-ai (the seat's linked user as GET /user answers it; always the card's assignee)
Branch: claude/project-thread-6kk1x6
Worktree: objectstack-issue-30140
Domain: domain:ui
Seat: domain:ui#1
File surface: ui/packages/core/src/utils/compare-to.ts, its tests (incl. dashboard-filters.presetWindows-29116.test.ts), dashboard.trend.* locale strings, one root .changeset/ file; ⛔ no spec or server change (stop on breach; explain in the report)
Container & model: M, mode:thread, model: TIER_DEFAULT (p2, judgment card), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the ui inline compare-to resolver (compare-to.ts) produces the wrong window | no platform path covers forward windows on the inline path | any dashboard author picking 下月/下季度/未来 30 天 with compare-to, since #30133 (unreleased)
Thread-read: 6638004233
Premise: holds
Serial constraints cleared: none — no open PR touches compare-to.ts (read this act); #30133 (forward presets) merged.
MERGED ff12aed37b at 2026-11-05T02:20:32Z, via the merge queue (seat ACCEPT 6647590904)
card
closed completed by Fixes #30140
content on origin/main
NEXT_TO_CURRENT_TOKENS and vsThisMonth / vsThisQuarter present in ui/packages/core/src/utils/compare-to.ts
Forward presets (下月, 下季度, 未来 30 天) now compare with the equal-length window just before them on the inline path (object-metric block, provider: 'object' chart series); the dataset executor was already right (measured, unchanged).
Activity
objectstack-fleet commentedon Nov 4, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: first-touch audit · p2 kept ·
domain:uikept ·pm:queue→pm:blocked· 2026-11-04T16:48Z⛔ Not a claim.
compare-to.ts). The card statesBlocked-by: #30076, which is open, so it ispm:blocked.pm:blockinggoes on [Decision] Relative dates look only backward: add 下月, 下季度 and 未来 N 天 for forecasting? #30076.Generated by Claude Code
objectstack-fleet commentedon Nov 4, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: unblocked ·
pm:blocked→pm:queue· 2026-11-04T17:55Z⛔ Not a claim.
Blocked-by: #30076is met: [Decision] Relative dates look only backward: add 下月, 下季度 and 未来 N 天 for forecasting? #30076 is closed, and its forward presets landed (aa57c760). p2,domain:ui, back in the queue.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:ui#1 · os-support-ai · session_01WGufzfE4V9fzZgJLrLDmMC
Claim: PM loop round 1
Session:
session_01WGufzijmF7yUSk5ga9jRkhAccount:
os-support-ai(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/project-thread-6kk1x6Worktree:
objectstack-issue-30140Domain:
domain:uiSeat:
domain:ui#1File surface:
ui/packages/core/src/utils/compare-to.ts, its tests (incl.dashboard-filters.presetWindows-29116.test.ts),dashboard.trend.*locale strings, one root.changeset/file; ⛔ no spec or server change (stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT(p2, judgment card),effort: highClause-②: no
Metadata-protocol: none
Responsibility: the ui inline compare-to resolver (
compare-to.ts) produces the wrong window | no platform path covers forward windows on the inline path | any dashboard author picking 下月/下季度/未来 30 天 with compare-to, since #30133 (unreleased)Thread-read: 6638004233
Premise: holds
Serial constraints cleared: none — no open PR touches
compare-to.ts(read this act); #30133 (forward presets) merged.objectstack-fleet commentedon Nov 5, 2026
domain:ui#1 · os-support-ai · session_01WGufzijmF7yUSk5ga9jRkh
os-dev-report
Stamp: 2026-11-05T01:43Z
{ "card": 30140, "pr": 30196, "branch": "claude/project-thread-6kk1x6", "head": "98450bd1b845ad39627d548fc5f65c9bb4ec94d0", "gates": { "derived_reconciliation": "dispatch-gates --ran: 35 derived, 35 run, 0 NOT-MEASURED (derived set re-read on the merged head: same 35)", "derived": [ "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0", "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0", "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0", "node scripts/check-closing-keyword-parity.mjs :: exit 0", "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0", "node scripts/check-comment-mask-corpus.mjs :: exit 0", "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0", "node scripts/check-empty-changeset.mjs --self-test :: exit 0", "node scripts/check-sdui-manifest.mjs :: exit 0", "node scripts/check-sdui-manifest.mjs --self-test :: exit 0", "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0", "node scripts/release-pending-publish.mjs --self-test :: exit 0", "pnpm --dir ui exec vitest run scripts/ :: exit 0", "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0", "pnpm check:changeset-gate-self-tests :: exit 0", "pnpm check:closed-ceremony-text :: exit 0", "pnpm check:cross-package-test-inputs :: exit 0", "pnpm check:dispatcher-error-vocabulary :: exit 0", "pnpm check:driver-memory-census :: exit 0", "pnpm check:engine-double-contract :: exit 0", "pnpm check:gitlink-declared :: exit 0", "pnpm check:nul-bytes :: exit 0", "pnpm check:published-files :: exit 0", "pnpm check:query-options-erasure :: exit 0", "pnpm check:refd-timer-probe :: exit 0", "pnpm check:registry-log-declared :: exit 0", "pnpm check:rest-log-spy-declared :: exit 0", "pnpm check:skill-identifier-liveness :: exit 0", "pnpm check:test-source-alias :: exit 0", "pnpm check:tier-file-adoption :: exit 0", "pnpm check:type-check-coverage :: exit 0", "pnpm check:type-check-debt :: exit 0", "pnpm check:undeclared-dep-imports :: exit 0", "pnpm check:watch-hint-literal :: exit 0", "pnpm check:where-matcher :: exit 0" ], "local_suites": [ "pnpm --dir ui exec vitest run --maxWorkers=3 packages/core/ :: exit 0", "pnpm --dir ui exec vitest run --maxWorkers=3 packages/i18n/ :: exit 0", "pnpm --dir ui exec vitest run --maxWorkers=3 packages/plugin-dashboard/ :: exit 0 (201 files, 1925 passed, 6 skipped)", "pnpm --dir ui exec vitest run --maxWorkers=3 packages/plugin-charts/ :: exit 0 (103 files, 1333 passed, 9 skipped)", "type-check @object-ui/core, @object-ui/i18n, @object-ui/plugin-dashboard, @object-ui/plugin-charts :: exit 0 each", "npx eslint (every touched file, from its package dir) :: exit 0, 0 errors", "ablation 1 (previousPeriod back to CURRENT_TO_LAST_TOKENS on the raw filter) :: 11 failed / 70 passed, restored", "ablation 2 (drop the next_quarter_ label check) :: 3 failed / 78 passed, restored", "post-merge of origin/main bedb96e0 on head 98450bd1: i18n suite (95 files) + the 3 compareTo test files (81 tests) + i18n type-check :: exit 0" ] }, "line_budget": { "diff": "+466 / -18, 19 files", "ratcheted_files_touched": "none (skills/** untouched)", "breakdown": "compare-to.ts +118/-4; tests +299/-14 across 3 files; 10 locale packs +2 each; fallbacks +10 across 3 widget files; plugin-dashboard SKILL.md +3; changeset +16" }, "deviations": [ "File surface beyond the Claim and the PM assumption (\"compare-to.ts plus locale strings and tests\"): the two new trend keys also need their English fallback rows in plugin-dashboard ObjectMetricWidget.tsx (+2) and MetricWidget.tsx (+6, defaults and phrase-to-key map) and plugin-charts ObjectChart.tsx (+2), and the plugin-dashboard SKILL.md label table (+3); a rendered test was added in plugin-dashboard. The changeset names all four packages (patch). The seat may amend the Claim file surface.", "Premise narrowed, measured: a dashboard metric widget is dataset-bound (DashboardRenderer to DatasetWidget; the analytics executor shiftRange shifts it, label from kind alone). The inline shiftFilterByCompareTo path that compared a forward window with itself is the object-metric block and provider object chart nodes. Executor probe: no forward window compares with itself; next_30_days previous window equals this PR inline window. Details in PR Acceptance notes; not changed here.", "Rendered unit check instead of a browser screenshot (no 30140-shots): the dashboard metric widget the console would show runs the dataset path this PR does not touch; the rendered test drives the registered object-metric block, its two aggregate calls and its trend badge (20%, vs this month).", "The first ablation-replace run restored compare-to.ts to its HEAD blob (then main), discarding the uncommitted fix; the fix was re-applied from the same edit text, a tsx probe of 16 presets x 8 dates x 2 kinds matched the pre-ablation output byte for byte, and the work was committed before ablation 2.", "Merged origin/main (11 commits, all ten locale packs moved upstream; auto-merged) before the push; full package suites and the 35 gates ran on the pre-merge commit fa390d3a, the post-merge re-run is listed under local_suites.", "The harness asked to set the PR assignee and reviewer through GitHub MCP; skipped per the order (no MCP writes, no assignee, no reviewer).", "Out-of-scope findings (pre-existing, kept by the CONTROL): inline previousPeriod on yesterday / last_week / last_month / last_quarter / last_year compares a window with itself; last_N_days compares N+1 days with N; previousYear from 2028-02-29 re-resolves at 2027-03-01 (this_month compares with March 2027). Evidence in PR Acceptance notes; dedupe words: compareTo previousPeriod last_month itself, compare-to leap day previousYear, last_7_days previous window length." ], "files_changed": [ ".changeset/30140-compare-to-forward-presets.md", "ui/packages/core/src/utils/compare-to.ts", "ui/packages/core/src/utils/__tests__/compare-to.test.ts", "ui/packages/core/src/utils/__tests__/dashboard-filters.presetWindows-29116.test.ts", "ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts", "ui/packages/plugin-charts/src/ObjectChart.tsx", "ui/packages/plugin-dashboard/SKILL.md", "ui/packages/plugin-dashboard/src/MetricWidget.tsx", "ui/packages/plugin-dashboard/src/ObjectMetricWidget.tsx", "ui/packages/plugin-dashboard/src/__tests__/ObjectMetricWidget.compareTo.forwardPresets-30140.test.tsx" ] }Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:ui#1 · os-support-ai · session_01WGufzfE4V9fzZgJLrLDmMC
Landed · PR #30196 · 2026-11-05T02:21Z
ff12aed37bat 2026-11-05T02:20:32Z, via the merge queue (seat ACCEPT 6647590904)completedbyFixes #30140origin/mainNEXT_TO_CURRENT_TOKENSandvsThisMonth/vsThisQuarterpresent inui/packages/core/src/utils/compare-to.tsobject-metricblock,provider: 'object'chart series); the dataset executor was already right (measured, unchanged).last_N_dayson the same function), unblocked by this landing.pm:dispatchedremoved in the same stroke.