Repository navigation
MCP: Lite's system-health, default trace, wait stats and blocking stats tools say where their data starts (part of #4966) - #5172
Merged
Conversation
…rmatter pin (part of #4966)
… on significant waits (part of #4966)
…ere their data starts (part of #4966) get_default_trace_events, get_wait_stats and get_blocking_stats now write effective_start, window_truncated and truncation_note right after hours_back on a data answer, with the contract the other Lite window-floor tools use; an empty answer carries the same keys under hints. get_blocking_stats reads two collectors and says one thing, from the earlier of the blocked process report coverage (with the DMV snapshots beside it) and the deadlock coverage. get_wait_stats keys on the data answer only; its no-rows unavailable answer stays bare. get_daily_summary_range needs none: each day it returns carries its own data_state and the payload names the retention_horizon. Part of #4966
… blocking and deadlock floors, and pin both series (part of #4966)
…es' starts (part of #4966)
…to HEAD # Conflicts: # Darling/Darling.Tests/McpPayloadContractCensusTests.cs
# Conflicts: # Darling/Darling.Tests/McpPayloadContractCensusTests.cs
This was referenced Oct 5, 2026
erikdarlingdata
marked this pull request as ready for review
October 5, 2026 06:33
12 of 14 tasks
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.
Thirteen more Lite MCP tools now say where their data starts. This PR also carries the default trace, wait stats and blocking stats work first opened as #5180, folded in so the two land together; #5180 is closed.
System health: the nine
get_health_parser_*toolsWhat an MCP client sees
The nine
get_health_parser_*tools (system_health, severe_errors, io_issues, scheduler_issues, memory_conditions, cpu_tasks, memory_broker, memory_node_oom, significant_waits) now say where this server's system_health data starts.effective_start,window_truncatedandtruncation_noteright afterhours_back, always present. A covered window givesfalse,nulland the asked start.effective_startis UTC with a Z. There is noeffective_hours_back.emptyanswers carry the same three keys underhints. This covers all threeemptyrungs of the empty ladder: events captured and gated out, a quiet window, and a session that is read but never recorded this type. A window the store holds nothing in giveseffective_start: nullandwindow_truncated: true, so an empty answer past coverage no longer reads as "nothing happened".unavailableandnot_collectedanswers are unchanged and carry no keys.The envelope is built in one place: a private
WindowNoticeAsynchelper inMcpHealthParserTools, andWitnessStatus(the empty ladder's one builder) takes an optionalhints. The probe isGetQueryWindowFloorAsync(SystemHealthEvents, ...), the same source the nine reads window on (v_system_health_events,event_time). It counts events of every type, because one collector stores them all, so it says where the session's capture starts, not where one category's first hit sits. The code comment says so.The event-time decision
EventWindowNoticeAsyncis not used. A first run of this collector can store events from before itself (up to the 10-minute event fallback window), but the probe already readsevent_time, the same column the reads window on. So it names such an event itself, and no row on a page can be older than the probe's floor. A test seeds a first run 100 minutes into the window with an event from 30 minutes in, and checks that all nine tools name the event and reportwindow_truncated: false.Test plan
Lite.Tests/McpWindowNoticeSystemHealthToolTests.cs, a theory over the nine tools with a fixedas_of: a notice when collection starts inside the window; none on a quiet start; the key order; a short window starts no probe; a capped page (limit: 1) leaves the notice unchanged; the first-run backfill; empty past coverage carries hints; empty with nothing held; empty but covered; the gated-out rung; an empty short window is probed; a never-captured server stays bare.--no-incremental: 0 warnings, 0 errors.McpWindowNoticeSystemHealthToolTests+McpWindowNoticeToolTests: Total: 135, Failed: 0.McpPayloadContractCensusTests68/0,EffectiveStartUtcTests15/0 (a new pin counts nineeffective_startwrites and three hints calls, and bans anEventWindowNoticeAsync(call in the file). The census roster listsMcpHealthParserTools.csforwindow_truncatedandtruncation_note.LivePostgresCollectionHygieneTests(WPF-only).GetPropertythrows.Review additions, at
b0285c739:significant_waitsas well as the memory broker.McpWindowNoticeSystemHealthToolTests, 97 tests, 0 failed.Default trace, wait stats and blocking stats
Three more Lite MCP tools now say where their data starts, with the contract the other Lite window-floor tools use (#5004, #5015, #5127).
get_daily_summary_rangeneeds no notice, and the reason is below.What an MCP client sees
On a data answer,
get_default_trace_events,get_wait_statsandget_blocking_statswrite three keys right afterhours_back, in this order:effective_start: UTC with a trailing Z. It is the start that was asked for when the store held the whole window.window_truncated: true when the store's data starts more than 90 minutes after the asked start.truncation_note: the usual sentence naming the table, or null when covered.Notes on each tool:
get_default_trace_eventsnamesdefault_trace_events. The Default Trace stores its times in the monitored server's wall clock. The probe converts each candidate row to UTC through that server's own clock (the read does the same), soeffective_startis UTC like every other. The probe readsevent_time, the column the read windows on, so no row on a page is older than its floor and the event-time form is not needed.get_wait_statsnameswait_stats. The keys ride on the data answer only. The no-rows answer isunavailableand stays bare, as the contract says.get_blocking_statsreturns two separate series in one answer, blocking and deadlocks, and writes ONE notice for the payload, at the LATER of the two series' start points. Inside the blocking series, the blocked process reports and the always-on DMV blocking snapshots stand in for each other, so the earlier of the two is the blocking start (the same also-covered rule the Blocked Process Reports grid uses). Between the two series the later start wins: a series whose collection began inside the window has an empty head, and that head would read as "no deadlocks" (or "no blocking") next to the other series' data. When both series are covered from before the window, there is no notice. The note namesblocked_process_report and deadlocks. Neither probe needs the event-time form: each reads the column its series windows on (event_time,deadlock_time).get_default_trace_eventsandget_blocking_statscarry the same three keys underhintson anemptyanswer, and always probe, whatever the window's length.not_collectedandunavailablekeep their shape.get_blocking_statsthat skips both probes.effective_hours_backis written:get_wait_statsandget_default_trace_eventscarry a pagetruncated/shown, and the census holds that key apart.Sparse tables: none of these probes names a sparse table's oldest row.
GetQueryWindowFloorAsynccounts the collector's runs for all four relations (default_trace_events,wait_stats,blocked_process_report,deadlocks;dmv_blocking_snapshotfor the DMV arm), as the collector map inQueryWindowRelationCollectorshows. A quiet server with the collector running from before the window reads covered. There are tests for that for each tool.get_daily_summary_range: no noticeThe reader (
LocalDataService.GetDailySummaryRangeAsync,Lite/Services/LocalDataService.DailySummary.cs:173) returns a row for each day in its day spine, and each row carries its own state.ReadDailySummaryRow(:~270-293) setsDataStatefrom the day, its collector runs, its signal presence and the retention horizon, and stampsRetentionHorizonon the row. The tool (Lite/Mcp/McpHealthTools.cs) serialises both:retention_horizon,days_before_horizon,purged_day_count,collected_day_count, and per daydata_stateanddata_note. A day before the horizon sayspurgedorpast_horizonwithhealth_bandNoData, never Healthy. A day the spine does not hold is absent, and the tool's description and its empty answer both call that a collection gap, not a quiet day. The desktop viewer's Daily Summary says the same through the same two fields (DataState,RetentionHorizon). A notice would repeat that, so I added none. A comment at the top of the tool's body says so, andDailySummaryRange_CarriesItsOwnDataState_AndNoWindowKeyspins both halves.Test plan
--no-incremental: 0 warnings, 0 errors.McpPayloadContractCensusTests: 68 total, 0 failed (rosters now listMcpDefaultTraceTools.cs; thewindow_truncatedandtruncation_noteprose names the three tools).EffectiveStartUtcTests: 16 total, 0 failed. The shared-notice pin now coversMcpDefaultTraceTools.cs,McpWaitTools.csand the second write inMcpHealthTools.cs.LivePostgresCollectionHygieneTests, which cannot run on the Mac.McpWindowNoticeAggregateToolTestsandMcpWindowNoticeToolTests, 77 tests, 0 failed. After the review fixes (the blocking stats rule, three new cases, the daily-summary guard),McpWindowNoticeAggregateToolTestsagain: 32 tests, 0 failed.Lite.Tests/McpWindowNoticeAggregateToolTests.cs, fixedas_ofanchor. Per tool: a notice when collection starts inside the window; none on a quiet start; the key order; a short window starts no probe; empty or unavailable as the contract says; forget_default_trace_eventsthe floor converted from the server's wall clock; forget_wait_statsa capped page next to a floor, and the bareunavailable; forget_blocking_statsthe earlier coverage wins in both orders, one source covering from before the window makes it covered in both orders, the DMV collector counts, and one notice only (none inside either series).GetProperty, which throws when the key is absent.Checks on the combined head
McpPayloadContractCensusTests,EffectiveStartUtcTestsandMcpMissMessageParityPinTests: 85 tests, 0 failed, with both parts' roster rows.CHANGELOG
SECTION: Fixed
ENTRY: - Lite's system-health MCP tools say where their data starts ([#5172]) - the nine
get_health_parser_*tools now returneffective_start,window_truncatedandtruncation_noteafterhours_back, and the same keys underhintson an empty answer, so an empty answer over a window the store does not reach back to is no longer read as "nothing happened".ENTRY: - Lite's default trace, wait stats and blocking stats MCP tools say where their data starts ([#5172]) -
get_default_trace_events,get_wait_statsandget_blocking_statsnow writeeffective_start(UTC),window_truncatedandtruncation_noteafterhours_back, so a window the store never covered no longer reads as a quiet one.get_blocking_statsgives one notice from the later of its blocking and deadlock start points, so an uncovered deadlock half no longer reads as "no deadlocks". An empty default trace or blocking answer carries the same keys underhints.REF: [#5172]: #5172
Part of #4966