Repository navigation
One payload said NoData and No Data, eight spellings of four severity words were two bands and six other vocabularies, and the page cut had five names: the daily summary speaks one band token on both SKUs, six inferred cuts become observed truncated + *_returned, and the census classifies every cut key and severity literal by what it is (partial #3653) - #3703
Merged
Merged
Conversation
… words were two bands and six other vocabularies, and the page cut had five names (partial #3653 A15/A16) get_daily_summary / get_daily_summary_range on both SKUs publish overall_health and health_band from the same enum token (NoData, not "No Data"); the four PostgreSQL tools that inferred limit_reached from a full page, the autovacuum run history's history_capped and get_analysis_findings' truncation_note (both SKUs) fetch one past their cap through McpHelpers.BoundPage and publish truncated (+ *_returned); the census classifies the fourteen cut keys and the eight severity spellings by what each actually is and fails a retired or unclassified spelling by name. McpHelpers.ValidateDaysBack adopts the five inline days_back refusals and list_servers goes through FormatError; FormatError's shape is untouched (Q11).
Closed
39 tasks done
…and token (overall_health = NoData beside health_band), and asserts the two keys agree
erikdarlingdata
enabled auto-merge (squash)
September 19, 2026 08:14
This was referenced Sep 19, 2026
erikdarlingdata
added a commit
that referenced
this pull request
Sep 20, 2026
… the page dialect's truncated: get_query_trend, the duration-trend trio and get_query_store_top publish the store's reach under its own key, every consumer and description follows, and the vocabulary census holds the two facts apart (partial #3653 — item 17) (#3793) `truncated` carried two facts on the wire. On twenty-odd paged tools it is the caller's `limit` biting — observed off a `cap + 1` fetch, beside `*_returned`, remedied by a bigger limit. On the #2364 / #2353 trend family and on get_query_store_top it was the store's REACH: the served series begins later than the requested start because the tier that answered no longer holds the window's head, beside `effective_start` / `effective_hours_back`, and no limit changes it. #3703 classified the homonym and left it as stated residue; #3706 counted the blast radius (~15) and stopped. This is that rename. Emitters (4): DarlingMcpTrendTools get_query_trend initializer + TrendDisclosure.WriteTo (the trio, data and empty envelopes); DarlingMcpDataTools get_query_store_top (truncation_note keeps its name — it is the prose for this flag); Lite McpQueryTools.WriteDisclosure (the trio + get_query_trend). Consumers: server-tabs.js drawQueryTrend reads window_truncated (undefined is falsy — the old key would have silently dropped the notice). Descriptions: McpHelpers.WindowTruncatedDescription, one shared clause on the nine publishing tools (5 Darling, 4 Lite), naming the key, the reach beside it, and the WIRE CHANGE; nine instructions rows and five web-catalog rows say window_truncated. C# members (Truncated, TruncationSlack, DescribeCoverage) keep their names — the wire key renamed. Census: McpPayloadContractCensusTests classifies window_truncated as the second bound it is (SecondBoundCutKeys), reads the ordered-envelope idiom (`envelope["key"] =`) the disclosure block uses so Lite's writer is in the roster, and adds TheWindowFloor_IsSpelledWindowTruncated_BesideItsReach_AndNeverBareTruncated_OnBothSkus: every block on both SKUs that writes effective_hours_back must write window_truncated and effective_start and never bare truncated — brace-walked over strings-blanked code, rostered as an equality on (file, idiom, count), checked first on a synthetic offender and a synthetic page cut. The discriminator is the reach vocabulary, not window_start: get_query_heatmap publishes window_start beside a bare truncated that IS a page cut. EveryWindowFloorTool_CarriesTheSharedClause_AndNoOtherToolDoes is the description half. The residue sentence is gone.
This was referenced Sep 20, 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.
Part of #3653 (the A15/A16 "one vocabulary" clause: 7 truncation dialects / 5 severity vocabularies ("NoData" and "No Data" in one payload)). PARTIAL — does not close it. #3699 measured the clause exactly and left the rosters (
TruncationKeyDialects, 14 keys;SeverityWordSpellings, 8 spellings; the namedNoData/No Datapair) for this lane to collapse. This PR collapses what is a dialect, classifies what is not, and says which is which in a census that fails on the next spelling.The lie, read from the source
Three lies of different sizes were hiding under one sentence.
One payload, two spellings of one band.
get_daily_summaryandget_daily_summary_range, on both SKUs, publishedoverall_health = DailyHealthBandCalculator.Label(band)besidehealth_band = band.ToString(). Those agree on three of four values and disagree on the fourth:"No Data"beside"NoData". The label is the desktop viewers' tooltip text; the token is what every other band on the wire is spelled as (HealthSeverity,FleetHealthBand,DailyHealthBand— PascalCase, one word) and what the web client keys its CSS classes on (band-Warning,sev-Critical;sweeps.jshad to special-case"No Data"because a space is not a class name). Both keys now publish the token.overall_healthstays as a key because it is the older of the two (the Dashboard's daily-summary column) and removing it is a wire-shape change, not a spelling. The row types keepOverallHealthas the human label for the viewers.The page cut had five names, and three of them were inferences. Four PostgreSQL tools (
get_pg_autovacuum_health,get_pg_session_states,get_pg_index_usage,get_pg_table_bloat) saidlimit_reached = x.Count >= limit— the>= capshape #3594 named, which cannot tell a population of exactlylimitfrom a busier one; its own prose said "more MAY exist". The autovacuum tool's run history saidhistory_capped = runs.Count >= RunsReadPerTable, the same inference one layer down and against a collector constant: a table with exactly 25 logged runs read as capped.get_analysis_findingson both SKUs inferred itstruncation_notefromfindings.Count >= WindowCoveringLimit— a window of exactly 10,000 occurrences read as cut. All six now fetch one row past their cap and bind throughMcpHelpers.BoundPage(#3699's helper), publishtruncated, and the four caller-capped ones publish their page count astables_returned/sessions_returned/indexes_returned(the web tiles already labelled those keys "Tables returned" / "Sessions returned" / "Indexes returned" — the label knew what the key did not say). Eachlimitdescription names the flag in #3679's wording. No SQL changed: all four readers already boundLIMIT $4, and the run-history read's per-relation cap is$5.Eight spellings of four severity words — of which two were bands. The census counted
Critical/Healthy/Warning/Unknown,warning,unknown,CRITICAL,HEALTHY. Read at each site: the PascalCase four are the band canon (HealthSeveritywritten out by the three PostgreSQL object tools and the AG reader's label switch). Every other spelling is another vocabulary that happens to use the same word, or the word on the way IN:CRITICALDarlingPlanCacheSchedulerReaderbloat_level's top rung of the Dashboard'sNORMAL / MEDIUM / HIGH / CRITICALlevel scale — spelled identically by Lite'sLocalDataService.ClassifyPlanCacheBloatand coloured by both viewers'BloatLevelBrush. Moving one rung would leaveCritical / HIGH / MEDIUM / NORMAL.HEALTHYDarlingAgReadersynchronization_health_desc, parsed on the way in and banded toHealthSeverity. Input, never emitted.HEALTHYDarlingFleetReaderNEVER_RUN / … / WARNING / HEALTHY), compared to count healthy collectors. Input.UnknownDarlingMcpTools,McpAnalysisToolsaudit_config's edition-NAME fallback. A name, canon-spelled by coincidence.unknownDarlingMcpPgWaitSamplingToolsservice_sampled / pg_wait_sampling / …).unknownDarlingPgLoggingAuditinstrumented / partial / off / unknown).unknownMcpHealthToolsget_collection_health's version-string fallback.warningDarlingMcpPgWraparoundToolsok / info_* / warning[_*] / critical_*, shared by the autovacuum, slot and wraparound tools, rendered untranslated byserver-tabs.jsby design).warningDarlingMcpTools,McpAnalysisToolsaudit_config's per-recommendationstatus(ok / warning / review) — the lower-case status vocabulary everystatuskey speaks.None of these moved, and the PR says so rather than counting them as collapsed. The one that is a severity by any reading — the token ladder — is a different vocabulary, not a case variant: the tier is a prefix and the reason is the rest of the token (
critical_far_past_threshold). Folding it into the band canon means splittingseverityinto a band plus areasonon three tools, which is a payload reshape and a maintainer's call; it is stated as residue below, not done quietly.The classification (14 keys → 5 classes + 2 homonyms)
truncatedcap + 1throughBoundPage, beside*_returned.limit_reached>= limitinference on four PG tools; nowtruncated+*_returned.history_capped>= RunsReadPerTableinference inRecentRuns; nowtruncatedoff a+ 1per-relation read.truncation_note*_noteis the house idiom for a disclosure; onget_analysis_findings(both SKUs) it now rides beside an observedtruncated; onget_query_store_topit explains the #2364 window floor (see residue).scan_truncatedget_blocking/get_deadlocksunderdedup_keyscan the window to a stated ceiling BEFORE the page is cut; two cuts a caller acts on differently need two names, and the second is<bound>_truncated, observed the same way.capture_was_truncatedpg_session_statescollector's per-capture row cap bit at COLLECTION.chain_may_be_truncated,chain_truncation_notepg_blockingcollector's chain-walk depth cap at collection.query_text_may_be_truncatedanswered_rows_withheld,created_rows_withheldshowntotal_*on the health-parser, default-trace and analysis-facts tools; the cut is exact (total − shown). The*_returned+truncatedrename is fenced tonight: fourPgTarget*test files readshownoffget_analysis_facts, and that fence is a standing decision.is_partialCREATE INDEX … WHERE).partial_countpartial.Source-side keys keep their names because they are true and different: a caller can do nothing about them by re-paging, and folding them into
truncatedwould tell that caller to raise a limit that changes nothing.The census now asserts the classification
McpPayloadContractCensusTests(49 facts, all executed here): the flatTruncationKeyDialectsroster is replaced by six classified rosters (SecondBoundCutKeys,CutNoteKeys,SourceSideCutKeys,WithheldSummaryKeys,PageCountsUnderANeutralNoun,CutHomonyms) each carrying files and a reason, plusRetiredCutSpellings.EveryCutKey_IsThePageDialect_OrClassified_OnBothSkussweeps both SKUs' tool sources and fails a retired spelling BY NAME, an unclassified spelling with the class it should have joined, a rostered key that moved files, and a rostered key that vanished. The cut matcher is widened beyond the tree (*_reached,*_capped,cap_hit/limit_hit,has_more,more_available,omitted) and witnessed both ways — including thatshared_blks_hitis a buffer-cache hit, not a cap hit (the first run of the widened matcher caught exactly that, and the arm is anchored to the cap words).TheSixMovedSites_FetchOnePastTheCap_AndObserveThroughBoundPagereads the six tools back;TheAutovacuumRunHistory_BindsToItsCapAndObservesthe block one layer down.Severity:
SeverityWordSpellingsbecomesBandCanonSpellings(PascalCase by construction, asserted) plusSeverityHomonyms— (spelling, file, what it is) for every non-band literal — andEverySeverityWordLiteral_IsTheBandCanon_OrARosteredHomonym_OnBothSkusfails a new lower- or upper-case severity literal in any unrostered file as a band spelled wrong. Executed controls:TheBandCanon_IsWhatTheSharedClassifiersSpell(the enum tokens and both label helpers agree);ThePlanCacheBloatLevel_IsOneScaleOnBothSkus_AndNotABand(Darling's classifier at every boundary, Lite's source spelling all four rungs);TheLadderTier_IsAPrefixOfATokenFamily_NotABand(the wraparound, autovacuum and slot ladders around the barewarning);TheDailySummary_PublishesOneBandSpelling_OnBothSkusreplaces the two-spellings fact — both keys readrow.HealthBand.ToString()on all four tool spans andOverallHealthappears in none.The four moved PG tools join
McpPageContractTests.PgPagedToolsThroughTheHelper(now eight), so the page census holds their full contract (limit + 1,BoundPage,truncatedpublished,LIMIT $4parameterised, the description naming the bound).Errors one shape: what this does and refuses
Refused: making
McpHelpers.FormatErrorreturn the JSON envelope. That is one helper change with a fleet-wide wire effect (~212 tools' failures become{status:"error"}), and it is ruling Q11 on #3653.FormatError's shape is untouched andTheTwoSharedErrorShapes_AreASentenceAndAnEnvelopestill executes the split.Done inside that line: the one ad-hoc catch (
list_serversreturned an interpolated sentence of its own) goes throughFormatErrorwith an operation that names what was being read, soAdHocErrorReturnsis empty; andMcpHelpers.ValidateDaysBack(daysBack, maxDaysBack)adopts the five inlinedays_backrefusals (get_collector_cost,get_collector_stall_probes,get_store_metrics, andget_daily_summary_rangeon both SKUs) inValidateHoursBack's first sentence, each tool keeping its own ceiling (60 / 90 / 366 / 400 — the retention of the series it reads), soInlineDaysBackRefusalsis empty and the bounded-parameter census recognises the new validator. Executed at its boundaries inValidateDaysBack_RefusesOutsideTheCeilingItIsHanded_InTheSharedSentence; the two range-tool tests that pinInvalid days_back value '367'on the wire pass unchanged.Consumers moved in the same PR
wwwroot/js/pages/server-tabs.js: the autovacuum / bloat / session-state / index-usage stat tiles readtables_returned/sessions_returned/indexes_returnedandtruncated.node --checkclean; zero hits forlimit_reached,"table_count","session_count"acrosswwwroot/js.wwwroot/js/util.js:bandClass/sevClassbuild their CSS class throughcanonicalBand, a case-insensitive map onto the PascalCase vocabulary — the belt to the census's brace, so a band arriving as"warning"from a surface the census does not sweep still colours. Executed under node against nine inputs.get_daily_summarydescriptions sayhealth_band=NoDatawhere they said "No Data"; bothMcpInstructionsalready saidNoData. READMEs and the web catalogue name none of the changed keys.McpFilterSemanticsLivePostgresTestsand Lite'sMcpPageContractTests(overall_health→NoData),DarlingPgAutovacuumVerdictLiveTests(truncated/tables_returned, plus the exactly-limitcomplete boundary),PgLogEventMetricsTests(RecentRuns: exactly 25 is complete, 26 is truncated withruns_counted25 and the 25th-newest asoldest_counted_run_at— the old pin encoded the>=inference as its own proof).What it does NOT do (residue, stated)
truncatedcarries two facts. On the paged tools it is the page cut; on the get_query_store_top reports a window it cannot serve: raw query_store_stats is dropped at 4 days #2364 trend family andget_query_store_topit is the WINDOW floor (the store's raw retention did not reach the whole requested window, besideeffective_start/effective_hours_back). Separating them (window_truncated) is a rename acrossDarlingMcpTrendTools.cs, which another lane holds tonight, and many trend-test pins. Named in the census's class summary.ok / info_* / warning[_*] / critical_*on three tools. Collapsing it into the band canon meansseverity→ band +reason; the wraparound ladder's barewarningis also the one rung in the family without a reason suffix. Maintainer's call (proposed as a Q on the issue).shownsurvives beside its honest total on 20 sites because the 21st (get_analysis_facts) is read by fourPgTarget*tests this lane may not touch; the rename is one mechanical pass once that fence lifts.bloat_level'sNORMAL/MEDIUM/HIGH/CRITICALand the latchLOW/MEDIUM/HIGHstay as the Dashboard's level scales they reproduce; moving them is a both-SKU + both-viewer change outside a spelling lane.deadlock_count,facet_count,plan_shapes,index_count) are not renamed*_returned; they sit beside an observedtruncatedand are nottotal_*.FormatError's return shape,AlertSeverity.cs, anyPgTarget*file,CHANGELOG.md, or the two lines other lanes hold inDarlingMcpTrendTools.cs/DarlingMcpDataTools.cs:94.Tests
Executed on this Mac through the built
Darling.Tests.dll(xunit v3 in-process runner,-c Release -p:EnableWindowsTargeting=true, WindowsDesktop framework entry stripped from the runtimeconfig):McpPayloadContractCensusTests49/49,McpPageContractTests42/42,McpLatestSnapshotStampTests34,ServerPageTabsTests17,AsOfWindowAnchorTests29,FleetIdentifierScrubTests2,DocCommentHygieneTests77,PgLogEventMetricsParserTests11,DailySummaryHealthFormatTests2,RepoFileAdoptionTests2,CommentFilterAdoptionTests4,DarlingMcpHealthToolsSurfaceAndSqlTests26,DarlingPgWraparoundReaderTests11,DarlingMcpPgPlanToolsTests14,PgCappedReadSurfaceTests12,ReadmeDerivedCountPinTests5 — all green. Lite through a throwawaynet10.0-windowsharness Compile-Including the classes:DailySummaryRangeToolTestsandCrossAppMcpToolInventoryPinTestsgreen;McpPageContractTests26/28 with the two reds (GetWaitStats_…,GetWaitingTasks_…) reproduced identically on dev before this change — a harness artefact, not this PR's. The two Darling live tests edited here (DarlingPgAutovacuumVerdictLiveTests,McpFilterSemanticsLivePostgresTests) are first executed by the Darling PostgreSQL CI job: no SQL text changed and every cap is bound as a parameter, so the+ 1is a bigger number through the same statement.PerformanceMonitor.Common,Darling.Service,Darling.Viewer,PerformanceMonitorLite,Darling.Tests,Lite.Tests,deprecated/Dashboard.Testsbuild-c Release -p:EnableWindowsTargeting=truewith 0 warnings from this change (Lite.Tests carries dev's one pre-existing xUnit2000 atLogTailOverlapThresholdPinTests.cs:95).Which component(s) does this affect?
get_daily_summary/get_daily_summary_rangeband spelling;get_analysis_findingsobserved cut;ValidateDaysBackadoption)list_servers; fourValidateDaysBackadoptions; web tiles and the band-class normaliser)Checklist
-c Release -p:EnableWindowsTargeting=true, every touched project and every consumer ofPerformanceMonitor.Common)