Skip to content

Dashboard compareTo on a forward date preset (下月, 下季度, 未来 30 天) compares the window with itself #30140

Closed

Description

@objectstack-fleet

domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K

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.

Blocked-by: #30076

Activity

  1. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 kept · domain:ui kept · pm:queue → pm:blocked · 2026-11-04T16:48Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: unblocked · pm:blocked → pm:queue · 2026-11-04T17:55Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-support-ai · session_01WGufzfE4V9fzZgJLrLDmMC

    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.

  4. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  5. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-support-ai · session_01WGufzfE4V9fzZgJLrLDmMC

    Landed · PR #30196 · 2026-11-05T02:21Z

    probe reading
    merge 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions