Repository navigation
Custom Views panels, Active Queries and Current Waits say where their data starts - #4953
Conversation
… data starts A window can reach further back than the rows the store holds: retention, a held purge, or a server added recently. A Custom Views panel now carries a notice naming where its data starts and the window it really covers, and the Darling viewer's Active Queries and Current Waits tabs show the "Showing since" banner the Queries tab already shows. The start is the oldest row each server in scope holds at or before the window's end, read per server through the registry. A panel read from a rollup takes its start from that rollup.
Blind-read notes the verdict block can't hold at lengthThe Lite parity question, checked rather than taken on trustThe two-store rule is the first thing this diff looks like it trips — it adds a disclosure to two Darling viewer surfaces over It isn't, and the PR body's account of why is accurate. Confirmed from the tree:
So a 30-day range in Lite over a 7-day table really does hold rows, and a banner there would have been the false alarm. The body's own disclosure of what stays open is also correct and worth keeping in view for the follow-up:
That last sentence is the load-bearing one: CostThe EXPLAIN and client-timing tables are the kind of evidence a read-only tree cannot grade, and they are the right evidence to have gathered. Two things a human with the rig should still look at, both flowing from the deliberate choice to drop the lower bound:
Neither is a reason to hold the change; both are worth a glance before this probe lands on the 30-day desktop tabs the body already names as the next step, where it would run on many more surfaces. What the new tests pin, and what they don't
Not covered by anything: the One pin that now passes by construction
|
There was a problem hiding this comment.
Verdict: CHANGES REQUESTED
Full reasoning in the top-level comment and three inline notes; this is the structured summary.
Claims
- VERIFIED — "the
run_custom_view_panelMCP tool uses the same runner and gets the same notice" — the probe is insideRunComposedPanelCoreAsync(DarlingWebEndpoints.cs:1322-1326), whose only callers are the web endpoint (:604) and the tool (Mcp/DarlingMcpCustomViewTools.cs:287). - VERIFIED — the notice's exact wording, and "the start always comes from the rows, never from the retention defaults" —
ComposeStoreAvailability.cs:358-361, pinned byte-for-byte byDataWindowFloorTests.TheNotice_NamesTheStartAndTheWindowItCovers_InUtc; the value comes fromDataWindowFloor.GetAsyncat:344. - VERIFIED — "
query_snapshotsandwaiting_taskskeep 7 days" —CollectorScheduleDefaults.cs:45,:71. - VERIFIED — banners on all three Active Queries reads and above both Current Waits charts —
ViewerServerTab.ActiveQueries.cs:82/:93/:114(counted byViewerDataStartBannerTests.ActiveQueries_ShowsWhereTheSnapshotsStart_OnEveryReadOfTheGrid) andBlocking.cs:188, fan-out 2→3 at:175; XAML rows consistent atViewerServerTab.xaml:690-711, styling matching the #4231 siblings at:906-909. - VERIFIED — the four "no change needed" rows — no compose renderer under the viewer;
MAX(collection_time)anchor atViewerDataService.RunningJobs.cs:43-44;DrillWindowUtcatViewerServerTab.DrillDown.cs:329-336. - VERIFIED — "a removed server still counts … removal deletes only the server's definition" —
BaselineCache.cs:58, andMcp/DarlingMcpTools.cs:1403namesconfig.config_monitored_serversasremove_server's target, so thecollect.serversrow survives. - VERIFIED — the whole Lite row, the claim I most expected to break —
RetentionService.cs:26("Lite does not purge per collector"),:34(3 months),ArchiveService.cs:40(7 hot days),DuckDbInitializer.cs:707-713, the union-view reads atLocalDataService.Blocking.cs:348/WaitingTasks.cs:105, and Lite's both-sides-bounded probe atLocalDataService.QueryWindowFloor.cs:68-73. - VERIFIED — "runs only when the tier notice is silent, not when the wide table served, and a failed probe costs no chart", the reused 90-minute slack, and the
index_object_statsexclusion —DarlingWebEndpoints.cs:1322;ComposeStoreAvailability.cs:346-349,:351;RawWindowFloor.cs:109-110;PgSchemaGenerator.cs:112failing the gate atDataWindowFloor.cs:83. - UNVERIFIED — the EXPLAIN table, plan excerpt, 25-call timing medians and the 708.6 ms comparison — live measurements; no rig, no 3.36M-row store, no planner here.
- UNVERIFIED — "4 of 7 failed" first, the three viewer-check failures, the two planted-and-reverted failures — needs
DARLING_TEST_PG+ TimescaleDB and a revert-and-rerun; every test body is consistent with what is reported. - UNVERIFIED — the Node render test — needs Node. Consistent on read:
el()setsnode.classNameforclass(util.js:30), matching the harness's"strip notice"walker againstnoticeStrip(util.js:136);compose.js:23-26imports exactly the four modules stubbed. - UNVERIFIED — "Total 19902 … Failed 11" and the clean 35-test UTC re-run — a build and a live store.
- REFUTED — nothing the body asserts; the gap is one it does not assert (see Divergence).
Riskiest lines
Darling/PerformanceMonitor.Darling.Storage/DataWindowFloor.cs:166— the end bound and the absent start bound: the whole false-alarm/missed-alarm hinge, and what forfeits chunk pruning. — pinned byDataWindowFloorTests.ThePanelProbe_BoundsOnlyTheEndandComposeDataFloorLiveTests.AQuietStartInsideTheWindow_GetsNoNotice_AgainstDevPostgresDarling/PerformanceMonitor.Darling.Service/DarlingWebEndpoints.cs:1322—retentionNotice is null && !queryStoreWideEligible: wrong one way every panel buys a needless store read, wrong the other a Query Store panel reports its start twice in two formats (:1337-1340). — UNPINNEDDarling/PerformanceMonitor.Darling.Service/Compose/ComposeStoreAvailability.cs:346— the blanketcatch: a 42P01 and a 57014 are swallowed identically, so a probe that never succeeds looks like a store with nothing to report. — UNPINNED
Traps near this diff
- "A retention-tiered store answers a 7-day question from a 4-day raw tier and labels the missing days quiet unless the read routes by tier and says which tier served it (#3590 … #3684)." — applies, and is the shape being fixed — closed at
DarlingWebEndpoints.cs:1324,ActiveQueries.cs:93,Blocking.cs:188. - "Lite and Darling ship in parity … a fix to one SKU's reader, tool, alert or description without the counterpart's is a finding, not a nit." — does not apply — nothing under
Lite/referencesRunComposedPanel/ComposeStoreAvailability, and Lite's two tabs read the archive-union views (LocalDataService.Blocking.cs:348,WaitingTasks.cs:105;DuckDbInitializer.cs:707-713) becauseRetentionService.cs:26says Lite does not purge per collector. - "Two copies of one definition pinned EQUAL to each other fail only after BOTH have drifted (#3684). Alias, do not copy." — applies narrowly, non-blocking — the live path aliases
route.CaggFromClause(ComposeStoreAvailability.cs:380), but its null-fallback re-derivesComposeCompiler.cs:185's string; the router always sets the field (ComposeSourceRouter.cs:350-362), so it is dead code holding a second copy. - "Truncation inferred from a full page:
truncated = rows.Count >= limit." — does not apply — the verdict is a separate probe against the window's start (ComposeStoreAvailability.cs:351), never read offrows. - "Strip the
DateTimeKindbefore binding a timestamp parameter … the row lands at the wrong hour with no error anywhere." — applies, and is honored —DataWindowFloor.cs:226-227, reason at:224-225; seeders likewise atComposeDataFloorLiveTests.cs:295-296. - "A test that reads the clock twice measures the CI scheduler (#3676). One anchor owns both ends of an interval." — does not apply — one
DateTime.UtcNowatComposeDataFloorLiveTests.cs:259ownsend,recentFirstandquietFirst. - "A pin that encodes the lie … Ask what a pin would fail ON." — applies narrowly, non-blocking —
DarlingComposeTests.cs:3529'sAssert.Null(notice)is now satisfied by construction (ComposeStoreAvailability.cs:344answers null first); disclosed in the docstring, and the routing arms at:3526-3528still bite. - "A roster-based census does not see the file it does not roster (#3699)." — does not apply — the new file calls the raw
ReadRepoFileandRepoFileAdoptionTests' exact-set equality covers only LF adopters (:299-301); raw adopters carry a floor (:269-273), and its anchors are single-line. - "
timescaledb_information.hypertablesnever lists a continuous aggregate's materialization (#3582 → #3610)." — does not apply — the probe reads each rollup's own user view (DataWindowFloor.cs:164).
Divergence (blind read vs PR body)
One, an omission rather than a disagreement. The body says "run_custom_view_panel MCP tool | Same runner, so it gets the same notice" — true — but never that the tool's declared semantics for notice had to move with it, and did not. Mcp/DarlingMcpCustomViewTools.cs:246-247 still reads "notice means retention covered only part of the window, or the row cap truncated the result; absent means neither happened"; the GUIDE half at :252 still scopes it to retention. This diff makes both halves false and says so itself — ComposeStoreAvailability.cs:327, added here, is explicit that the notice "names no cause: retention, a purge that ran late, and a server added last week truncate the same way." A panel over a server registered last week now returns notice with neither retention nor the row cap involved. That description is the only contract an agent has here, so the drift becomes an agent telling an operator their retention is too short when the cause is a young install. The web surface is fine — the notice body names itself.
Elsewhere the accounts agree, including where I expected them not to: the Lite parity row (correct from the tree, residual gaps disclosed) and the index_object_stats exclusion. Secondary non-blocking: compose.js:260's comment is now narrower than reality, and ViewerReadFanOut.Of(2) is not declared around the new two-read concurrency in LoadActiveQueriesAsync — which matches the #4231 precedent at ViewerServerTab.Queries.cs:176-177, so consistency rather than regression.
Reviewer checklist
- Update
run_custom_view_panel's description (Mcp/DarlingMcpCustomViewTools.cs:246-247,:252) sonoticecovers the data-start cause and "absent" claims nothing about retention;compose.js:260with it. - Drive a Query Store panel through the wide-table path on a live store and confirm
DarlingWebEndpoints.cs:1322's!queryStoreWideEligiblearm suppresses the probe, so the start is reported once. - Re-run the fleet EXPLAIN with the empty-server population dominant and a 90-day hourly rollup at 10-day chunks — unbounded-below cost scales as chunks times servers-with-no-rows. Capture a CAGG plan too: the rollups are
materialized_only = false(TimescaleSupport.cs:626). - Run the gated live classes with
DARLING_TEST_PGon a UTC-session TimescaleDB store, plus the Node harness, and build the WPF viewer. - Open the viewer on a range entirely before where
query_snapshots/waiting_tasksbegin and decide whether an empty grid with no banner is acceptable (the probe answers null;IsTruncated(null, …)is false).
…the store session to UTC The raw window floor behind the Queries tab's "Showing since" banner and the MCP tools' window_truncated is now the oldest row at or before the window's end, the way Custom Views panels find where their data starts. A server quiet for the first hours of a window no longer reads as cut short. The floor stays null when the window holds nothing, and the served start never precedes the requested one. The test process applies the product's own UTC session pin to DARLING_TEST_PG when it loads, so a test store whose server runs in another time zone no longer fails tests that plant rows relative to UTC now.
…e the window's end, so a quiet start inside the window raises no banner The probe read the oldest row INSIDE the window, so a server with older rows and then a quiet stretch at the window's start looked like a store that failed to hold the window. It now returns NULL when the server has no row inside the window (a bounded existence check, cheap with zone maps), and otherwise the oldest row at or before the window's end, unbounded below. The three MCP tools clamp the effective start to the requested start, so a floor before the window never makes the window look longer than it was asked for.
A window or custom range that reaches further back than the stored rows (the archive's first month, or a server added recently) now shows the same 'Showing since' banner on Active Queries (query_snapshots) and Current Waits (waiting_tasks) that the Queries grids carry, through the one shared floor probe and one banner step. The probe's relation list gains the two views; the three call-site count pins move 3 to 4 and 6 to 10 for the new calls.
…x/cv-retention-notice-lite
Lite/Darling parity: the diff changes the Darling half of a probe whose own doc calls Lite's "the twin"The body's surface table says:
Every factual sentence there is true, and I confirmed each from the tree. But the reason given is scoped to reusing Lite's probe for the new sparse surfaces — and that is not the parity question this diff raises. The diff also rewrote What the two SKUs now say about identical data, on the same three tables:
The two files already name each other as one definition in two places:
REVIEW-TRAPS, last line, quoted whole:
And the parenthetical is why nothing went red: Note the direction, too. Lite's Pick one and say so in the body:
Either is a decision for you; what is not available is the current state, where one SKU's Everything else I checked held up — the measurement tables, the EXPLAIN plan shape, and the failing-first ledger are all things a read-only tree cannot confirm, but the claims that are checkable from the tree checked out. Details on the rest in the inline comments and the review body. |
There was a problem hiding this comment.
Verdict: CHANGES REQUESTED
Two blocking findings; detail in the inline comment on RawWindowFloor.cs:68-87 and the top-level parity comment.
Claims
- VERIFIED — notice sits beside the tier and row-cap notices —
DarlingWebEndpoints.cs:1322-1330 - VERIFIED —
run_custom_view_panelshares the runner —DarlingMcpCustomViewTools.cs:287 - VERIFIED — Active Queries banner on grid, slicer and deep-link reads —
ViewerServerTab.ActiveQueries.cs:82, 93, 114;ViewerDataStartBannerTests.ActiveQueries_ShowsWhereTheSnapshotsStart_OnEveryReadOfTheGrid - VERIFIED — Current Waits banner above both charts —
ViewerServerTab.Blocking.cs:188;Of(2)→Of(3)keepsEveryViewerFanOut_DeclaresItsWidthgreen - VERIFIED — runs only when the tier notice is silent, never when the wide table served —
DarlingWebEndpoints.cs:1322 - VERIFIED — a failed probe costs the notice, not the chart, and a cancel still propagates —
ComposeStoreAvailability.cs:338-342 - VERIFIED — reuses
IsTruncated's 90-minute slack —ComposeStoreAvailability.cs:351,RawWindowFloor.cs:130 - VERIFIED —
index_object_statsexcluded on index order; no unvetted name reaches the SQL —DataWindowFloor.cs:83,DataWindowFloorTests.CollectorTables_AreProbedOnlyWhenTheirIndexLeadsWithServerAndTime - VERIFIED — probing both stitched halves can only find an earlier start —
DataWindowFloor.cs:150 - VERIFIED — Lite's probe looks for the start inside the window —
Lite/Services/LocalDataService.QueryWindowFloor.cs:68-73 - VERIFIED — Lite untouched, Lite.Tests did not run — absent from the diff. Accurate, and it is the gap.
- VERIFIED —
DataWindowFloorTestswritten after the code, did not fail first — shape pins only - UNVERIFIED — 708.6 ms vs 0.228/3.410 ms — live rig, no artifact in the tree
- UNVERIFIED — EXPLAIN table,
ChunkAppend/Heap Fetches: 0plan, "never executed" chunks, median/p90 render table — need the 200-server, 36-chunk store - UNVERIFIED — "4 of 7 failed", the 3 viewer failures, the two planted reverts — need a run with
DARLING_TEST_PG - UNVERIFIED — 19902/0/11 then 35/0 — need Windows plus a live store; the
LiveStoreSessionTimeZone[ModuleInitializer]mechanism does read correctly in the tree - REFUTED — "Lite custom range | Not changed … cannot be reused as it is" as a complete account — the reason covers only reusing Lite's probe for the NEW sparse surfaces, while the diff rewrote
RawWindowFloor(:68-87, 120), the twin of Lite's three dense tables and the source for four Darling MCP tools - REFUTED — "No lower bound, on purpose …
waiting_taskswith a quiet first day, and deadlocks" as applied toRawWindowFloor— neither table is inRawWindowFloor.Table(:49-54);DataWindowFloor.cs:27-28says the opposite for the three dense ones
Riskiest lines
RawWindowFloor.cs:68-87— lower bound gone, so a collection HOLE at the window's head reads as "served whole" on three dense tables, feeding four MCP tools and three banners — pinned byRawWindowFloorQuietStartLiveTests.AQuietStartInsideTheWindow_IsNotACut_AgainstDevPostgres, which ratifies the new answer rather than guarding itLite/Services/LocalDataService.QueryWindowFloor.cs:68-73— the untouched twin, still bounded below — UNPINNEDDarlingWebEndpoints.cs:1322-1326— puts a fleet-wide per-serverLATERALon every render — pinned byComposeDataFloorLiveTests/ComposeRollupDataFloorLiveTests, both live-only
Traps near this diff
- "Lite and Darling ship in parity (CONTRIBUTING's two-store rule): a fix to one SKU's reader, tool, alert or description without the counterpart's is a finding, not a nit — the census in
McpPageContractTestscompares the two SKUs' payload keys by tool name for exactly this (#3594)." — applies —RawWindowFloor.cs:68-87, 120vsLite/Services/LocalDataService.QueryWindowFloor.cs:68-73andLite/Mcp/McpQueryTools.cs:82, 215, 344 - "A pin that encodes the lie … Ask what a pin would fail ON. (#3699)" — applies —
RawWindowFloorQuietStartTests.cs:30-40 - "Two copies of one definition pinned EQUAL to each other fail only after BOTH have drifted (#3684). Alias, do not copy." — applies, non-blocking, pre-existing —
DarlingMcpQueryStoreClutterTools.cs:149vs:89 - "A retention-tiered store answers a 7-day question from a 4-day raw tier … unless the read routes by tier (#3590)" — does not apply; this diff is the fix —
ComposeStoreAvailability.cs:373-392 - "
hours_back,limit,top,days_backare refused when out of range, never clamped (#3699, #3641)" — does not apply — the clamp atDarlingWebEndpoints.cs:1266is untouched and not an MCP parameter - "A test that reads the clock twice measures the CI scheduler (#3676)" — does not apply — two reads exist (
ComposeDataFloorLiveTests.cs:259) but margins are whole days - "A JSON number above 2^53 is rounded by every JavaScript client (#3487)" — does not apply — the notice is a string,
ComposeStoreAvailability.cs:358-362 - "An expression-bodied member holding a
{ }property pattern is read SHORT by the member walk (#3667)" — does not apply — no property pattern in the new members;DataWindowFloor.cs:191is braced
Divergence (blind read vs PR body)
1. RawWindowFloor is not in the body at all. The diff rewrites its SQL (:68-87) and flips EffectiveStart to a clamp (:120), changing window_truncated / effective_start / effective_hours_back on get_top_queries_by_cpu, get_top_procedures_by_cpu, get_query_store_top, query_store_clutter, and three Queries-tab banners. The surface table rosters nine surfaces and names none of these seven.
2. The rewrite's stated purpose is a table class it does not serve. The quiet-day and deadlock examples justify DataWindowFloor, not RawWindowFloor, whose tables are dense; there the lower bound caught a hole. DataWindowFloor.cs:27-28 still calls bounded-inside-the-window right for exactly those tables — opposite behaviour, two files, one PR.
Everything else matched the tree.
Reviewer checklist
- Pick which
RawWindowFloorsemantics ship, then reconcileDataWindowFloor.cs:27-28andLite/Services/LocalDataService.QueryWindowFloor.cs:54 - Reproduce live: collector down for day 1 of a 7-day window on a server holding a fortnight of
query_stats; confirmwindow_truncated: falsewith no banner is wanted - Re-run
Darling.TestswithDARLING_TEST_PGon Windows for the 35/0 ledger, and check nothing expectsDARLING_TEST_PGunmodified - Measure the fleet probe on a real fleet: one unbounded
LATERALper registered server, 10,903 buffers per render - Verify the viewer/MCP roles hold
SELECToncollect.servers, else every notice and banner silently disappears - Run the Node harness where
nodeexists:TryRenderreturns false onWin32Exception, so that test asserts nothing without it
… an older row, instead of a MIN over every archived row GetQueryWindowFloorAsync read the server's oldest row with an unbounded MIN(collection_time). DuckDB has no (server_id, collection_time) index to stop at the first row, so that MIN reads every archived row for the server: about 45 to 60 ms for a server with 90 days of rows against about 6 ms for the bounded probe it replaced, with a 7-day window. No caller needs the oldest row. The banner and the three MCP tools only ask whether the window was served whole (IsWindowTruncated, EffectiveWindowStart), and any floor at or before the requested start gives the same output. The probe is now two steps. The first is the bounded in-window MIN. It ends the probe when the window holds no row (NULL) or its first row sits on the start. Only when that first row is after the start does a second query ask, LIMIT 1, whether the server holds ANY row before the start. The answer is NULL (nothing in the window), the requested start (a row before the window: served whole) or the first row in the window (the data starts late). Tests: the quiet-start guard now expects the requested start, and so does the window-inside-the-rows test (both fail on the previous probe); new guards pin a row exactly on the window's start and that another server's older rows do not count as this server's coverage. Planting a lower bound on the older-row query fails the quiet-start guard.
…ata starts, and the window-floor probe no longer calls a quiet start a cut (#4958)
There was a problem hiding this comment.
Verdict: CHANGES REQUESTED
Detail is in the seven inline comments; this is the ledger.
Claims
- VERIFIED — the notice reaches both the web panel and
run_custom_view_panelfrom one place —DarlingWebEndpoints.cs:1322-1332;DarlingMcpCustomViewTools.cs:287is the tool's only path intoRunComposedPanelAsync. Its exact wording isComposeStoreAvailability.cs:357-361, pinned character-for-character byDataWindowFloorTests.TheNotice_NamesTheStartAndTheWindowItCovers_InUtc. - VERIFIED — Darling Active Queries / Current Waits banners on the range, deep-link and slicer reads —
ViewerServerTab.ActiveQueries.cs:76,91,110,ViewerServerTab.Blocking.cs:176,188,ViewerServerTab.xaml;ViewerDataStartBannerTestsasserts exactly 3 probe and 3 banner calls. - VERIFIED — "the served start these tools report never comes before the requested start" —
RawWindowFloor.cs:120-121,McpQueryTools.cs:986-987, wired atDarlingMcpDataTools.cs:641,854,1049,DarlingMcpQueryStoreClutterTools.cs:148,McpQueryTools.cs:82,215,344. - VERIFIED — "runs only when the tier notice is silent … a failed probe costs the panel its notice, not its chart" — gate at
DarlingWebEndpoints.cs:1322, swallow atComposeStoreAvailability.cs:343-347. - VERIFIED — "a stitched route asks both halves" —
DataStartSourcesscrapesCaggFromClause, whichStitchedRelationSql(TimescaleSupport.cs:13793-13795) emits as legacyUNION ALLsuccessor; both surviveTryForRollupandMINtakes the older legacy half. - VERIFIED — "a
LIMIT 1walk of the(server_id, <time>)index", andindex_object_statsexcluded for ordering by object first —PgSchemaGenerator.CreateIndex:112,114; every CAGG keeps(server_id, bucket)explicitly undercreate_group_indexes = false(TimescaleSupport.cs:2257-2261,2702,2750,2817,2864). The probe's time column is the samePrefixTimeColumnNameComposeCompiler.s_timeColumnByTable:86-87uses, andSource.EndExclusivematchesComposeCompiler.cs:351. - VERIFIED — the "no change needed" references — no
ComposeCompiler/PanelPlananywhere underPerformanceMonitor.Darling.Viewer;RunningJobs.cs:71,DrillDown.cs:329-337andBaselineCache.cs:58each say what the body says. The existing-test change adds["server"] = "compose-old-window-no-rows"and leaves the no-notice assertion untouched. - VERIFIED — "Lite asks in two steps … bounded on both sides, as before" (
LocalDataService.QueryWindowFloor.cs:93-119), and the census arithmetic matches: 10GetQueriesTabWindowUtcsites and 10 banner calls inServerTab.Refresh.cs, 4 slicer calls one.StartUtc/e.EndUtc. - UNVERIFIED — every EXPLAIN, buffer count, latency median and the "708.6 ms vs 0.228 ms" comparison, plus the Lite before/now table — live measurements against a 3.36M-row TimescaleDB store and a 29.3M-row Lite store; the Lite numbers are self-declared as Python DuckDB 1.4.4, not the engine Lite ships.
- UNVERIFIED — every failing-first count ("4 of 7", "3 of 10", "11 of 17", "19902/11", "35 of 35", "37 passed") and the four planted-failure reverts — each needs
DARLING_TEST_PGset, plus TimescaleDB for the rollup class; those classes areAssert.SkipWhen-gated without it. - UNVERIFIED — "Lite builds with 0 warnings" —
dotnet buildis unavailable here and the WPF projects do not build on Linux. - UNVERIFIED — "#4958 lists each surface" — an issue outside the tree.
Riskiest lines
Darling/PerformanceMonitor.Darling.Storage/RawWindowFloor.cs:75— droppingcollection_time >= $2redefines everywindow_truncated/effective_startthe three raw grids and four MCP tools have reported since #2364/#4231 — pinned byRawWindowFloorQuietStartLiveTests.AQuietStartInsideTheWindow_IsNotACut_AgainstDevPostgresandQueryStoreTopWindowTests.TheWindowFloorProbe_WalksTheIndexFromTheOldestRow_AndChecksTheWindowApart, but what they pin is the behaviour the first finding objects to, not a guard against it.Lite/Services/LocalDataService.QueryWindowFloor.cs:119— the twin, returningstartUtcas a sentinel, read by three MCP tools and five banners — pinned by five newQueryWindowTruncationTests.FloorHelper_*cases (exact-boundary and other-server included) and six inDataStartBannerTests; genuinely thorough boundary coverage.Darling/PerformanceMonitor.Darling.Service/DarlingWebEndpoints.cs:1325— a new store round trip on every Custom Views render with no tier notice, under the panel's owncomposedQuerySecondsceiling, after the panel query already succeeded — pinned for correctness byComposeDataFloorLiveTests/ComposeRollupDataFloorLiveTests; UNPINNED for cost.
Traps near this diff
- "A retention-tiered store answers a 7-day question from a 4-day raw tier and labels the missing days quiet unless the read routes by tier and says which tier served it (#3590; the viewer's charts in #3684)." — applies, inverted: a window whose first day holds no row is now labelled served, because
RawWindowFloor.cs:75lost its lower bound andEffectiveStart(:120) clamps to the requested start;DarlingMcpDataTools.cs:930then emitstruncation_note = null. - "Two copies of one definition pinned EQUAL to each other fail only after BOTH have drifted (#3684). Alias, do not copy." — applies:
DarlingMcpQueryStoreClutterTools.cs:89keeps its ownTimeSpan.FromMinutes(90)and:149its own hand-rolled verdict, one line under theEffectiveStartthis PR wired in. - "An anti-pattern census sweeps the class (every tool body); rosters are for the positive contract only (#3699)." — applies:
NoMcpTool_ComputesTheServedStartByHandbans only the stringfloor ?? requestedStart, so it sweeps that file and passes with:149intact. - "An empty analysis window is 'unavailable', not an all-clear (#3553)." — applies in the probe's favour: the EXISTS guard (
RawWindowFloor.cs:79-86) and the early return (LocalDataService.QueryWindowFloor.cs:105-108) both keep null for an empty window, pinned either side. - "Lite and Darling ship in parity … a fix to one SKU without the counterpart's is a finding (#3594)." — does not apply:
QueryWindowRelationgainsQuerySnapshots/WaitingTasks(LocalDataService.QueryWindowFloor.cs:28-29) against Darling'sDataWindowFloor, and both SKUs get both banners (Lite/Controls/ServerTab.xaml:371,:1722vsViewerServerTab.xaml:694,:2477). The compose notice has no counterpart to write — noComposeCompiler/PanelPlananywhere inLite/. - CONTRIBUTING's T-SQL style section, and "a clamp is a silent lie about the window (#3699)" — neither applies: the diff adds no T-SQL (the new SQL is PostgreSQL at
DataWindowFloor.cs:150-176, aliasedAS s/AS f/AS l/AS u, and DuckDB atLocalDataService.QueryWindowFloor.cs:93-116), and the clamp added is on a floor the store reported, not on a caller's argument.
Divergence (blind read vs PR body)
- "quiet for the first hours" vs. the hole the tests pin. The body motivates dropping the lower bound with sparse tables and "a server that was quiet for the first hours of a window". The two tests pinning the rule on the DENSE per-collection tables plant far more:
RawWindowFloorQuietStartLiveTestsseedsquery_statsat -8d then nothing until -6d against a 7-day window (a full day empty) and asserts not-truncated;FloorHelper_QuietStartInsideTheWindow_…seeds two rows 27 days apart and asserts the 7-day window reads as served whole. The body never says a collection outage, a re-pointed server or an offline target at the head of a window now answerswindow_truncated = false,effective_hours_back = 168. The direction of the trade is documented; its cost is not. get_query_store_clutter— "same floor". The surface table puts this tool on the same footing as the other three. Only its served start moved to the shared helper (:148); the verdict is still hand-computed over a local 90-minute literal. True today, but by coincidence, not construction.- Cost measured only in the shape that is fast. "One statement per panel render" is accurate and the EXPLAIN work is unusually thorough — the quoted
rows=0.25 loops=200even covers the no-rows servers I expected to be missing. Unquantified: scaling in chunk count, since a server with no rows must touch every chunk's index to answer "none", and the rig has 36wait_statschunks where a busy 4-day raw tier has more. Non-blocking, raised inline.
Everything else the body claims about the code matched the tree.
Reviewer checklist
- Decide finding 1: should
window_truncated/effective_startcarry "the store holds a row older than the window's start", or should the window's own first row ride beside it so a hole at the head is still disclosed? If the former, say so inRawWindowFloor's remarks and the body — it narrows a shipped honesty flag. - Build both SKUs and confirm "0 warnings":
DataWindowFlooris new,ApplyWindowFloorToBanner/QueryWindowRelationViewchanged accessibility, and nothing here compiles in a read-only Linux tree. - Run the live classes with
DARLING_TEST_PGset (TimescaleDB installed) and once unset; then run the whole assembly against a store NOT on UTC to prove the[ModuleInitializer]ordering claim inLiveStoreSessionTimeZone.cs. - Open both tabs on both SKUs: the Darling Active Queries grid moved to
Grid.Row="3"and both Current Waits charts shifted down a row — only a running window shows whether the collapsed banner leaves a gap. - Click Live Snapshot / Latest Snapshot with the banner up, and time a fleet Custom Views panel against the production store with the probe on the render path.
… banner pin follows the shared window-floor step The Darling live-test base string now carries the session time-zone pin, so the scratch store's unpinned string has to drop it. Without that, the unpinned session reports UTC instead of the database's own default, and the test that proves the product pin overrides that default fails. The Lite source pin for the Showing since banner looked for the old direct call. It now pins the shared window-floor step's call, its definition and its inner call, and a second check requires every call in the ServerTab files to hand the banner the tab's own picker zone as its last argument.
…-start notice from coverage, not the oldest row Coverage starts at the later of the server's first collection and the table's retention edge; a row in the window only moves it earlier. A window that starts at or after coverage shows no notice, whether or not it holds rows. Darling: first collection is the registry's created_date (written once at the first connect, never purged); the edge is the probe's clock less the collector's fleet retention days (the fleet override, else the schedule default). Servers count only with a row or a logged run in the window, so stopped servers' old rows no longer hide a new server's late start on a fleet panel. The per-server walk is bounded to the window. Lite: Active Queries and Current Waits also count the collector's runs in v_collection_log, which the single archive horizon keeps exactly as long as the tables. The Queries-tab relations keep the row-only probe. Checkpoint: not built or run yet.
…rver's oldest row Rollups, the raw relations the gated purge owns and the collectors whose purge is floored at the baseline window have no schedule edge. The draft read their coverage from the registry's first collection and the window's rows alone, so an old server showed no notice even when the window started long before anything the table keeps. Their edge is now the oldest row the server holds at or before the window's end, the rule before the probe read coverage. These tables are dense, so that row is where coverage starts. The walk sits in the select list, so it runs only for a server that counts. Pins follow the new shape: the scope is the fourth parameter, the window read has a lower bound, the join is LEFT JOIN LATERAL, and a server counts only with a row or a logged run in the window. A live test covers a Custom Views panel over a baseline-floored table for a server older than the window. Docs on the Lite banner step and the truncation helpers now say what a null floor means: no row, and for Active Queries and Current Waits no logged run. Checkpoint: written but not built or run yet.
…overage, not the oldest row The previous commit was written before it was built. It builds clean with 0 warnings for Darling, Lite and the Dashboard, and the targeted Darling classes (DataWindowFloorTests, ComposeDataFloorLiveTests, ComposeRollupDataFloorLiveTests, ViewerDataStartBannerTests, RawWindowFloorQuietStartLiveTests, RawWindowFloorEffectiveStartTests: 58 tests) and the Lite classes (DataStartBannerTests, DisplayZoneTextFrameTests, QueryWindowTruncationTests: 40 tests) pass against a local PostgreSQL with TimescaleDB. This commit only renames the one-server probe test and updates the viewer pin's class comment to the coverage rule.
…goes on, the viewer banner reads on the invariant culture, and the viewer pins check arguments A data-start probe that threw skipped everything after it. In Lite the Active Queries probe runs before the Query Stats grid bind and the Current Waits probe before the Locking tab's slicers and tab-badge counts; in the viewer the Active Queries probe runs before the slicer load. Lite's shared banner refresh now reads its probe through ProbeWindowFloorOrNullAsync, and the viewer's four probe awaits go through DataStartOrNullAsync: a probe that throws answers null (a null floor hides the banner, and ApplyWindowFloorToBanner also clears its text), the failure is logged at Warn in Lite and through ViewerLogger.Warn in the viewer, and the refresh finishes. Both helpers take the probe as an argument so the tests drive a throwing one without building the control. The web notice's probe catch now logs the exception at Debug through the runner's read-latency logger: the panel is still answered, and the probe runs once per panel run, so a standing fault at Warning would put a line in the service log on every refresh of every panel. The viewer's Active Queries, Current Waits and Queries-tab banners format their instants inside UpdateTruncationBanner with DisplayZone.Format on the invariant culture, as Lite's banner and the web notice do, so a Thai or Arabic default calendar no longer prints 2026 as 2569. ViewerTimeHelper.FormatForDisplay and its other callers keep the current culture. ViewerDataStartBannerTests now pins the arguments, as Lite's twin does with a regex: each probe gets its path's window (the toolbar's start and end, the deep link's pending bounds, the slicer's selection) and each banner is compared with that window's start (pending.FromUtc on the deep link, not the toolbar's start). New pins run a throwing probe in Lite and in the viewer, and read the banner under th-TH and fi-FI. ComposeDataFloorLiveTests skips when Node is missing instead of passing without running its check.
…fresh goes on The Top Queries, Top Procedures and Query Store grids awaited their window-floor probe bare. A probe that threw on a range load unwound it past the slicer and the comparison that follow the banner, and one that threw on a slicer drag unwound it past the comparison. Lite's Queries tab already goes through its catch. Each of the six awaits (a range load and a slicer drag on each grid) now goes through DataStartOrNullAsync, as Active Queries and Current Waits do, and the log line names the surface: Query Stats, Procedure Stats or Query Store. Every other argument of each banner call is as it was, and what each probe decides is unchanged. The helper's doc names these probes too. The pins check all six call sites for their probe, window, surface and window start, what follows the banner on each, and that no banner call on the tab awaits its probe bare.
Blind-read notes (full tier)Two things worth recording beyond the inline comments, neither a verdict driver. The two SKUs now answer "where does coverage start" by different mechanisms. Darling's The spliced retention edge is a second copy of What I checked and did not find a problem with
Traps I checked that do not apply
|
There was a problem hiding this comment.
Verdict: CHANGES REQUESTED
Detail for each item is in the top-level comment and the two inline comments on this PR.
Claims
- VERIFIED — the notice's exact wording —
ComposeStoreAvailability.cs:369-372, pinned byDataWindowFloorTests.TheNotice_NamesTheStartAndTheWindowItCovers_InUtc - VERIFIED — shows with the row-cap notice, not with the tier notice —
DarlingWebEndpoints.cs:1322-1332 - VERIFIED —
run_custom_view_panelshares the runner —DarlingMcpCustomViewTools.cs:287 - VERIFIED — floor is now the oldest row at or before the window's end, still null on an empty window —
RawWindowFloor.cs:68-87, pinned byQueryStoreTopWindowTests.TheWindowFloorProbe_WalksTheIndexFromTheOldestRow_AndChecksTheWindowApart - VERIFIED — served start never precedes the requested start, all 7 tools —
RawWindowFloor.cs:120-121,McpQueryTools.cs:255-256, every call site re-read - VERIFIED — fan-out 2 to 3 —
ViewerReadFanOut.Of(3)inViewerServerTab.Blocking.cs - VERIFIED — banner on grid, slicer and finding-card reads — 3 sites, pinned by
ViewerDataStartBannerTests.ActiveQueries_ShowsWhereTheSnapshotsStart_OnEveryReadOfTheGrid - VERIFIED — the viewer role can read
config_collector_schedules—DarlingManagedRolesTests.cs:105/:282; absent fromViewerRestrictedConfigTables - VERIFIED — purge edge = clock less fleet retention days, else schedule default —
DataWindowFloor.cs:234agrees withResolveFleetRetentionDays;RetentionPoliciesattaches none to these two tables - VERIFIED — Lite's two-step probe, runs counting in both, one shared horizon —
LocalDataService.QueryWindowFloor.cs:399-463,RetentionService.cs:23-33 - VERIFIED — invariant-culture banner, grids unchanged —
DisplayZone.cs:94-99, pinned under th-TH and fi-FI byTheBanner_NamesItsInstants_OnTheInvariantCulture - VERIFIED — a failed viewer/Lite probe costs only the banner —
DataStartOrNullAsync,ProbeWindowFloorOrNullAsync, bothAProbeThatThrows_...tests - VERIFIED — a failed web probe logs at Debug, panel still answered, cancellation still propagates —
ComposeStoreAvailability.cs:356-359 - VERIFIED — the changed existing test's point is unchanged (only a
serverscope added) - VERIFIED — Running Jobs / Agent status / Wait drill-down need no change —
ViewerDataService.RunningJobs.cs:65-68,ViewerServerTab.DrillDown.cs:335 - VERIFIED —
ScratchPostgresdrops the pin; the zone pin follows the shared step —builder.Remove("Timezone"),EveryWindowFloorBannerCall_IsHandedTheTabsPickerZone - VERIFIED —
index_object_statsexcluded by the generic index gate —DataWindowFloor.cs:135-137 - UNVERIFIED — the whole Cost section (EXPLAIN, 708.6 ms vs 0.228 ms, render medians, compressed-chunk grid, Lite's DuckDB medians) — live measurement; Lite's numbers are self-labelled as Python DuckDB 1.4.4
- UNVERIFIED — every failing-first transcript, the reverted planted failures and the suite totals — needs a build and a live
DARLING_TEST_PG; I confirmed each named test exists and asserts what the body says, not that it was red - UNVERIFIED — "a collector turned on after the first connect reads as covered: never a false notice" (self-labelled inferred) — mechanism confirmed, but no test covers a collector enabled after
created_date
Riskiest lines
Darling/PerformanceMonitor.Darling.Service/Compose/ComposeStoreAvailability.cs:369— no comparison ofdataStartUtcwithwindowEndUtc, and the schedule-edge arm can answer later than the window's end — UNPINNED (no test sendswindowStart/windowEnd)Darling/PerformanceMonitor.Darling.Storage/DataWindowFloor.cs:234— the spliced retention edge, a second copy ofResolveFleetRetentionDays, pinned only as a SQL substringDarling/PerformanceMonitor.Darling.Storage/RawWindowFloor.cs:68— the unbounded-below walk, which changes six existing readers' answers — pinned byRawWindowFloorQuietStartLiveTests
Traps near this diff
- "Two copies of one definition pinned EQUAL to each other fail only after BOTH have drifted (#3684). Alias, do not copy." — applies —
DarlingMcpQueryStoreClutterTools.cs:149still hand-rolls the verdict against its privateWindowFloorTolerance(:89); non-blocking, but that constant's doc comment is now wrong - "A retention-tiered store answers a 7-day question from a 4-day raw tier and labels the missing days quiet unless the read routes by tier and says which tier served it (#3590)." — does not apply — this diff is the remedy;
ComposeRollupDataFloorLiveTestspins the rollup's start, not raw's - "Lite and Darling ship in parity (CONTRIBUTING's two-store rule)" — does not apply — both SKUs got the banners here (
Lite/Services/LocalDataService.QueryWindowFloor.cs:55-56,ViewerServerTab.xaml) - "
ORDER BY 3 + 4 DESCis not 'ordinal 3 plus ordinal 4'" — does not apply — every ordering names a column (DataWindowFloor.cs:247,RawWindowFloor.cs:76) - "
CASE WHEN interval > 0 THEN delta / interval ELSE 0 ENDspells 'unknowable' as 0" — does not apply — no rate arithmetic; NULL reaches the caller as "nothing to report" (DataWindowFloor.cs:346) - "Truncation inferred from a full page:
truncated = rows.Count >= limit" — does not apply — a timestamp comparison with 90-minute slack (RawWindowFloor.cs:129-130) - "A pin that encodes the lie. Ask what a pin would fail ON." — does not apply — the live tests plant rows and read the rendered notice back; the culture pin asserts its own premise (
ViewerDataStartBannerTests.cs:245)
Divergence (blind read vs PR body)
The body's unqualified rule for the empty case — null only when no server has a row or a logged run, and a covered window with no rows answers its start or earlier — holds only for a window the store covers. For an UNCOVERED window with no rows, reachable because collection_log keeps 60 days while waiting_tasks/query_snapshots keep 7, the schedule-edge arm cannot reach null and answers the purge cutoff; when the window also ends before that cutoff (the absolute-window path), the notice inverts its own "covers X to Y" clause. The body never addresses a windowStart/windowEnd window and no test sends one.
Smaller: the body says get_query_store_clutter got the "same floor" — true of the floor, but that tool alone still computes its truncation verdict by hand, which the framing implies it no longer does.
Reviewer checklist
- Pin a Custom Views panel over
waiting_tasksto an absolute range older than its retention but insidecollection_log's 60 days and read the notice; the inline comment predicts a reversed "covers X to Y". - Re-run the Cost measurements on a store with far more than the 36
wait_statschunks measured; the probe now runs on every render where the tier notice is silent. - Confirm
LiveStoreSessionTimeZone's module initializer wins against the 400+ classes readingDARLING_TEST_PG, on a non-UTC store. - Watch the service log at Debug on a managed store for the swallowed probe failure, which costs every panel its notice silently.
…nd the clutter tool reads its truncation verdict from the shared helper DataWindowFloor.GetAsync and GetForServerAsync answer null when the coverage they find starts at or after the window's end. collection_log outlives a table the purge keeps shorter, so a logged run made a server count in a window whose rows were gone, and its coverage, the purge edge, came after the window ended: the Custom Views notice read "covers <edge> to <end>" with the end before the edge, and the viewer's banner said "Showing since" a time after its range. No new notice text; a window the store covers answers as before. The Query Store clutter tool takes window_truncated from RawWindowFloor.IsTruncated, as get_query_store_top does, and its private 90-minute tolerance, whose doc described a floor that is no longer the first row inside the window, is deleted. The guard against hand-computed served starts now also fails on a restated tolerance or a floor compared with the requested start by hand. Pins: three live tests in ComposeDataFloorLiveTests (a pinned window 45 to 40 days back gets no notice; a window 10 to 5 days back keeps its notice and covers to the window's end; both probes answer null for the 45-to-40-day window).
…e stitch boundary up The probe read both halves of a stitched rollup route whole, but the route reads the successor only from the stitch boundary up. When the successor had been materialized back past the boundary and the superseded half held nothing for a server, the probe found the successor's older buckets and reported a start below the boundary, with no notice, though the panel's data starts at the boundary. The router now carries the boundary on the route as a value (RollupCoverage.StitchFloor, beside the stitched clause on both tiers). A probe source for a rollup takes an optional lower bound that starts both the window read and the oldest-row walk, as a bind parameter numbered after the scope's. The successor half is probed with the boundary, found through the registry rather than by its place in the clause, and the superseded half is probed whole. The day-grain daily route now carries its FROM clause like every other rollup route (the compiled SQL is unchanged), so the probe no longer falls back to the relation name; a rollup route without a clause is refused. DataWindowFloor's remarks now say the probe answers by server identity (the registry's current name and server_id) while the panel filters rows by their stored server_name, so for a renamed server the rows written before the rename count toward coverage even though the panel's filter misses them.
…auses, and the no-notice live test registers its server (#4953) The tool description (head and tail) and the compose.js comment said a notice meant retention or the row cap. A notice also means the panel's own data starts after the window does, and an absent notice means the window was served whole. The head now names all three causes and drops its server and rollup sentences, which the tail already carries (pinned in the tail facts), to stay inside its length budget (609, down from 612). A new pin checks the head and the tail name every cause. The old-window live test scoped its panel to a server that was never in collect.servers, so the data-start probe read no table and its no-notice assertion passed whatever the store held. It now registers a sentinel server and removes it afterwards through the shared cleanup helper. With a row planted in the window for that server the assertion fails with the partial-window notice.
…rt tests carry the project's copyright header LiveStoreSessionTimeZone.cs, LiveStoreSessionTimeZoneTests.cs and RawWindowFloorQuietStartTests.cs were the only new files of the data-start change without the header the others carry (for example ComposeDataFloorLiveTests.cs).
…g since" banner the last range read raised, in Lite and the Darling viewer The Active Queries grids show a "Showing since <time>" banner when a range read starts after the stored snapshots do. Lite's Live Snapshot and the viewer's Latest Snapshot swap the grid for a different set of rows (the server's running queries now, the newest stored batch), but left the banner from the last range read up, so it described rows that were no longer there. Both handlers now hide the banner (collapsed, text cleared) as the new rows are bound, and not when the read fails, because the grid then keeps the range rows and the banner that describes them. Lite goes through the shared SetWindowTruncatedBanner step; the viewer collapses its banner directly, since its UpdateTruncationBanner takes a probe answer and leaves a hidden banner's text in place. The next range read raises the banner again through the existing path, which is unchanged. DataStartBannerTests (Lite) and ViewerDataStartBannerTests (viewer) each gain a pin that reads the handler's source: the hide appears once, after the rows are bound and before the failure arm.
… its own window, in Lite and the Darling viewer (#4953) A drill-down (the heatmap, the chart drills, the Overview drills) loads the Active Queries grid for a narrow window but never refreshed the banner, so it kept describing the last range read: it could claim a cut the drill window does not have, or miss one it does. Lite: OnActiveQueriesDrillDown and OnHeatmapDrillDown refresh the banner through the shared window-floor helper after the rows are bound. The drill window is a naive-UTC pair from GetDrillWindow, the grid read takes it unconverted, and the probe compares against UTC collection_time, so the same pair goes to the banner. Darling viewer: NavigateToActiveQueriesForWindowAsync starts the data-start probe for the drill window beside the rows read and sets the banner once the rows are bound, as the deep-link branch of the range load does. The count pin for this banner goes from three calls to four on purpose. Pins: DataStartBannerTests (Lite) and ViewerDataStartBannerTests (Darling) hold the new calls.
Resolved at c857763: every finding is fixed or answered in its thread.
| { | ||
| /* The table's edge is the purge cutoff: the schedule's horizon is the purge's, as written. The later | ||
| of it and the server's first collection is where coverage starts, whatever rows survive near it. */ | ||
| coverage = $"GREATEST($3 - make_interval(days => COALESCE((SELECT o.retention_days FROM config.config_collector_schedules AS o WHERE o.server_id IS NULL AND lower(o.collector_name) = '{collector}' AND o.retention_days >= 1 LIMIT 1), {days.ToString(System.Globalization.CultureInfo.InvariantCulture)})), s.created_date)"; |
There was a problem hiding this comment.
Non-blocking — the fleet-retention rule is now a second copy, and the pin is the copy.
DarlingRetentionHorizons.ResolveFleetRetentionDays (DailySummaryHorizon.cs:129) owns one rule: the fleet override when it is set and at least one day, else the CollectorScheduleDefaults default. This line restates that rule in SQL. The default days are aliased off the catalog (good), but the override predicate — server_id IS NULL, retention_days >= 1, first match — is a hand copy.
AScheduleGovernedTable_ReadsItsEdgeFromTheScheduleNotFromAWalk (DataWindowFloorTests.cs:83-84) pins this SQL's text, not its agreement with the resolver, so it would stay green through exactly the drift it should catch: move the validity floor off >= 1, or add a second condition to ResolveFleetRetentionDays, and the purge edge the probe reports silently stops being the purge's edge. That is the #3684 shape from .github/REVIEW-TRAPS.md ("Two copies of one definition pinned EQUAL to each other fail only after BOTH have drifted. Alias, do not copy."), with only one half pinned. The two agree today — I checked both.
Two smaller notes on the same line:
lower(o.collector_name) = '…'is case-insensitive on the column, where the canonical read (DailySummaryHorizon.FleetRetentionOverridesSql,collector_name = ANY($1)) is exact. A differently-cased fleet row would be honoured here and ignored by the purge.config.is spelled literally while the collect schema goes throughPgSchemaGenerator.CollectSchematwo lines down;ConfigSchemaexists.
| /* The tier notice judges a tier by the store-wide floors, so it is silent for a source with no rollups, | ||
| a store with no TimescaleDB, and one server whose rows start later than the rest. When it is silent, | ||
| ask where this panel's own rows start. The Query Store wide table reports its own start in the |
There was a problem hiding this comment.
Non-blocking — the third case in this comment is one a fleet panel does not get.
"…and one server whose rows start later than the rest. When it is silent, ask where this panel's own rows start" reads as a guarantee that the new probe covers the late-server case. On a fleet-scoped panel it deliberately does not: DataWindowFloor.FloorSql aggregates MIN(u.t) over the servers that count (DataWindowFloor.cs:241), so the earliest coverage wins and one server that started last week is silent behind any server that covers the window. AFleetPanel_StartsAtItsOldestServer_AgainstDevPostgres (ComposeDataFloorLiveTests.cs:182) pins exactly that: a 7-day fleet panel gets no notice "though the recent server's rows start a week back".
The behaviour is the right one and is the behaviour the class doc states ("the earliest coverage start among the servers that count"); it is this comment that promises more than the scope delivers. Reading it as a per-server guarantee is how a future reader would conclude a late server on a fleet dashboard is covered. Worth narrowing to the scoped case — e.g. "…and, for a panel scoped to it, one server whose rows start later than the rest."
| DateTime windowStartUtc, DateTime windowEndUtc, int commandTimeoutSeconds, CancellationToken cancellationToken, | ||
| ILogger? logger = null) | ||
| { | ||
| var sources = DataStartSources(sourceTable, route); |
There was a problem hiding this comment.
Non-blocking — this one call sits outside the try, so it is the one probe failure that can cost the chart.
The summary above says a failed probe "costs the panel its notice, never its chart", and the try three lines down keeps that promise for the probe itself. DataStartSources is called before it, and it throws (:400) for a rollup route with no FROM clause — so that one failure mode unwinds into RunComposedPanelCoreAsync and fails the whole panel, not just its notice.
I verified no production path can reach it: every new ComposeRoute( with a CAGG tier is at ComposeSourceRouter.cs:305, :363 and :372, all three now carry a clause, ComposeCompiler only ever sets ComposeRoute.Raw (:247), and EveryRollupRoute_CarriesTheFromClauseItReads (ComposeSourceRouterTests.cs:521) sweeps the router's outcomes. The throw is also documented as deliberate ("A rollup route without a FROM clause is a router defect, and throws"), so this is a note, not a request.
Still: moving the call inside the try would make the method's own stated contract true for every failure mode rather than for all but one, and would cost nothing — a router defect would then surface as a Debug line and a missing notice, which is what every other fault on this path does.
| /// <item><b>The table's edge:</b> where the table's own rows start. For a collector table the schedule governs | ||
| /// as written, it is the purge's cutoff: the probe's clock less the collector's fleet retention days (the fleet | ||
| /// override in <c>config.config_collector_schedules</c>, else <see cref="CollectorScheduleDefaults"/>, as | ||
| /// <see cref="DarlingRetentionHorizons.ResolveFleetRetentionDays"/> resolves it). The purge applies one horizon | ||
| /// to the whole table (per-server overrides never reach it), so this is the same for every server, and it does |
There was a problem hiding this comment.
Non-blocking — one way the schedule edge can be later than the probe assumes, which LEAST cannot correct.
The asymmetry here is worth a sentence in these remarks. The computed edge is $3 − fleet retention days, and LEAST(coverage, w.t) can only move the answer earlier: when the purge is behind, or dropped a chunk whose newer rows survive, a row inside the window pulls the start back and the notice agrees with the chart. That direction is safe, and the remarks already cover it ("it does not depend on a row or a chunk surviving near it").
The other direction has no corrector. purge_now with a custom horizon (DarlingWorker.StartPurgeNow → RunPurgeNowBackgroundAsync, "purges every collector to that horizon") leaves the real edge later than the schedule says. The probe then computes a coverage start earlier than the data really has, LEAST takes the smaller of the two and keeps it, and a window that genuinely lost days gets no notice. A lowered schedule is fine — the override subquery reads it — so this is only the one-off operator purge.
Narrow enough that I would not change the rule for it; but "the schedule's horizon is the purge's, as written" is the assumption, and the one documented way to purge off-schedule breaks it in the silent direction.
Callers sweep (the thing I most wanted to be wrong about)
No unpinned caller: every site either clamps or reads the floor only through Two more things I checked because the diff invites the question and the answer was not obvious:
|
What changes
Some windows reach further back than the rows the store holds. These surfaces now say where the data starts, instead of drawing a shorter range as if it were the whole window:
Custom Views panels in the web viewer. The
run_custom_view_panelMCP tool uses the same runner and gets the same notice. The notice reads like this: "partial window: this panel's data starts at 2026-09-25 16:00 UTC, after the window's start at 2026-09-02 16:00 UTC. The panel covers 2026-09-25 16:00 to 2026-10-02 16:00 UTC." It can show with the row-cap notice. It does not show when the retention-tier notice does. The tool's description names the three causes of a notice. The tier's retention did not cover the window, the panel's own data starts after the window does, or the row cap cut the result. No notice means the window was served whole. (seen:TheNoticeContract_NamesAllThreeCauses_InTheHeadAndInTheTail)Active Queries and Current Waits in the Darling viewer. By default,
query_snapshotsandwaiting_taskskeep 7 days. A custom range that reaches past them now shows the "Showing since ..." banner that the Queries tab already shows. A drill-down to Active Queries sets the banner for its own window. The Latest Snapshot read takes the banner down, because it shows the newest batch, not a range.The Queries tab banner, and four MCP tools:
get_top_queries_by_cpu,get_top_procedures_by_cpu,get_query_store_topandget_query_store_clutter. They read the raw window floor, which looked for the start inside the window. So a server that was quiet for the first hours of a window read as cut short. The floor is now the oldest row at or before the window's end, found the same way as above. It is still null when the window holds nothing. The served start these tools report never comes before the requested start. All four judge the cut through the sharedRawWindowFloor.IsTruncated.get_query_store_clutterhad kept its own copy of the 90-minute tolerance. (seen: tests below)Lite. Active Queries and Current Waits now show the "Showing since ..." banner when a range starts before the data's coverage. A drill-down to Active Queries sets the banner for its own window, and the Live Snapshot read takes it down. Lite's window floor also looked for the start inside the window. So the Queries tab banner and three MCP tools called a quiet start a cut:
get_top_queries_by_cpu,get_top_procedures_by_cpuandget_query_store_top. That no longer happens. The served start these tools report never comes before the requested start. (seen: tests below)The cause can be retention or a server that was added recently. A quiet start gets no notice when the store covered the whole window. (seen: the live tests below plant rows and logged runs and read the notice back)
Each surface and its result
run_custom_view_panelMCP toolMainWindow.Tags.cs,ViewerDataService.cs. (seen)query_snapshots)waiting_tasks)waiting_tasks. The tab's read fan-out widens from 2 to 3 for the probe (ViewerServerTab.Blocking.cs). (seen)query_stats,procedure_stats,query_store_stats)get_top_queries_by_cpu,get_top_procedures_by_cpu,get_query_store_top,get_query_store_clutterwindow_truncatedno longer fires for a quiet start, andeffective_startnever precedes the requested start. (seen)running_jobs)ViewerDataService.RunningJobs.cs:71). (seen)ViewerDataService.JobHistory.cs:463,:507). (seen)ViewerServerTab.DrillDown.cs:329-337). (seen)(server_id, <time>), so each such tab needs one data-service read and one banner. (inferred)v_query_snapshots)v_waiting_tasks)v_query_stats,v_procedure_stats,v_query_store_stats)get_top_queries_by_cpu,get_top_procedures_by_cpu,get_query_store_topwindow_truncatedno longer fires for a quiet start, andeffective_startnever precedes the requested start. (seen)RefreshVisibleTabAsync). (seen)How the start is found
The notice decides from coverage, not from the oldest stored row. Coverage starts at the later of two instants: the server's first collection by the table's collector, and the table's purge edge. A row in the window only moves it earlier. A window that starts at or after coverage shows no notice, whether it holds rows or not. A window that starts before it says where coverage starts.
DataWindowFloor(in Storage) asks this in one statement per panel render: aLATERALper server throughcollect.servers. (seen: tests below)waiting_tasksandquery_snapshotshold a row only while something waits or runs. A server idle overnight, whose older rows the purge dropped, has its first row hours after a 7-day window starts. A server whose first waiting task came 3 days ago has no row before that. The store covered both windows, and the oldest-row rule called both cut short. (seen: the RED below)created_date. The service writes it once, at the server's first connect, and no purge touches the registry.collection_logis not used for it. It keeps 60 days, and a fleet override can keep a table longer, so the log can forget a first run the table still covers. A collector turned on after the first connect reads as covered from that connect: no notice, never a false one. Lite reads coverage from its logged runs instead. So for a collector turned on late, Lite names where its runs start, and Darling shows no notice. (inferred from the code)config.config_collector_schedules, else the schedule default. The purge applies one horizon to the whole table, so the edge is the same for every server. The viewer's role can read that table:DarlingManagedRolesTestspinsSELECTon every config table. (seen)ABaselineFlooredTable_ForAServerOlderThanTheWindow_StillSaysWhereItsOldestRowIs_AgainstDevPostgres)BaselineCache.cs:58). Its old rows no longer hide a newer server's late start on a fleet panel. (seen:AFleetPanel_StoppedServersOldRows_DoNotHideALateStart_AgainstDevPostgres) After a server rename, the probe still finds the server by its registry row: its current name and server_id. The panel filters rows by their storedserver_name. So rows written before the rename count toward coverage, though the panel's filter misses them. (inferred from the code.DataWindowFloor's remarks say so.)collection_logkeeps 60 days andwaiting_taskskeeps 7, so a logged run can make a server count in a window whose rows are gone. That window lies wholly before coverage. Callers read null as nothing to report, as they do for a window older than the run log, and as Lite does. Such a panel is empty and shows no notice. A covered window with no rows answers its start or earlier, so it also shows no notice. (seen: the tests below)wait_statsrows, aserver_name = ANYfilter on the fact table took 708.6 ms. The per-server walk took 0.228 ms for one server and 3.410 ms for the fleet. (seen)EveryRollupRoute_CarriesTheFromClauseItReadspins that. (seen)RawWindowFloorwalks the same index from the oldest row. A bounded existence check keeps the floor null when the window holds nothing, because the MCP tools report that as an empty window. The served start is clamped to the requested start. (seen)(server_id, collection_time)index to stop at the first row. Reading a server's oldest row reads every archived row it holds, so Lite'sGetQueryWindowFloorAsyncsplits the question. Step 1 reads the first row inside the window, bounded on both sides. DuckDB can then skip archived data outside it (inferred from the timings below). Only when that row comes after the start does step 2 look for one older row, withLIMIT 1. For Active Queries and Current Waits, the collector's runs inv_collection_logcount as well as rows, in both steps. The log is archived and deleted by the same single horizon as the tables, so a run proves the window from then on is held. The Queries-tab relations keep the row-only probe. The answer is null when the window holds no row (and, for the two coverage tabs, no run). It is the start when an older row or run exists, and otherwise the first row or run in the window. (seen)(server_id, <time>), and the rollups a panel can read.index_object_statsis left out because its index orders by object before time. (seen:DataWindowFloorTests)RawWindowFloor.IsTruncated, with the same 90-minute slack the Queries tab uses. (seen)TheBanner_NamesItsInstants_OnTheInvariantCulture, under th-TH and fi-FI)Cost
EXPLAIN
These are EXPLAIN (ANALYZE, BUFFERS) results for the exact statements, on a local TimescaleDB test store. The store holds 200 registered servers (50 with rows), 3.36M
wait_statsrows in 36 chunks, and 707,040query_statsrows with both hourly rollups. (seen)waiting_tasks, one serverwaiting_tasks, fleetwait_stats, one serverwait_stats, fleetquery_stats_hourly, one serverquery_stats_hourly, fleetThe plan is a nested loop over
servers, which is the only Seq Scan (200 rows, 2 buffers). Under it, aLimitsits over aChunkAppendordered by time, with an Index Only Scan per chunk (Heap Fetches: 0). Chunks after the one that holds a server's oldest row show "never executed". A window that ends 20 days back excludes 20 chunks at startup and runs in 0.761 ms. (seen)Added render time per panel
This is the client time of one probe call through Npgsql: the median and p90 over 25 calls, after 3 warm-up calls. (seen)
waiting_tasks, one serverwaiting_tasks, fleetwait_stats, one serverwait_stats, fleetquery_stats_hourly, one serverquery_stats_hourly, fleetwait_statschunks. Planning time on a store with many more chunks was not measured. (inferred)The raw window floor
EXPLAIN (ANALYZE, BUFFERS) on the same store, for
query_statsand a 7-day window, run warm: (seen)Both halves are Index Only Scans on
(server_id, collection_time). Chunks after the first one that answers show "never executed". Cold, right after a restart, the recent-server case took 11.4 ms, with 54 blocks read. (seen)Lite's window floor
Medians in ms on a seeded Lite store: 29.3M rows, 40 servers, three monthly archive files and a 7-day hot table. The engine was Python DuckDB 1.4.4, not the engine Lite ships, so the absolute numbers for the app are inferred. Single cells moved 5 to 15 ms between runs. (seen)
LIMIT 1look for an older row. Reading the oldest row directly cost 47.5 ms in the 90-day, 7-day case. (seen)The coverage probe on compressed chunks
The EXPLAIN and render tables above were measured on the oldest-row probe, before the coverage rule. These time the coverage probe on a test store with 50 servers.
waiting_taskshad 6 of 9 chunks compressed, andquery_stats28 of 31, withsegmentby = server_id. Each cell is planning / execution in ms, with shared-buffer hits where measured. (seen)waiting_tasks, one server, 7 dayswaiting_tasks, fleetquery_statswalk (no schedule edge), recent serverquery_statswalk, fleetcollection_logwas empty on that store, so the logged-run check was not timed. Lite's timings above were taken before the coverage rule, which adds one bounded read ofv_collection_logfor two tabs. (seen)A change to an existing test
RunComposedPanel_OldWindow_AgainstPlainPostgres_RunsCleanOnRawnow scopes its panel to a server of its own. Without a scope, the panel reads the whole shared test store. Other tests' rows there start after the window's start, so without a scope the panel now gets the new notice.The test registers its server in
collect.serversand removes it afterwards through the shared cleanup helper. A scope that names a server the registry does not hold makes the probe read no table. The no-notice assertion then passes whatever the store holds. The point of the test is unchanged: the old window runs clean on raw, with no tier notice. (seen)Tests
Failing first, before the change, 4 of 7 failed: (seen)
The Darling viewer checks, before the viewer change, 3 failed: (seen)
What the live tests cover (each test makes and drops its own database):
AThirtyDayPanel_OverSevenDaysOfRows_SaysWhereTheDataStarts: a 30-day window over 7 days of rows gets the notice.TheRenderedPanel_ShowsWhereTheDataStarts: the web page renders the notice. The panel's answer goes through the realcompose.jsin Node (web-compose-notice-harness.mjs).AWindowTheRowsCover_GetsNoNotice: a window inside the rows gets no notice.AQuietStartInsideTheWindow_GetsNoNotice: a server with an older row before a quiet stretch gets no notice.AFleetPanel_StartsAtItsOldestServer: a fleet panel starts at its oldest server.AFleetPanel_StoppedServersOldRows_DoNotHideALateStart: a server stopped before the window does not hide a newer server's late start.AnIdleStart_WithNoOlderRow_OnAServerMonitoredForMonths_GetsNoNotice: a server collected for months, idle at the window's start, with no older row left, gets no notice.AFirstWaitThreeDaysAgo_OnAServerCollectedForThirtyDays_GetsNoNotice: a server collected for 30 days whose first waiting task came 3 days ago gets no notice.AServerAddedTwoDaysAgo_SaysSinceItsFirstCollection_NotItsFirstRow: a server added 2 days ago gets the notice, and it names the first collection, not the first row.ABaselineFlooredTable_ForAServerOlderThanTheWindow_StillSaysWhereItsOldestRowIs: a table the schedule gives no edge still names its oldest row.AnHourlyRoutedPanel_TakesItsStartFromTheHourlyRollup: this one needs TimescaleDB. Raw rows are trimmed to 3 days and the hourly rollup keeps 10. The notice names the rollup's start, not raw's.TheViewerProbe_ForOneServer_AnswersWhereItsCoverageStarts: the Darling viewer's one-server probe.Two planted failures, each reverted afterwards: (seen)
AQuietStartInsideTheWindow_GetsNoNoticered:Assert.Null() Failure: Value is not null.AnHourlyRoutedPanel_TakesItsStartFromTheHourlyRollupred:Not found: "2026-09-22 10:00 UTC".The raw window floor, before the change, 3 of 10 failed: (seen)
A planted change that drops the existence check turns
AServerWhoseRowsEndBeforeTheWindow_ReadsAsNothingred (Assert.Null() Failure: Value of type 'Nullable<DateTime>' has a value). It was reverted. (seen)The UTC session pin was tested on a store whose server runs in another time zone. Before the change, 11 of 17 failed: the new
LiveStoreSessionTimeZoneTests.ALiveTestSession_RunsInUtc_AgainstDevPostgres, 9 inFleetOverviewAzureMasterScopeLiveTestsand 1 inDailySummaryAzureMasterScopeLiveTests. After it, 35 of 35 passed on that store. (seen)Lite, before the change,
QueryWindowTruncationTestsran 17 tests and 3 failed: the quiet-start guard, the window-inside-the-rows guard and the MCP clamp guard. (seen)A planted lower bound on the older-row look (
AND collection_time >= $2) turns the quiet-start guard red again, with this line:floor 2026-10-02T16:20:24.7685560 must be the requested start 2026-09-25T18:20:24.7685565Z (the server holds a row before it), not the window's first row. It was reverted. (seen)What the Lite tests cover: a quiet start with older rows gets the requested start and no banner (for
query_statsandwaiting_tasks). A server whose rows all end before the window gets null. A range that starts before the oldest stored row is cut at that row. That holds in the probe and in the Active Queries and Current Waits banner text. They also cover a row exactly on the window's start, and another server's older rows, which do not count. (seen)The first CI run on the merged branch failed two tests that this PR broke. Both are fixed. (seen)
StoreSessionTimeZoneLiveTests.AStoreConnection_PinsToUtc_EvenWhenTheDatabaseDefaultIsAmericaNewYorkexpected the database's ownAmerica/New_Yorkdefault from the scratch store's unpinned connection, and gotUTC. The UTC pin that this PR adds to the test store's connection string reached that unpinned string too.ScratchPostgresnow drops the pin from it.DisplayZoneTextFrameTests.TheRefreshHeaderAndTheTruncationBanner_UseTheTabsOwnClockAndZonelooked for the banner call's old text. The pin now follows the shared step,ApplyWindowFloorToBanner(banner, floor, startUtc, GetPickerZone()). A new check,EveryWindowFloorBannerCall_IsHandedTheTabsPickerZone, requires every call to hand the banner the tab's own zone. A plantedTimeZoneInfo.Localturned both tests red. It was reverted.DataWindowFloorTestschecks the SQL shape, which tables and rollups are accepted, each route's source list, and the notice text. These checks were written after the code, so they did not fail first.The coverage rule
Failing first: the new and changed test files, run against the product code at
1337f701f. Two calls went back to the old signature, so the copy compiled. (seen)DataWindowFloorTestsshape pins and 4 areComposeDataFloorLiveTests, among themAnIdleStart_WithNoOlderRow_OnAServerMonitoredForMonths_GetsNoNotice_AgainstDevPostgresandAFirstWaitThreeDaysAgo_OnAServerCollectedForThirtyDays_GetsNoNotice_AgainstDevPostgres.DataStartBannerTests: 10 run, 3 failed, among themCurrentWaits_IdleStart_WithNoOlderRow_OnAServerMonitoredForMonths_ShowsNoBannerandFirstRowThreeDaysAgo_OnAServerCollectedForThirtyDays_ShowsNoBanner.1337f701f, because its edge is the rule before this change.A failed probe, the probe's arguments, and the banner's culture
Failing first: each new pin ran against a temporary revert of its fix, and then the file was restored byte for byte. (seen)
AProbeThatThrows_HidesTheBanner_IsLogged_AndLetsTheLoadGoOn.ActiveQueries_RangeLoad_AsksAboutTheToolbarWindow_AndComparesWithItsStart, with the probe's start and end swapped.ActiveQueries_DeepLink_AsksAboutThePendingWindow_AndComparesWithItsStart, with the toolbar's start in place ofpending.FromUtc.TheBanner_NamesItsInstants_OnTheInvariantCulture, under th-TH and under fi-FI.AProbeThatThrows_HidesTheBanner_IsLogged_AndLetsTheRefreshGoOn.ComposeDataFloorLiveTestsnow reports a skip, not a pass, when Node is not installed.3b06e9b7a: 30 run, 8 failed. They are the six new call-site pins (three range loads, three slicer drags), the extendedNoLoadAwaitsItsProbeBare_AndTheDefaultLogIsTheViewersOwn, and the changed Query Store pin inRawWindowFloorViewerPortTests. (seen)A window wholly before coverage
Failing first, at
8c46cb58b: (seen)ComposeDataFloorLiveTests: 14 run, 2 failed.AWindowWhollyBeforeTheRetentionEdge_WithLoggedRuns_GetsNoNoticegot a notice that named the purge edge, a week after the window's end.TheProbes_AnswerNothing_ForAWindowWhollyBeforeTheRetentionEdgegot that edge from the probe instead of null.AWindowStraddlingTheRetentionEdge_NamesTheEdge_AndCoversToTheWindowsEndpasses before and after. It checks that the fix does not answer null too often.RawWindowFloorEffectiveStartTests.NoMcpTool_ComputesTheServedStartByHandnow also fails on a private 90-minute tolerance, or on a floor compared withrequestedStart +. It failed on the clutter tool before the fix, and again with the old line planted back.Stitched routes, the tool's text, and the Active Queries banner
Each check below failed first. (seen)
DataStartSources, which gives the probe as it was. Then the newAStitchedHourlyPanel_StartsAtTheStitchBoundary_WhenTheSuccessorWasMaterializedBackPastIt_AgainstDevPostgresfails withAssert.NotNull() Failure: Value is null: no notice. With the bound, it passes, and the notice names the boundary.TheDayGrainDailyRoute_CarriesItsFromClause_SoTheDataStartProbeReadsItandEveryRollupRoute_CarriesTheFromClauseItReadsfail:Expected: "collect.query_store_stats_daygrain_daily AS f",Actual: null. With the clause, both pass.McpToolGuideHeadsCustomViewTestsran 3 tests and 2 failed. The newTheNoticeContract_NamesAllThreeCauses_InTheHeadAndInTheTailfailed withNot found: notice is a partial-window caveat. The served head of the description went from 612 to 609 characters, inside its budget. Two facts it dropped, the server scope and the 90-day limit, stay in the tail, and two new pins keep them there.query_statsrow planted 1 hour back for the test's own server,RunComposedPanel_OldWindow_AgainstPlainPostgres_RunsCleanOnRawfailsAssert.Nullwith the partial-window notice. With the plant removed, it passes.LiveSnapshot_HidesTheActiveQueriesBanner_AsTheLiveRowsAreBound_AndNotWhenTheReadFailsfailed (11 run, 1 failed). The viewer'sLatestSnapshot_HidesTheActiveQueriesBanner_AsTheBatchIsBound_AndNotWhenTheReadFailsfailed too (19 run, 1 failed).ActiveQueriesDrillDowns_RefreshTheBannerForTheDrillWindow_AfterTheRowsAreBoundfailed both its cases. The viewer'sViewerDataStartBannerTestsran 20 tests and 2 failed: the newActiveQueries_WindowDrill_AsksAboutTheDrillWindow_AndComparesWithItsStart, and the count pin. That pin goes from 3 calls to 4 on purpose.Totals
#1776 own-storecomment onComposeDataFloorLiveTests, whichLivePostgresCollectionHygieneTestsrequires. Ten were inFleetOverviewAzureMasterScopeLiveTests(9) andDailySummaryAzureMasterScopeLiveTests(1), on a test store whose server runs in another time zone. This PR fixes both. The comment is in place, and the live tests' connection now setsTimezone=UTC, as the product's store connections do (DarlingStoreConnection.cs:58). A re-run of those classes and this change's live classes passed: Total 35, Failed 0. (seen)DataWindowFloorTests,ComposeDataFloorLiveTests,ComposeRollupDataFloorLiveTests,ViewerDataStartBannerTests,RawWindowFloorQuietStartLiveTests,RawWindowFloorEffectiveStartTests). Lite.Tests 40 run, 0 failed (DataStartBannerTests,DisplayZoneTextFrameTests,QueryWindowTruncationTests). Darling, Lite and the Dashboard build with 0 warnings. (seen)ViewerDataStartBannerTests,RawWindowFloorViewerPortTests,DataWindowFloorTests,DarlingComposeTests).ComposeDataFloorLiveTestspassed 11 of 11, none skipped, so Node ran. Lite.Tests 54 passed, 0 failed (DataStartBannerTests,DisplayZoneTextFrameTests,DataStartBannerProbeFailureTests,QueryWindowTruncationTests,ComparisonWindowUtcTests,ServerTabCapabilityPinTests). Darling, Lite and the Dashboard build with 0 warnings. (seen)ViewerDataStartBannerTests,RawWindowFloorViewerPortTests,QueryStoreClutterViewerSurfacesTests,ViewerSlicerMetricMapTests,DocCommentHygieneTests). Darling, Lite and the Dashboard build with 0 warnings. (seen)ComposeDataFloorLiveTests14,RawWindowFloorQuietStartLiveTests3,QueryStoreClutterLivePostgresTests2). Non-live, 336 run, 0 failed, among themDataWindowFloorTests,RawWindowFloorEffectiveStartTests,ViewerDataStartBannerTests,QueryStoreClutterTestsandMcpPayloadContractCensusTests. Darling, Lite and the Dashboard build with 0 warnings. (seen)ViewerDataStartBannerTests,DocCommentHygieneTests,RawWindowFloorViewerPortTests). A wider run of 404 tests across about 24 related classes had 0 failed and 2 skipped, which need a database. Darling.Tests, Lite.Tests, the viewer, Lite and the Dashboard build with 0 warnings. (seen)CHANGELOG
No entry in this PR; the release owner adds it under [Unreleased].
Proposed entry: