Skip to content

driver-memory analytics accepts timeDimensions[].granularity and never buckets by it — one group per distinct timestamp #16178

Description

@claude

Found while working on #16042 (the AnalyticsQuery.timezone repair in the same function's file). ⛔ Deliberately NOT fixed there — that card's fence was dateRange, and this is a different field with a different consumer. Refs #16042, #15825.

The shape

AnalyticsQuery.timeDimensions[].granularity is declared by the spec (packages/spec/src/data/analytics.zod.ts:324, granularity: TimeUpdateInterval.optional()), and a cube dimension declares which granularities it offers (granularities: ['day']). packages/drivers/driver-memory/src/memory-analytics.ts never reads either.

Measured on origin/main @ 1328902ce:

git grep -c 'granularity' -- packages/drivers/driver-memory/src/memory-analytics.ts
(0 hits)

Positive control on the same file in the same session: git grep -c 'dateRange' returns 4, and git grep -c 'timeDimensions' returns 1. So the zero is a real absence, not a broken grep.

Measured through the public entry, against the BUILT package

Two rows on the same UTC calendar day, grouped by the time dimension with granularity: 'day':

rows:   2026-09-06T01:00:00.000Z, 2026-09-06T23:00:00.000Z
query:  dimensions: ['events.createdAt'],
        timeDimensions: [{ dimension: 'events.createdAt', granularity: 'day' }]

result: [ {events.createdAt: '2026-09-06T01:00:00.000Z', events.count: 1},
          {events.createdAt: '2026-09-06T23:00:00.000Z', events.count: 1} ]

two groups, not one. The $group stage keys on the raw field path (memory-analytics.ts:786, groupStage._id[dimName] = '$' + fieldPath), so a time dimension buckets one group per distinct timestamp — one bar per row in a "new accounts by month" chart, which is the exact symptom #3588 catalogued and repaired for service-analytics.

Why this is a card and not "unimplemented"

Same declared-≠-enforced shape as #16042, one field over: the schema declares the knob, the cube metadata enumerates the granularities a dimension offers, and this implementation quietly drops both. The request is accepted, no warning is emitted, and the answer is silently ungrouped.

The other implementations do read it — service-analytics' preview-evaluator.ts:215 calls bucketDate(raw, gran, timezone), and objectql's engine.ts routes a non-UTC reference timezone to applyInMemoryAggregation(raw, ast, tz) precisely so bucketing stays uniform. ⚠️ I measured that they READ it; I did not verify they bucket correctly.

Note this is orthogonal to #16042, which repaired the dateRange WINDOW (which rows are selected). This is the GROUPING (how selected rows are folded). #16042 changes no grouping behaviour.

Prior art already in the tree

bucketDate(value, granularity, timezone) in packages/services/service-analytics/src/preview-evaluator.ts:129 is the whole rule, and it already takes the reference timezone — so a repair here would want #16042's resolution rather than a second dialect.

Unlabelled on purpose: routing, domain:*, type and priority belong to triage.


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions