Repository navigation
The clutter view had no viewer and told every reader the capture mode was uncollected: the web server tab and the Viewer's Query Store Clutter grid now read the same rows, and the config arm reads the V137 column instead of stubbing it - #3841
Merged
Merged
Conversation
… was uncollected: the web server tab and the Viewer's Query Store Clutter grid now read the same rows, and the config arm reads the V137 column instead of stubbing it #3797's second lane. The reader and the composition move to PerformanceMonitor.Darling.Storage beside the DarlingPg*Reader family, for the reason that folder exists: the web page reads the MCP tool and the WPF Viewer runs the same statements in-process, so neither surface carries a second copy of the SQL or a second spelling of a verdict. The config arm now selects query_capture_mode. The V137 rung (#3796) created the column, the shared collector fills it hourly, get_query_store_health and both Viewers' Query Store grids already read it — this view was the one surface still publishing null with capture_mode_known false and a note saying the rung had not landed. The churn recommendations name the mode they are looking at; a null is published as a pre-rung capture, never as the engine's NONE. No band moves: the mode steers the wording only. Web: one fetch of get_query_store_clutter on the Queries tab, three panels — the per-database rows, the per-server QDS wait block and the memory clerk. Viewer: a Query Store Clutter sub-tab after Query Store Regressions, with the grid, the selected row's recommendation and the per-server overhead block. A readable secondary is a row on both, carrying excluded_reason, never filtered out.
…to keep: the grid takes none, because the arrival order IS the ranking The composition orders rows worst-first by band, then the read-cost share, then plans per query. A DataGrid's default sort is one column, and the stand-in this grid had — the Verdict text descending — sorts alphabetically: Warning, Unknown, Healthy, Critical. That is the ranking reversed at the top of a grid whose job is to put the worst database first, and it would look like a working sort. Pinned, with the reasoning on the pin, so the next reader does not restore it as a missing line.
The web tab's header named the third panel as the fleet reference, which is the memory clerk, and claimed a panel prints the fleet-median note, which none does. It now names the three panels it builds and says what not sending include_fleet_median actually leaves on the payload. The reader carried no account of why it sits in .Storage rather than the service's Mcp folder, which is the first question its new path raises. It carries the #2530 reason now: three surfaces answer this question and the WPF Viewer has no route to the service, so the alternative to one copy is two.
…olumns bind numbers, and the em-dash moves onto the binding Every measured cell was a pre-formatted string, so a DataGrid sorting on the binding's path put 9 above 1,234 and 0.9 above 0.10 — on the one grid in the Viewer whose purpose is to rank databases by magnitude, and it looked exactly like a working sort. The row now carries nullable numerics, which WPF sorts correctly, and each column's binding carries StringFormat for the value and TargetNullValue for the absence, so an unmeasured arm still reads as the em-dash every other Viewer grid uses without becoming text or becoming a zero. Only the genuinely textual cells — the band, the reason tokens, the exclusion and the capture mode — stay strings. The timestamp column follows the same rule: it binds the converted DateTime rather than its rendering, so it sorts chronologically.
…n displaced, a roster it joined without declaring, and a SQL shape it changed All three were mine, all three were caught by CI rather than here, and all three are now replicated locally so red-before/green-after is provable without a CI round trip. Inserting two tests above `Between` pushed that method's doc block off it: the block was left stranded on the member below and `Between` was left undocumented, which is the #1745 displaced-block shape the rule warns about rather than a duplicate to delete. The block moves back onto `Between`. `QueryStoreClutterViewerSurfacesTests` reads repo files through the LF reader, so it belongs on `RepoFileAdoptionTests`' roster, at its sorted position, with the reason it needs LF written beside it: its pins slice regions out of `ViewerServerTab.xaml` and `server-tabs.js` between anchors several lines apart, and anchor the sub-tab dispatch on the awaited call on the next line. `ConfigSql`'s projection pin anchored `capture_time` on the line break that followed it, to tell the projected column from the one in the ORDER BY. Appending `query_capture_mode` moved that break. The pin is not loosened to match: one anchor now carries three facts — `capture_time` is projected, the mode follows it, and the mode is the LAST projected column, which is what makes the reader's ordinal 12 the mode rather than a shift of every ordinal before it. The rung reference moves from a comment inside the SQL to the doc above it; no other statement in this file carries inline comments.
This was referenced Sep 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
get_query_store_cluttershipped in #3814 with no viewer and with its config arm hard-coded toquery_capture_mode: null, capture_mode_known: falsebeside a note saying the column would land with the V137 rung. The rung had already landed: V137 (#3796) createdcollect.query_store_health.query_capture_mode, the shared collector fills it hourly,get_query_store_healthpublishes it on both SKUs, and both desktop Viewers' Query Store grids already render it. The clutter view was the only surface left telling a reader the mode was uncollected, and it said so inside the recommendation an operator would act on. This lane builds the two missing viewers and reads the column.The reader and the composition move to
.StorageDarlingQueryStoreClutterReaderandQueryStoreCluttermove from the service'sMcp/folder toPerformanceMonitor.Darling.Storage, beside theDarlingPg*Readerfamily and for the reason that folder exists (#2530, stated in its own csproj): the web page reads the MCP tool over HTTP, the WPF Viewer reads the store directly, and the alternative to a shared reader is a second copy of four statements carrying a window floor, a discrete-median definition that has to agree withpercentile_disc, and a replica gate read off one engine bit. A copy that drifts on any of those calls a database Critical on one surface and Healthy on the other, and the copy that drifted is never the one being read.The move is otherwise mechanical: namespace and visibility, the two command helpers that stayed behind swapped for
.Storage's own spellings (StorageCommandDeadlines.McpReadSeconds, and a local naive-UTC binder with theKind=Unspecifiedreasoning theDarlingPg*readers carry), and the deadline consequently 30 s rather than 20 s — the constant every shared reader serving both front ends already uses..Storagegains aPerformanceMonitor.Commonproject reference, because the composition speaks the band canon (HealthSeverity) and thereadonly_reasondecode, and restating either here would be the duplication this move exists to avoid. The two lock files that carry aperformancemonitor.darling.storageentry gain the one dependency line--locked-modeneeds.The config arm reads the capture mode
ConfigSqlselects one more existing column;ConfigRowcarries it; the payload publishesquery_capture_modewithcapture_mode_knownbeside it, and the server-level flag is the AND over the rows, so one database still on a pre-rung capture makes it false rather than being averaged away. A NULL is published as never asked and never as the engine'sNONE, which is a mode a store can really be in.QueryStoreClutter.CaptureModeClauseis the one sentence both churn recommendations end on, written from the mode the row carries:ALLbeside churn is the switch-to-AUTOcase,AUTObeside it points at the workload,CUSTOMisAUTOwith thresholds this row does not collect,NONEmeans the churn is inside the queries already held, and anything else is printed verbatim rather than mapped onto a default. No band moves — the mode steers the wording and never the verdict, which is pinned so a capture mode cannot become a threshold nobody published.Web
One
fanoutofget_query_store_clutteron the Queries tab, after Query Store Regressions, feeding three panels: the per-database rows, the per-server non-sleepQDS_*wait block, and the Query Store memory clerk. One fetch because the read composes four arms over two raw hypertables and three descriptors would pay for that three times on one tab. The verdict cell is coloured off the band the server computed — the page re-derives no threshold — with the reason tokens beside it so the colour is never the only evidence, and the recommendation cell is the server's own prose behind a disclosure.include_fleet_medianis deliberately not requested: it walks the two raw hypertables fleet-wide, and a server tab is a per-server question.Viewer
A Query Store Clutter sub-tab in the Queries group, between Query Store Regressions and Plan Corrections, loaded by its named index constant through the existing sub-tab dispatch.
ViewerDataService.QueryStoreClutter.cscalls the five shared arms and the shared composition and contains no SQL at all; what it adds is the projection, because the grid cannot bind a nullable record graph — each arm flattened with the absences rendered as the em-dash every other Viewer grid uses for "not measured". Selecting a row prints its recommendation whole, and the per-server overhead block sits in its own expander labelled per-server, with the sleep waits the collection filter drops named from the shared list rather than restated.Every measured column binds a nullable number with
StringFormatfor the value andTargetNullValuefor the absence, rather than a pre-formatted string. ADataGridsorts on the binding's path, so text columns would sort 9 above 1,234 and 0.9 above 0.10 on the one grid in the Viewer whose purpose is to rank by magnitude — and it would look like a working sort. The em-dash an unmeasured arm shows is the binding's, so the absence still reads like every other absent cell without becoming text or becoming a zero; the timestamp column binds the convertedDateTimefor the same reason.The grid takes no default
SortDescription, unlike the grids beside it, and that is the decision rather than the omission: the composition orders rows worst-first by band, then the read-cost share, then plans per query, and the nearest single-column stand-in — the Verdict text descending — sorts alphabetically into Warning, Unknown, Healthy, Critical. That is the ranking reversed at the top of a grid whose job is to put the worst database first, and it would look like a working sort. The arrival order is the ranking, and it is left alone until the user sorts a column themselves.Replicas
A database whose
readonly_reasoncarries the readable-secondary bit stays in the grid on both surfaces withexcludedset andexcluded_reasonnaming the architecture —Excluded/Excluded Becausecolumns in the Viewer,excluded_reasonon the web row. Dropping the row would leave an operator who knows the database exists unable to tell "not cluttered" from "not shown", and file the second as the first. The projection's only filter is the tab's database filter, applied to the composed rows rather than inside the read so the per-server denominators keep meaning what they mean; that is pinned as the exact filter expression rather than as a count ofWherecalls, because the overhead projection has a filter of its own and a count would be satisfied by moving the wrong one into the right total.Censuses
Both censuses the brief flagged are PostgreSQL-scoped and are unchanged, re-derived rather than asserted.
ServerPageTabsTests.KnownUnreadablecounts PostgreSQL collectors with no servedget_pg_*read: 29 PostgreSQL collectors inCollectorCatalog, 35 servedget_pg_*reads, all 35 resolving throughCollectorForReadonto 28 distinct collectors, leaving 1 (pg_database_size_stats) — the constant's current value.ViewerCollectorCoverageTests' allow-list is the same single entry: 71 catalog tables against 71ViewerDataService*.csfiles plus the 29 shared readers they name, 0 uncovered and 0 stale. This lane adds a SQL Server read and no PostgreSQL collector, so neither number moves;DarlingQueryStoreClutterReaderis now inside the coverage scan's follow set, which adds coverage and removes nothing.Tests
QueryStoreClutterViewerSurfacesTestspins both surfaces as source, and its assertions are mostly negative: the Viewer reader contains no SQL, neither surface words a remedy of its own, neither restates a sleep-wait name, every Queries sub-tab constant matches its position in the XAML. The positive half is what a screenshot would catch; the negative half is what nothing would.QueryStoreClutterTestsgains a table over all four capture modes, the pre-rung null and the no-config case, and a pin that the mode moves neither the verdict nor the reason tokens. Two existing pins move with the change rather than around it.QueryStoreClutterTests'ConfigSqlshape pin anchoredcapture_timeon the line break that followed it, to tell the projected column from the one in theORDER BY; appendingquery_capture_modemoved that break, so the anchor is rewritten to carry three facts at once —capture_timeis projected, the mode follows it, and the mode is the LAST projected column, which is what makes the reader's ordinal 12 the mode rather than a shift of every ordinal before it. AndRepoFileAdoptionTests' LF-reader roster gains the new test file at its sorted position, with the reason it needs LF beside it: its pins slice regions out ofViewerServerTab.xamlandserver-tabs.jsbetween anchors several lines apart.The live PostgreSQL rig now plants three capture-mode states —
ALLon the newest capture with a pre-rung NULL on the older one for the same database,AUTOelsewhere, and a NULL that keeps the server-level flag false for a real reason rather than because nothing was ever written.Closes #3797