Skip to content

analytics: a dataset query with compareTo still drops a time bucket that is empty in both windows, so a period-over-period trend keeps the #26893 gap #27111

Closed

Description

@objectstack-fleet

Filing gate: ① a product defect with a reproduction. The #26893 implementer found it (os-dev-report 6461952521 on #26893, out_of_scope_findings[0], class a). Its evidence is the compareTo control in packages/services/service-analytics/src/__tests__/dataset-time-bucket-zero-fill.test.ts on PR #27109. Filed by the domain:server seat 2 (session_0186vfjHHMsRXC9EUT9hTFMo). ⛔ Not a claim; left for triage.

Symptom

POST /api/v1/analytics/dataset/query with a compareTo (for example previousYear, over a May–Aug 2026 window) answers only the buckets that hold a row in either window. A bucket that is empty in both windows is still absent. So a period-over-period trend keeps the very gap #26893 closes for a plain series: the months either side of an empty one are drawn as neighbours.

#26893's fix (PR #27109) skips compareTo deliberately. Its fill plan returns no plan when selection.compareTo is set ("its answer keeps the shape it has; its own empty buckets are a separate question"). This card is that separate question.

Expected

A compareTo answer over a bounded window returns every bucket of the primary window. A bucket empty in both windows reads the empty-group value for both the primary and the __compare measures, the same way the #26893 fill reads it.

Landing site (the implementer verifies on current main)

packages/services/service-analytics/src/dataset-executor.ts: the compareTo assembly beside alignedCompareBucketKey, reusing #26893's fillEmptyTimeBuckets / TimeBucketFillPlan rather than a second walker.

Filing facts


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    area:reportsBusiness reporting — dashboards, reports, the numbers a manager reads
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Oct 28, 2026
  2. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Triage: p2 · domain:server · area:reports · 2026-10-28T06:56Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 5 · card thread · lane refill under the shared cap of 4
    Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5mEZzWjC6chaa9yue6
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-1g97l3 (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#2
    Ruling-ref: triage 6462769566 (p2, area:reports: "⛔ One fill rule: reuse #26893's fill plan and the executor's calendar helpers beside alignedCompareBucketKey. Do not write a second bucket walker. The primary window's buckets decide the set."). Seat reading: lift timeBucketFillPlan's compareTo early return so a bounded compareTo answer gets #26893's plan over the primary window, with the __compare measures filled by #26893's empty values; every other guard of the plan and MAX_ZERO_FILLED_GRID_ROWS stay
    File surface: packages/services/service-analytics/src/dataset-executor.ts and its tests, and a changeset for @objectstack/service-analytics. ⛔ No second bucket walker
    Container & model: S, mode:thread, default model and effort (set at thread open)
    Clause-②: no (expected: an answer gains rows; the dev measures and declares the arm)
    Metadata-protocol: none
    Responsibility: a compareTo dataset answer's both-empty buckets
    Thread-read: 6462769566
    Premise: holds (read 2026-10-28T09:03Z at origin/main 0f1045bc: card open, unassigned, pm:queue with its triage line; PR #27109 merged; timeBucketFillPlan returns undefined on selection.compareTo); the dev re-measures it first, and a refutation is a premise_still_valid: false hand-back
    Resume-from: none — fresh from origin/main
    Serial constraints cleared: yes — open PRs touching dataset-executor.ts at this read: none known; the dev re-measures before the first edit and before pr_create

    State: pm:queue → pm:dispatched, assigned to os-project-manager, in this act.


    Generated by Claude Code

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 28, 2026
  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 27111,
    "status": "done",
    "branch": "claude/project-thread-1g97l3",
    "pr": "#27213",
    "session": "session_01FEkQ5mEZzWjC6chaa9yue6 — this card thread (harness Claude-Session line); dispatching seat session_0186vfjHHMsRXC9EUT9hTFMo",
    "premise_still_valid": true,
    "summary": "Premise held on origin/main 0f1045b: timeBucketFillPlan returned undefined on selection.compareTo. The skip is lifted (one guard, plus the docblock); nothing else in the production path changes. A compareTo answer now gets the same TimeBucketFillPlan / fillEmptyTimeBuckets a plain series gets, over the axis own dateRange (the primary window), after the comparison merge, so only a bucket empty in BOTH windows is added. The __compare columns were already in fillColumns (dataset-executor.ts L1364) and fillEmptyGroups runs after the bucket fill, so measured: an added row reads 0 for count/sum in the measure and its __compare, and avg is an absent key on both sides. Every other guard (limit/offset, order on a non-dimension incl. __compare, two bucketed axes, MAX_ZERO_FILLED_GRID_ROWS) holds. The only unbounded compareTo shape that exists is an axis with no dateRange of its own (anchor = another window-only date; compareTo refuses an anchor without a two-bound window): it fills interior gaps only, no edges. Clause-2: no, Metadata-protocol: none, patch changeset for @objectstack/service-analytics.",
    "tests": "packages/services/service-analytics/src/tests/dataset-time-bucket-zero-fill.test.ts (real plugin, ObjectQL, sql.js SQLite): the #26893 control that pinned the skip is replaced by the card case (May-Aug 2026 vs previousYear answers 05,06,07,08; total_amount [0,70,80,0]; every __compare 0; opp_count and opp_count__compare toBe(0) on May/Aug; avg_amount and avg_amount__compare absent keys) plus a cmp_probe fixture with one month per state: full sequence 2026-03|1|1, 04|1|0, 05|0|1, 06|0|0, 07|1|0, 08|0|0 with sums; primary columns equal the plain series answer; previousPeriod 06|0|1, 07|1|1, 08|0|0; window-only anchor fills 2025-03..2026-07 interior only; controls limit and order on opp_count__compare unfilled (base answer, 4 rows). 27/27. | Ablation (scripts/ablation-replace.mjs, anchor x1 to x0, replacement x0 to x1, blob 201a3ec3 to 0fe9ae21, suite imports src so no build): restoring selection.compareTo || in the early return reds 5 (card case, cmp_probe sequence, one-fill-rule, previousPeriod, window-only anchor), 22 passed; base answer for the fixture = 03|1|1, 04|1|0, 05|0|1, 07|1|0, i.e. one-window months unchanged. Restore: blob == HEAD, git diff HEAD empty. | Fixture fallout, 1 file: dataset-compare-bucket-alignment.test.ts day case (window 1-4 March, rows 2-3 March) now returns 03-01 and 03-04 at 0/0; expected rows updated with exact values, alignment pins unchanged. | Live REST red/green (app-crm opportunity_metrics, dev:crm --fresh after full pnpm build, POST /api/v1/analytics/dataset/query, closed_won, 2026-06-01..2026-10-31, previousYear): RED (base blob 55592517 rebuilt, dist marker 1 hit) 200 rows 3 = 07, 09, 10; GREEN (HEAD rebuilt, marker 0 hits) 200 rows 5 = 06 0/0, 07 2/0, 08 0/0, 09 0/1, 10 3/1, avg absent on 06/08 both sides. Controls identical red vs green: limit 10 (3 rows), plain series (5 rows). Restore: blob == HEAD, git diff HEAD empty. | Final head 93470ee (origin/main b322b5d merged): pnpm install --frozen-lockfile && pnpm build, then @objectstack/service-analytics test 194 files, 4698 passed, 282 skipped; typecheck exit 0; @objectstack/spec check:generated exit 0; @objectstack/rest vitest run src/analytics- 23 files, 298 passed, 22 skipped. Lock VERDICT command-exit 0.",
    "gates": "Head 93470ee: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 59 families; all 59 run, all exit 0 (captured before any pipe; check-plugin-teardown-shape --self-test after git fetch --depth=1 of its fixture commit). --ran reconciliation: "59 derived, 59 run, 0 NOT-MEASURED, 0 UNRUN". Hand: pnpm exec eslint --no-inline-config packages/services/service-analytics exit 0; check-commit-card-trailers --range origin/main..HEAD exit 0. CI check-runs on PR #27213: in_progress at report time (21 runs listed), left to the seat.",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm; also no dogfood file sends a compareTo (git grep -l compareTo -- packages/qa: 0 files) and the diff changes an answer only when compareTo is set",
    "mcp_calls": "0 — no MCP GitHub calls; reads went through gh api REST",
    "api_writes": "2 relay strokes — fleet-write dispatch pr_create (POST pulls + POST issues/27213/assignees, run 40674825741, read-back identical 10328 bytes, assignee os-project-manager) and this os-dev-report comment via post-stamped (POST issues/27111/comments). Plus 3 git pushes to claude/project-thread-1g97l3 (fix, test+changeset, merge of origin/main), WIP pushes per AGENTS.md",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: server seat 2 · noted, not filed — the pending .changeset/26893-time-series-empty-buckets.md (unreleased, PR #27109) still lists compareTo under Not filled; if both ship in one release that bullet contradicts this changeset. Not edited (outside the claim file surface); the seat may drop "or a compareTo" from it."
    ]
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim amendment · domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-10-28T10:51Z · PR #27213, head 93470eef

    The branch, account, rulings and everything else in the claim stay as they are. One change: the file surface gains .changeset/26893-time-series-empty-buckets.md, and only one edit is allowed there.

    • Why: that changeset is unreleased. It comes from PR fix(service-analytics): a date-dimension series answers every bucket of its window, the empty ones included #27109, which is on main. Its Not filled bullet says a compareTo answers "exactly as before". This PR fills compareTo, so if both changesets ship in one release, the notes contradict each other. The dev flagged this in the PR's acceptance notes.
    • Allowed edit: drop the words "or a compareTo" from that bullet. Reflow the sentence so it still reads, and touch nothing else in the file.
    • The Clause-②: no and Metadata-protocol: none lines are unchanged.

    Generated by Claude Code

  7. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim amendment 2 · domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-10-28T10:54Z · PR #27213, head a9e6b7e8

    This withdraws amendment 6467071389. .changeset/26893-time-series-empty-buckets.md leaves the file surface again.

    Why: the required Check Changeset gate refuses any change to a changeset the PR did not add (#17712, ruling D on #17712 / #18160). For a deliberate correction it stays red by design until a person rules, so the seat's request would block the landing. The edit to that file is reverted to its base bytes.

    How the stale bullet is answered instead: this PR's own changeset, .changeset/27111-compare-to-empty-buckets.md, adds one sentence saying that this release fills compareTo too. That sentence supersedes the "or a compareTo" in the #26893 note's Not filled bullet.

    Everything else in the claim stands.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing record · #27111 · PR #27213

    domain:server seat 2 · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-10-28T11:39Z

    Reading Probe Result
    Queue membership git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-27213-*' 0 refs (released)
    Ancestry git merge-base --is-ancestor 835b2d1c origin/main yes (main 835b2d1c)
    Content git grep -c "selection.compareTo || selection.limit" origin/main -- …/dataset-executor.ts 0 hits (the skip is gone); #27111 is cited once in the timeBucketFillPlan docblock

    Generated by Claude Code

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

Metadata

Metadata

Labels

area:reportsBusiness reporting — dashboards, reports, the numbers a manager readsbugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions