You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Query Store item-timeline overlay plots at collection_time while the bars it annotates are keyed on the interval start #1921
Found while fixing #1892 and verified against the code; filed rather than folded in because the fix is a product decision about what the overlay is FOR, not a mechanical edit.
The disagreement
QueryStoreItemTimelineSql draws its points at collection_time:
Darling/PerformanceMonitor.Darling.Viewer/ViewerDataService.ItemTimeline.cs — projects collection_time as the x-value, windows on collection_time >= $5 / <= $6
That series is drawn over the Query Store slicer bars, which since #1841 are keyed on COALESCE(interval_start_time_utc, collection_time) — the hour the work RAN. The two axes are no longer the same instant, so a point sits up to one Query Store interval (default 60 minutes, max 1440) to the RIGHT of the bar describing the very same work.
The file's own comment states the invariant this breaks:
This series is drawn OVER the Query Store slicer bars, which ARE deduped (QueryStoreSlicerSql) — leaving the overlay raw would make the overlay disagree with the bars it annotates.
The dedup half of that invariant holds. The PLACEMENT half silently stopped holding when #1841 moved the bars and left the overlay where it was.
#1892 does not create this and does not worsen the x-axis, but it does add a second axis of disagreement: after #1892 the bars are windowed on the effective timestamp while the overlay is still windowed on collection_time, so at a range edge the two surfaces can disagree about whether a given interval is in the window at all.
Why this is a decision, not a mechanical edit
The overlay answers a genuinely different question from the bars. A bar says "this much work ran in this hour". An overlay point arguably says "at this moment, the collector observed these cumulative totals" — which is a real thing to want, and collection_time is the honest x-value for it.
So there are two defensible fixes and they are not equivalent:
Keep collection_time and document the overlay as a collection-event series, updating the comment that currently claims agreement. Cost: the two series on one chart keep using different clocks, which is exactly the kind of thing that produces a support question.
Option 1 is probably right — it is the direction #1841 took everything else — but it changes what a shipped chart means, so it wants a deliberate call rather than being folded into an edge-case fix.
Scope when it is done
Both apps, and the window filter moves with the x-value (the #1892 shape: filter on the same expression you place on, keep a bare collection_time floor for chunk exclusion and no ceiling).
The live pin ViewerQueriesTests.QueryStoreAggregates_CountARecollectedIntervalOnce_AtItsLatestValues_AgainstDevPostgres asserts the timeline point lands at bucketStart+15m (a collection time), so it moves with the decision.
Shipped in #1938, per Erik's option-1 ruling: the Query Store item-timeline overlay now plots at the interval start - work placed when it ran - matching the bars it annotates, with the window filter and ORDER BY moving with the x-value (the #1892 shape plus #1923's 30-day pruning ceiling). Both apps. Lite gained a DEDICATED overlay read rather than inheriting the history grid's raw per-collection projection, which converges the two apps' structure and fixed a second disagreement in the same feature: Lite's overlay never deduped, so a repeatedly-collected interval drew as a rising staircase of restatements - it now draws as one point at final values, which is what the bar beside it always showed. The legacy fallback (rows with no interval identity plot at collection_time) is pinned deliberately, and the behavioral proof lives in a test whose seeds genuinely discriminate (70-minute offset goes red on revert). Review round added: three accidental BOMs stripped and ItemTimelinePoint.CollectionTime renamed to PointTime, since the old name lied for exactly the series this change moved.
Found while fixing #1892 and verified against the code; filed rather than folded in because the fix is a product decision about what the overlay is FOR, not a mechanical edit.
The disagreement
QueryStoreItemTimelineSqldraws its points atcollection_time:Darling/PerformanceMonitor.Darling.Viewer/ViewerDataService.ItemTimeline.cs— projectscollection_timeas the x-value, windows oncollection_time >= $5 / <= $6That series is drawn over the Query Store slicer bars, which since #1841 are keyed on
COALESCE(interval_start_time_utc, collection_time)— the hour the work RAN. The two axes are no longer the same instant, so a point sits up to one Query Store interval (default 60 minutes, max 1440) to the RIGHT of the bar describing the very same work.The file's own comment states the invariant this breaks:
The dedup half of that invariant holds. The PLACEMENT half silently stopped holding when #1841 moved the bars and left the overlay where it was.
#1892 does not create this and does not worsen the x-axis, but it does add a second axis of disagreement: after #1892 the bars are windowed on the effective timestamp while the overlay is still windowed on
collection_time, so at a range edge the two surfaces can disagree about whether a given interval is in the window at all.Why this is a decision, not a mechanical edit
The overlay answers a genuinely different question from the bars. A bar says "this much work ran in this hour". An overlay point arguably says "at this moment, the collector observed these cumulative totals" — which is a real thing to want, and
collection_timeis the honest x-value for it.So there are two defensible fixes and they are not equivalent:
collection_timeand document the overlay as a collection-event series, updating the comment that currently claims agreement. Cost: the two series on one chart keep using different clocks, which is exactly the kind of thing that produces a support question.Option 1 is probably right — it is the direction #1841 took everything else — but it changes what a shipped chart means, so it wants a deliberate call rather than being folded into an edge-case fix.
Scope when it is done
Both apps, and the window filter moves with the x-value (the #1892 shape: filter on the same expression you place on, keep a bare
collection_timefloor for chunk exclusion and no ceiling).Darling/PerformanceMonitor.Darling.Viewer/ViewerDataService.ItemTimeline.csViewerQueriesTests.QueryStoreAggregates_CountARecollectedIntervalOnce_AtItsLatestValues_AgainstDevPostgresasserts the timeline point lands atbucketStart+15m(a collection time), so it moves with the decision.