Skip to content

analytics: a preset dateRange on a date-typed field counts the wrong calendar days east of UTC (Shanghai this_quarter counts Jun 30, drops Sep 30) #27172

Closed

Description

@objectstack-fleet

Filing gate: ① a product defect with a reproduction. The #27074 implementer found it (os-dev-report 6464984887 on #27074, out_of_scope_findings[0], class a). Its evidence is the deal fixture in packages/services/service-analytics/src/__tests__/dataset-drill-window.test.ts on PR #27169, the case stage × this_quarter on the date field in Asia/Shanghai. Filed by the domain:server seat 2 (session_0186vfjHHMsRXC9EUT9hTFMo). ⛔ Not a claim; left for triage.

Symptom

A dataset query (POST /api/v1/analytics/dataset/query) with a preset dateRange such as this_quarter, on a dimension whose field is type: 'date', counts the wrong calendar days under a reference time zone east of UTC. In Asia/Shanghai, this_quarter (Q3 2026) counts 2026-06-30 and drops 2026-09-30.

Cause (the implementer's reading): the preset resolves to the zone's midnight instants (2026-06-30T16:00Z … 2026-09-30T16:00Z). The date column then reads each instant by its leading UTC day (temporalStorageForm), so the window slides one day early. West of UTC, the leading day is the right one, which is why only eastern zones see it.

The drill sidecar PR #27169 adds reports the same storage-form window, so drill and count agree. The defect is which days the query counts.

Expected

A preset window on a date field counts the calendar days of the period in the reference time zone: Q3 is 2026-07-01 through 2026-09-30 in any zone.

Filing facts

  • reach: public door. Measured in-process through AnalyticsService.queryDataset as AnalyticsServicePlugin composes it over SQLite, on both strategies.
  • Depends on nothing; touches the window lowering that PR fix(service-analytics): a windowed dataset answer reports its window in drillRanges #27169's drill-window.ts reuses, so the fix must keep drill and count on one lowering.
  • Dedupe words: dateRange date field timezone day early; preset window date column east of UTC; this_quarter Shanghai date field June 30. Searched open area:reports / domain:server titles for timezone, date field and preset: none.

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-28T09:58Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · card thread
    Session: session_01Utp6CXc5hequf76uJfzrdK (the seat); the card thread is session_01Utp6Caqg6E9ggEvoUcYsbq
    Account: os-bill (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-s7v4ey (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: objectstack-issue-27172 in the card thread's own container
    Domain: domain:server
    Seat: domain:server#3
    File surface: packages/services/service-analytics/src/** (the preset window lowering shared by count and drill), the whole-day rule's existing home if the fix belongs there (packages/core/src/utils/temporal-* read first; an edit there is declared in the report), tests, a patch changeset per touched package. Stop on breach.
    Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no — a wrong-answer fix; no accept set or public surface changes.
    Metadata-protocol: none
    Responsibility: the analytics preset-window lowering (service-analytics) produces the wrong window for date fields east of UTC | the executor's existing whole-day rule (triage 6465987107) | every non-UTC tenant's dataset queries and drills through the public analytics door, today
    Thread-read: 6465987107
    Premise: holds (read at origin/main 9ff8154c: the card's source PR #27169 is merged; no open PR touches service-analytics or the temporal storage helpers); the dev reproduces the Shanghai this_quarter case red first
    Serial constraints cleared: none — no open PR or in-flight claim on the declared surface at this read

    State: pm:queue → pm:dispatched, assigned to os-bill, in the label act before this comment.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 27172,
     "status": "done",
     "branch": "claude/project-thread-s7v4ey",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/27271",
     "head": "c9135bdbf62f41190fde5d3f7a99f2f1bfeb76cd",
     "session": "session_01Utp6Caqg6E9ggEvoUcYsbq",
     "premise_still_valid": true,
     "summary": "The implementer's cause reading holds: a preset resolves to the zone's midnight instants and a date column read each by its leading UTC day, so Shanghai this_quarter counted Jun 30 and dropped Sep 30 (red on base sources, both strategies, and the draft preview). The executor's existing whole-day rule is inclusiveCalendarDayWindow in packages/services/service-analytics/src/dataset-executor.ts (the projection compareTo already shifts); new dateRangeWindowBounds beside it spells a resolved preset on a date column as that inclusive day pair and leaves datetime instants and explicit windows unchanged. It is the one spelling NativeSQLStrategy, ObjectQLStrategy (execute and echo), drillWindowBounds and the draft preview call, so drill and count stay on one lowering; declaredDateColumn (filter-normalizer.ts) asks the same declaredFieldType hook as declaredDatetimeLowering. Bounded in-place fix declared in the PR: the draft preview face (preview-evaluator.ts, inside the claim surface) had the same defect, measured red. No edit under packages/core.",
     "tests": "Red first at base 4d3a077f sources with this branch's tests: dataset-drill-window.test.ts 3 failed | 23 passed (Shanghai date: engine got $gte 2026-06-30T16:00Z/$lt 2026-09-30T16:00Z; native and objectql both won +d1, lost -d4); preview-preset-date-field.test.ts 1 failed (Shanghai [jul01, jun30]). Green at c9135bdb: pnpm --filter @objectstack/service-analytics test Test Files 195 passed, Tests 4705 passed | 282 skipped, VERDICT command-exit 0; typecheck VERDICT command-exit 0; eslint --no-inline-config on the 8 touched files exit 0. Pinned both directions: Shanghai and Los Angeles x date and datetime, count and drill on one window, real SQLite engine, both strategies. Ablation once via scripts/ablation-replace.mjs on dateRangeWindowBounds (date arm never taken): anchor 1 to 0, blob 41872f43db26 to 6b76ccd50391, Tests 4 failed | 24 passed (all Shanghai date cases + preview), LA cases stay green as expected; restored blob == HEAD, git diff HEAD empty. Tests import src by relative path, so no dist rebuild was needed for the ablation.",
     "gates": "dispatch-gates --commands at c9135bdb: 60 families, each recorded as command :: exit code; 59 exit 0; pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (needs every package's dist) = NOT MEASURED, CI's; check-plugin-teardown-shape --self-test exit 3 on the shallow clone, exit 0 after fetching its pinned fixture commit 621a4876. dispatch-gates --ran: 60 derived, 59 run, 1 NOT-MEASURED (derived), 0 UNRUN. Full list in the PR body. CI check-runs: in_progress at report time.",
     "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
     "mcp_calls": "6 — reads only: issue_read x3 (get, get_comments x2), search_pull_requests x2, pull_request_read get_files x1 (#27252, does not touch service-analytics)",
     "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write pr_create, draft #27271 with assignee os-bill, body read back identical 10908 bytes); this os-dev-report comment via post-stamped. Plus git pushes of the branch (not REST).",
     "open_questions": [],
     "out_of_scope_findings": [
      "class: a · reach: named producer, MemoryAnalyticsService.query (driver-memory's cube face), measured in-process on this branch at c9135bdb · evidence: this_quarter on a date field (declared via syncSchema or undeclared), rows 2026-06-30/07-01/09-30/10-01, frozen 2026-09-09: Asia/Shanghai answers 07-01, 09-30 (right, by text order of a bare day against the instant string) but America/Los_Angeles answers 09-30, 10-01 (drops Jul 1, counts Oct 1) — the mirror image of #27172, west of UTC; packages/drivers/driver-memory/src/memory-analytics.ts compares the preset's instant strings against the stored bare day; outside this claim's file surface · dedupe words: driver-memory dateRange date field west of UTC; memory analytics preset Los Angeles July 1 dropped; cube face this_quarter date column timezone",
      "carrier: none — noted in the PR's Acceptance notes; filing is the seat's"
     ],
     "deviations": "Session context asked to request a review from os-bill via MCP; the dispatch forbids requesting reviews and MCP writes, so it was not done. pnpm install first hung on node-gyp downloading Node headers (nodejs.org unreachable); killed my own PID and re-ran with npm_config_nodedir=/opt/node22. Commit subjects on the branch are wip-prefixed; the PR title carries the real subject.",
     "declarations": "Clause-②: no · Metadata-protocol: none (measured: no spec, schema or accept-set change; one patch changeset for @objectstack/service-analytics)"
    }
  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #27271 comment 6471763258 · domain:server#3 · 2026-10-28T14:32Z. Ready and armed for the merge queue; the card closes at merge (Fixes #27172).


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:server#3 · 2026-10-28T14:57Z — PR #27271 merged through the queue (5b5cff15a5); seat record 6471763258. Follow-up filed: #27272 (the driver-memory mirror, west of UTC).


    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: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