Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

console(dashboard): a dataset widget's compareTo previousPeriod is labelled "vs yesterday" — the label is guessed from {today} in the raw filter while the executor compares the whole preceding window #11632

Closed

Description

@objectstack-fleet

QA-source: objectstack-ai/objectstack#21782 · dashboards.chart-type-matrix · outside the item's clauses

A defect found while running dashboards.chart-type-matrix (outside the item's clauses) surfaced in the ObjectStack 17.7 pre-release checklist run objectstack-ai/objectstack#21782 (framework subject 316be321e, console pin 2e818d0b51ec). An independent verifier (VF3, RUNNER rule 7; code only) confirmed it: P3 (label only; the comparison values are right). It predates the 17.6.0 console pin 31971ff1e; no open duplicate was found. Owner: objectui.

Reproduction

  1. As admin, PUT /api/v1/meta/dashboard/qa_compareto_probe?mode=draft with:
    • dateRange:{field:'created_at', defaultRange:'last_30_days'};
    • a metric widget on dataset showcase_task_metrics, values:['task_count'], compareTo:{kind:'previousPeriod'}.
  2. POST /api/v1/meta/dashboard/qa_compareto_probe/publish.
  3. Server truth: the dataset query's timeDimensions dateRange is [2026-09-04, 2026-10-04], and task_count__compare is 1, so the previous 30 days.
  4. Browser: /_console/apps/showcase_app/dashboard/qa_compareto_probe.
  5. Expected: "vs previous period".
  6. Actual: the metric reads "9 ↑800%" "vs yesterday", and the line legend reads "Tasks · vs yesterday".

Mechanism

  • packages/core/src/utils/compare-to.ts:124-136 compareToTrendLabelKey regex-sniffs the raw filter for macro tokens (\btoday\b → vsYesterday).
  • plugin-dashboard/src/DatasetWidget.tsx:1097 reuses it on the ADR-0021 dataset path, where the framework executor shifts the dimension window to the equal-length window before it (packages/services/service-analytics/src/dataset-executor.ts:810-819 shiftRange).
  • The heuristic is faithful only on the inline path (compare-to.ts ~100-118). The same code is at 31971ff1e (DatasetWidget.tsx:995).

Done when

On the dataset path the label comes from the compareTo kind and the resolved window, not from filter-token sniffing (pinned).


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: business reports | 缺项 (dashboards.chart-type-matrix found it outside its clauses; no item asserts a dataset widget's compareTo label) | P2

    Triage: first grade — bug · priority:p3 · domain:ui · area:reports · pm:queue. On the dataset path, the label comes from the compareTo kind

    Triage: lands in packages/plugin-dashboard/src/DatasetWidget.tsx ⇒ domain:ui; rationale: the executor's values are right; only the client label guesses.

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-05T02:05Z. ⛔ Not a claim, ⛔ not a dispatch.

    • Direction. DatasetWidget.tsx (about :1097) takes its label from compareTo.kind, so previousPeriod reads "vs previous period", not from compareToTrendLabelKey's token sniffing. The inline path keeps its heuristic, which is faithful there.
    • Why p3. Label only; the compared values are right. The verifier graded it P3.
    • Serial: objectui#11095 is in flight on plugin-dashboard's dataset KPI tile. The claim reads its file list.

    Generated by Claude Code

  2. added
    area:reportsBusiness reporting — dashboards, reports, the numbers a manager reads
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 5, 2026
  3. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2
    Session: session_015W8GBu6sBiqus2L2xjMsAL
    Account: os-steve
    Branch: claude/issue-11632-dataset-compare-label
    Worktree: objectui-issue-11632
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: packages/plugin-dashboard/src/DatasetWidget.tsx (the compareTo trend label on the dataset path, about :1097), the DatasetWidget tests beside it, and .changeset/11632-*.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default tier (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; floor sonnet · default opus · ceiling fable)
    Clause-②: no
    Thread-read: 5986877469
    Serial constraints cleared: triage's named neighbour, objectui#11095, landed as 22ddcd5 (PR objectui#11635) and changed no DatasetWidget.tsx line, read 2026-10-05T06:36Z. No open objectui PR touches packages/plugin-dashboard. The in-flight objectui#11626, objectui#11642 and objectui#11627 declare other files.

    Why Clause-②: no: on the dataset path the trend label is taken from compareTo.kind instead of from filter-token sniffing (triage 5986877469). The inline path keeps its heuristic, and nothing in a published accept set or public surface widens. The dispatch fences any new export, prop, type member or i18n key: a route that needs one stops and reports.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 11632,
    "status": "done",
    "branch": "claude/issue-11632-dataset-compare-label",
    "pr": "#11647",
    "session": "session_015W8GBu6sBiqus2L2xjMsAL (subagent run, so this is the parent seat's id)",
    "premise_still_valid": true,
    "summary": "On the ADR-0021 dataset path, DatasetWidget names a comparison window from compareTo.kind alone: previousPeriod reads 'vs previous period' and previousYear reads 'vs last year'. A module-local COMPARE_KIND_TREND_KEY, typed with satisfies against a Record keyed by CompareToConfig['kind'], replaces the call to compareToTrendLabelKey(compareTo, rawFilter), which guessed the window from the filter's macro tokens. compareToTrendLabelKey and the inline path are untouched, and TREND_LABEL_DEFAULTS is unchanged because check:i18n-keys reads it as the dashboard.trend. vocabulary. That one compareLabel feeds every comparison surface: the KPI delta, the table comparison column and CSV header, the cross-tab caption and title, and the chart comparison series. The PR body records what the resolved window would add: a length needs a new interpolated i18n key, which the Clause-② fence forbids, and a calendar name would re-derive the executor's shiftRange in the renderer. It also records why the kind alone gives a faithful label for every window, as Zone 2 item 3 asked. Zone 2 readings: (1) holds: shiftRange at objectstack 07bf21ff moves the whole window (previousPeriod is the equal-length window ending the day before, previousYear the same window a year back). (2) The installed @objectstack/spec 17.6.0 declares exactly previousPeriod and previousYear (DashboardWidgetSchema.compareTo.kind and DatasetCompareToSchema). Both keys, vsPreviousPeriod and vsLastYear, already exist in all 10 locales, so no key was added. (4) The other compareToTrendLabelKey callers, ObjectMetricWidget and ObjectChart, are inline-path only; ObjectChart's dataset branch forwards no compareTo. (5) The live run was done: before and after against objectstack main 07bf21ff, see tests.",
    "tests": "All at HEAD 95f2df9, under os-verify-lock (VERDICT command-exit 0, held 553s, waited 332s, shared box). (a) 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)'. (b) pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-dashboard^...' build (13 packages): exit 0. (c) pnpm --filter @object-ui/plugin-dashboard type-check: echoed 'tsc --noEmit && tsc -p tsconfig.test.json', exit 0. (d) pnpm --filter @object-ui/plugin-dashboard lint: exit 0, '0 errors, 546 warnings', none of them on a touched line. REVERSE VERIFICATION, run from committed state: git checkout BASE -- DatasetWidget.tsx. The mutated blob hash equalled the base blob (a27ff8c3...), COMPARE_KIND_TREND_KEY counted 0 and 'compareToTrendLabelKey(compareTo, rawFilter)' counted 1. Verbose runs of DatasetWidget.compareTo.test.tsx: HEAD gave 'Tests 31 passed (31)'; reverted gave 'Tests 4 failed | 27 passed (31)'. The direction was the expected turn-red: all 4 failures are in the new objectui#11632 block, receiving 'Revenue · vs yesterday', '20%vs yesterday' and '20%vs last quarter'. The previousYear case and the spec-coverage case stayed green, since previousYear was already labelled by its kind. A trap restored HEAD, proved by blob d998dc62... equal to the HEAD blob and an empty git diff HEAD. Single-file test, imported relatively, so no dist preflight applies. LIVE: objectstack main 07bf21ff showcase (objectstack dev --fresh -p 4632, own worktree built with turbo --filter '@objectstack/example-showcase^...', 60/60 tasks), with the card's probe dashboard PUT as a draft and published (200/200). Consoles from source on 5633 (base 76993f8) and 5632 (this branch), Playwright, Chromium /opt/pw-browsers. Base: KPI trends ['800%vs yesterday', '100%vs last year'], legend 'Tasks · vs yesterday'. Branch: ['800%vs previous period', '100%vs last year'], legend 'Tasks · vs previous period'. Both sent identical queries: timeDimensions created_at ['2026-09-05','2026-10-05'] plus the compareTo kind. Server rows {task_count 9, task_count__compare 1}. Discriminator: the 8-day window 2026-09-28..2026-10-05 with previousPeriod gave {4, compare 3}, while 2026-09-20..27 alone counted 3 and yesterday alone counted 1. Lockless gates, all exit 0, on bytes identical to 95f2df9: check:spec-symbols, check:new-line-citations (0 new), check:control-bytes, check:i18n-keys, check:i18n-dead-keys, 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, check-changeset-presence, check-changeset-no-major. Inline-path pins unchanged and inside run (a): core compare-to.test ({today} gives vsYesterday) and ObjectMetricWidget.compareTo ('labels vs last quarter'). CI at report time: 42 check runs, 20 success, 3 skipped, 19 in_progress, 0 failed. in_progress is reported as read, with no wait.",
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "3 REST writes, all through the fleet-write relay (each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls (draft #11647; read-back identical, 9472 bytes); (2) label-write --assign os-steve → POST /repos//issues/11647/assignees (read-back MATCHES); (3) this os-dev-report → POST /repos//issues/11632/comments. Not REST: two git pushes of claude/issue-11632-dataset-compare-label (the empty probe, then 95f2df9). Local backend only, not GitHub: PUT and publish of the probe dashboard on my own localhost:4632.",
    "open_questions": [],
    "gates": {
    "vitest packages/plugin-dashboard/ + core compare-to.test": 0,
    "build closure @object-ui/plugin-dashboard^...": 0,
    "plugin-dashboard type-check": 0,
    "plugin-dashboard lint": 0,
    "ablation DatasetWidget.compareTo (HEAD green / reverted red)": "0 / 1",
    "check:spec-symbols": 0,
    "check:new-line-citations": 0,
    "check:control-bytes": 0,
    "check:i18n-keys": 0,
    "check:i18n-dead-keys": 0,
    "check:changeset-claims": 0,
    "check:pending-changeset-literals": 0,
    "check:test-path-roots": 0,
    "check:vi-mock-specifiers": 0,
    "check:vi-mock-inherit": 0,
    "check:vi-mock-override-shape": 0,
    "check:phantom-deps": 0,
    "check:unused-deps": 0,
    "check-changeset-presence": 0,
    "check-changeset-no-major": 0,
    "CI": "in_progress (20 success, 3 skipped, 19 in_progress, 0 failed at report time)"
    },
    "line_budget": "n/a — no skills/** or governed file touched",
    "files_changed": [
    "packages/plugin-dashboard/src/DatasetWidget.tsx (+36 -5)",
    "packages/plugin-dashboard/src/tests/DatasetWidget.compareTo.test.tsx (+114 -18)",
    ".changeset/11632-dataset-compare-label.md (+9, patch @object-ui/plugin-dashboard)"
    ],
    "deviations": [
    "No merge commit: origin/main was still the base 76993f8 when the PR opened (ls-remote checked twice), so 'git merge origin/main' answered 'Already up to date'. The runs above are of the tree a merge would have produced.",
    "Live run scaffolding outside the claim's file surface, nothing committed: a detached objectstack worktree at 07bf21ff and a detached objectui worktree at the base (for the before console). Both were removed after the run, the backend's --fresh temp DB was confirmed deleted, and every server I started was stopped by its recorded PID. My objectui worktree was removed after the PR opened.",
    "REPORTING: the harness attribution reminder asked for a model-named Co-Authored-By trailer. The commits carry the model-free pair (Claude-Session plus Co-authored-by: Claude) that objectui AGENTS.md and os-dev.md prescribe.",
    "The card's Done-when names 'the compareTo kind and the resolved window'. The kind alone was taken, per triage's direction and Zone 2 item 3, and the window's possible additions are written up in the PR body, not raised as an open question."
    ],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted in PR Acceptance notes, not filed (a read-only inference, no public-door measurement). Inline previousPeriod over a rolling range: shiftFilterByCompareTo rewrites {today} to {yesterday} but leaves {30_days_ago}, so a last_30_days filter compares [30 days ago, yesterday]. That overlaps the current window and is labelled 'vs yesterday', which is not the equal-length-before window that CompareToConfig's docblock and the spec's DatasetCompareTo describe. Dedupe words: shiftFilterByCompareTo, previousPeriod rolling, 30_days_ago, inline compareTo window.",
    "carrier: 承接者:无 · noted in PR Acceptance notes, not filed (read from source, no producer looked for). ObjectChart's dataset branch sends no compareTo to queryDataset and builds the comparison series only for an aggregate chart, so a dataset-bound chart block with compareTo would draw no comparison and say nothing. Dedupe words: ObjectChart dataset compareTo, queryDataset compareTo, comparison series dataset chart."
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR objectui#11647 → main e398a54, verified by content

    domain:ui execution seat 1 @ objectui · session_015W8GBu6sBiqus2L2xjMsAL (os-steve) · 2026-10-05T08:20Z.

    • Merged through the merge queue as squash commit e398a54 (one parent, 531b26c), an ancestor of origin/main. Its +/- lines are identical to the PR head 95f2df9 diffed from its merge base: 3 files, +159/−23.

    • Content check against the first parent:

      reading 531b26c e398a54
      COMPARE_KIND_TREND_KEY in plugin-dashboard DatasetWidget.tsx 0 3
      compareToTrendLabelKey(compareTo, rawFilter) in DatasetWidget.tsx 1 0
      .changeset/11632-dataset-compare-label.md exists no yes
      export function compareToTrendLabelKey in core utils/compare-to.ts (control: the inline path is untouched) 1 1
    • The card closed completed through the PR's Fixes line. It was the only issue closed in that window. pm:dispatched is removed in this stroke.

    • Carried by the seat, not filed here (no reach measured; both are in the PR's Acceptance notes):

      • An inline previousPeriod over a rolling range compares an overlapping window.
      • ObjectChart's dataset branch forwards no compareTo.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:reportsBusiness reporting — dashboards, reports, the numbers a manager readsbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions