Repository navigation
Lite Overview baseline bands use the server's actual hour under a custom range (#4320) - #4325
Merged
Merged
Conversation
…rver (#4320) CorrelatedTimelineLanesControl.RefreshAsync fed a custom range's server-local fromDate straight into GetBaselineForLaneAsync as if it were UTC. BaselineLocalClock.LocalKey expects UTC and converts to server-local itself, so the baseline's local-hour/day-of-week lookup was shifted a second time, by the server's own UTC offset, on any server not on UTC. A preset range's utcNow.AddHours(-hoursBack) was already UTC and unaffected. Add GetBaselineReferenceTimeUtc, which converts a custom range's fromDate back to UTC (fromDate - utcOffsetMinutes) and leaves a preset range's fallback unchanged. RefreshAsync now takes utcOffsetMinutes as an explicit parameter (matching GetCurrentWindowServerLocal/GetOverviewComparisonRange's existing pattern) instead of reading ambient state, and ServerTab.Refresh.cs passes ServerTimeHelper.UtcOffsetMinutes, as it already does for the comparison range. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
Add GetBaselineReferenceTimeUtc_CustomRange_ConvertsFromDateBackToUtc and _PresetRange_UsesUtcNowUnchanged (UTC+5 and UTC-7), plus a source pin that RefreshAsync's referenceTime calls the new helper instead of falling back to a raw fromDate. Proved these fail on the pre-fix code: reverted CorrelatedTimelineLanesControl.xaml.cs and ServerTab.Refresh.cs to the parent commit, which broke the build (the two Theory tests call a method that didn't exist yet -- CS0117), then guarded those two tests out and reran the source pin alone, which failed its Assert.False on the old "fromDate ?? DateTime.UtcNow.AddHours(-hoursBack)" fallback string. Restored both production files from HEAD and removed the guard before this commit; all 14 tests in the class pass again. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
erikdarlingdata
marked this pull request as ready for review
September 25, 2026 17:15
erikdarlingdata
enabled auto-merge (squash)
September 25, 2026 17:15
This was referenced Sep 25, 2026
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.
Closes #4320.
Why
Lite's Overview tab renders baseline bands (CPU, wait ms/sec, I/O latency, blocking/minute) behind the
correlated timeline lanes.
CorrelatedTimelineLanesControl.RefreshAsynccomputed areferenceTimeto keythose baseline lookups and fed it to
GetBaselineForLaneAsync->BaselineProvider.GetBaselineAsync->BaselineLocalClock.LocalKey, which expects a UTCDateTimeand converts it to the server's local hour andday-of-week itself.
Under a CUSTOM time range,
fromDateis already server-local (ServerTab's pickers convert it beforeRefreshOverviewAsyncever sees it — the same factGetCurrentWindowServerLocal's doc comment records forthe #4296 ghost-line fix). The old code,
fromDate ?? DateTime.UtcNow.AddHours(-hoursBack), passed thatserver-local value straight through as if it were UTC.
LocalKeythen converted it to server-local A SECONDTIME, shifting the baseline lookup by the server's own UTC offset. On a server at UTC+5, a custom range
starting at server-local 09:00 was looked up as if it were UTC 09:00, i.e. server-local 14:00 — a 5-hour
bucket error; on a UTC-7 server the same 09:00 start looked up server-local 02:00, a 7-hour error the other
way. A PRESET range was already correct:
DateTime.UtcNow.AddHours(-hoursBack)is genuinely UTC, so noconversion was needed there.
I confirmed this by reading
BaselineLocalClock.LocalKey(PerformanceMonitor.Analysis/Baselines/, ~line280) and
GetBaselineForLaneAsync/BaselineProvider.GetBaselineAsync, and I did not find any other placethat re-corrects the offset before the lookup — the bug is exactly where the issue's correction comment
placed it.
What changes
Lite/Controls/CorrelatedTimelineLanesControl.xaml.cs: addGetBaselineReferenceTimeUtc(hoursBack, fromDate, utcNow, utcOffsetMinutes), beside the existingGetCurrentWindowServerLocal. Under a customrange it converts
fromDateback to UTC (fromDate - utcOffsetMinutes); under a preset range it returnsutcNow.AddHours(-hoursBack)unchanged.RefreshAsyncnow calls this helper instead of usingfromDatedirectly.
RefreshAsynctakesutcOffsetMinutesas an explicit parameter instead of readingServerTimeHelper.UtcOffsetMinutesambiently — matching the existing pattern onGetCurrentWindowServerLocal/GetOverviewComparisonRange, both of which already takeutcNow/utcOffsetMinutesexplicitly so a test can drive them deterministically.Lite/Controls/ServerTab.Refresh.cs: the one caller now passesServerTimeHelper.UtcOffsetMinutes, thesame value it already passes to
GetOverviewComparisonRangeon the line above.for its server-local baseline handling.
Test plan
Lite.Tests.csprojbuilds with 0 Warning(s), 0 Error(s).Lite.Tests/OverviewComparisonWindowOffsetTests.cs, the existing class for this file:GetBaselineReferenceTimeUtc_CustomRange_ConvertsFromDateBackToUtc(UTC+5 and UTC-7): a custom range'sresult is
fromDate - utcOffsetMinutes.GetBaselineReferenceTimeUtc_PresetRange_UsesUtcNowUnchanged(UTC+5 and UTC-7): a preset range's resultis
utcNow - hoursBack, unchanged by the offset.BaselineReferenceTime_UsesHelper_NotFromDateDirectly: a source pin thatRefreshAsynccalls the newhelper rather than falling back to a raw
fromDate.(before either method/parameter existed), which broke the build for the two
Theorytests (CS0117,the method doesn't exist yet); guarded those two out and reran the source pin alone against the reverted
source, which failed its
Assert.Falseon the oldfromDate ?? DateTime.UtcNow.AddHours(-hoursBack)string. Restored both files from
HEADand removed the guard before committing; all 14 tests in theclass pass again on the fixed code.
Lite.Tests.exesuite, run once after mergingorigin/dev(which had advanced by three unrelatedPRs while this branch was in progress — merged clean, no conflicts, confirmed the merge added nothing of
mine beyond the three files below): 5413 total, 0 errors, 0 failed, 0 skipped, 291.4s.
apply here — this is a pure WPF/desktop app fix with no PostgreSQL or SQL Server rig involved).
Diff (
git diff --numstat origin/dev...HEAD):For the coordinator
RefreshAsync's newutcOffsetMinutesparameter has exactly one caller in Lite (confirmed by grep acrossLite/andLite.Tests/) —ServerTab.Refresh.cs'sRefreshOverviewAsync, updated in this PR. TheDashboard's separate, deprecated copy of this control (
deprecated/Dashboard/Controls/) is untouched, perthe brief and PR Dashboard query comparison grids use the server's local time (#4313) #4321.
origin/devmoved by three unrelated PRs (WPF trend charts never adopted the #3897/#3960 bucket contract: at the "Last 7 days" window one chart reads 85–170 k raw rows, and the pickers re-run a week-long DISTINCT every refresh #4234, Store host visibility: a cross-platform host profile, a --check-settings verb, and a get_store_host read, so "is this store sized right" has an answer without shell access #4214, WPF Active Queries grid reads 24 h of snapshots with full plan XML on every 30 s refresh: 221–499 MB per server, 5–7.7 s per read, ~1 GB of strings, to enable two buttons #4239-related merges) while this branch was beingbuilt and tested; merged clean with no conflicts, and
git diff --numstat origin/dev...HEADconfirms thisPR's actual content is still only the three files listed above.
CHANGELOG entry
SECTION: Fixed
ENTRY:
([Lite Overview baseline bands use the server's actual hour under a custom range (#4320) #4325]) - Under a custom time range, the Overview tab's CPU, wait, I/O latency, and blocking baseline
bands were keyed off the server-local start time as if it were UTC, shifting the lookup by the server's own
UTC offset a second time. A preset range was already correct. Custom ranges now convert the start time back
to UTC before the baseline lookup, on any server not on UTC.
REF:
[Lite Overview baseline bands use the server's actual hour under a custom range (#4320) #4325]: Lite Overview baseline bands use the server's actual hour under a custom range (#4320) #4325
🤖 Generated with Claude Code
https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3