fix(analytics): apply the effective date granularity to labels and drill ranges (#3588 follow-up) - #3673
Merged
Conversation
…ill ranges (#3588 follow-up) `selection.dateGranularity` reached the GROUP BY but not the post-processing: the bucket-label formatter and the drill-range inverter both kept reading the DATASET dimension's default, so a query was grouped one way and described another. Found by driving the query in a browser, not by the unit tests — which passed throughout, because each site was correct in isolation. Against a dataset declaring `dateGranularity: 'month'`: - selection `year` → row labelled "1970-01", a year bucket re-formatted with the dataset's month granularity, its "2026" key re-read as 2026 milliseconds past the epoch; - selection `day` → day buckets re-labelled as months, collapsing ten distinct days into two duplicated keys; - selection `quarter`/`year`/`day`/`week` → `drillRanges` empty, silently removing drill-through from every bucketed chart. Granularity precedence now lives in one exported function, `resolveDimensionGranularity`, called from all three sites that must agree: the query's GROUP BY, the label formatter, and the range inverter. The drift was possible only because each resolved it independently — so the fix is the shared resolver, not three parallel patches. Also fixes two things this surfaced: - A dataset dimension declaring NO granularity but bucketed by the widget now gets drill ranges. The sidecar keyed off the dataset's own `dateGranularity`, so the case #3588 is actually about could never drill. - `formatDateBucket` no longer mistakes a bare year key for an epoch timestamp. "2026" is the only bucket key that collides with the pure-digit epoch heuristic; "2026-Q2", "2026-07" and "2026-07-15" all fail it. Idempotence over already-formatted keys is that function's stated contract — the year case just never held. Verified in a browser end to end: all five granularities now label correctly (year "2026", not "1970") and every one carries its half-open drill range. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SEZLBGyNoJMLvtGPqsMPRC
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 6 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
July 27, 2026 14:01
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #3652 (issue #3588). Found by browser-verifying that merge, not by the test suite — which passed throughout, because each site was correct in isolation.
What was wrong
selection.dateGranularityreached theGROUP BY, but two post-processing steps kept reading the dataset dimension's default: the bucket-label formatter and the drill-range inverter. So a query was grouped one way and described another.Driving a real dashboard query against a dataset whose dimension declares
dateGranularity: 'month':yearcreated_at: "1970-01""2026"dayquarterdrillRanges: [{}, {}]week/daydrillRanges: [{}, …]The
1970-01is the tell: a year bucket's key is"2026", which the month formatter re-read as 2026 milliseconds past the epoch.The fix
Granularity precedence now lives in one exported function,
resolveDimensionGranularity, called from all three sites that must agree — the query'sGROUP BY, the label formatter, and the range inverter. The drift was possible only because each resolved it independently, so the fix is the shared resolver rather than three parallel patches.Two things this surfaced, fixed here too:
dateGranularity, so it skipped exactly the case Analytics query builder ignores widget dateGranularity, sortBy/sortOrder, and funnel stage order #3588 is about (hotcrm'saccount_metrics.created_at).formatDateBucketmistook a bare year key for an epoch timestamp."2026"is the only bucket key that collides with its pure-digit epoch heuristic —"2026-Q2","2026-07","2026-07-15"all fail it. Idempotence over already-formatted keys is that function's stated contract; the year case just never held. This one predates feat(analytics): honour widget dateGranularity, sortBy/sortOrder, and limit in dataset queries (#3588) #3652 and affects any dataset declaringdateGranularity: 'year'.Verification
Browser-driven against the showcase app, before and after. All five granularities now label correctly and every one carries its half-open drill range:
Tests: 11 new in
dataset-granularity-postprocess.test.ts, pinning each broken case plus the precedence table; full@objectstack/service-analyticssuite 219 passed.The test service returns the bucket key the driver would actually produce for the granularity requested, so a query/post-processing mismatch reproduces exactly as it did in the browser — a mock that echoed a fixed key would have stayed green through the original bug.
Generated by Claude Code