Repository navigation
Query Store clutter had no surface: get_query_store_clutter composes per-database read cost, plan churn and the options row from rows already collected, one per-server QDS overhead block, replicas excluded by architecture (partial #3797) - #3814
Merged
Merged
Conversation
…per-database read cost, plan churn and the options row from rows already collected, one per-server QDS overhead block, replicas excluded by architecture (partial #3797) The maintainer's intent for #3797: a view of Query Store clutter, not a new query against the target — analyse what is already collected. Every input existed: the V80 fan-out rollup on collection_log (which database the query_store collector spends its time in), plan_id on the raw query_store_stats rows, the hourly query_store_health options row, the QDS_* deltas in wait_stats, MEMORYCLERK_QUERYDISKSTORE in memory_clerks. Nothing composed them. Reader (DarlingQueryStoreClutterReader): four statements, each server_id = ANY($1::int[]) so the per-server read and the opt-in fleet reference are one arithmetic; percentile_disc throughout. Pure judgment (QueryStoreClutter): the band canon with reason tokens and published thresholds, never a weighted score; Unknown means unmeasured. Tool (DarlingMcpQueryStoreClutterTools): per-database rows with three decomposed arms, one per-server overhead block naming the four excluded QDS sleep waits, the page dialect, the window floor for the raw-tier arms, and query_capture_mode null with capture_mode_known false until #3796. Replicas: readonly_reason bit 8 — the engine's readable-secondary flag the collector already gates on — excludes the row with the reason on it; a replica's Query Store is its primary's and its READ_ONLY is never a defect. Registered on the host, the web catalog and dispatch, the instructions census (157 / 70), the READMEs, llms.txt and the Lite inventory ratchet (a port, not a boundary: Lite has every input). Census rosters for the window floor gain the file. Live rig test plants three databases (one slowest on 8 of 10 runs at 90% of the pass), one-versus-six plans per query, a reason-8 replica row and a QDS sleep wait, and asserts the raw numbers off the tool's JSON.
erikdarlingdata
force-pushed
the
feat/3797-qs-clutter-reader-mcp
branch
from
September 20, 2026 17:55
276923a to
4f8499a
Compare
Owner
Author
|
Head rebuilt as 4f8499a (13 files, +2567/−9) on dev f2e1816. The first head (276923a) was cut with |
4 tasks done
erikdarlingdata
added a commit
that referenced
this pull request
Sep 20, 2026
…older as a consumer: get_query_store_clutter's query_capture_mode key (null, capture_mode_known false) is allowed by name in its two files and the READ half is fenced, so the (a) arm still retires when a reader lands (dev red since #3814 met #3813) QsCaptureModeRouteKnobToastRungTests.NoReaderNamesAnyOfTheEightColumnsYet scans every product source for the literal query_capture_mode and fails on the first hit. #3814 (the Query Store clutter view) publishes that KEY as null beside capture_mode_known: false and a note naming #3796's rung — the payload's promise that the column exists and is not yet read — in DarlingMcpQueryStoreClutterTools.cs and its DarlingMcpInstructions.cs row. The two PRs merged eleven minutes apart and the pin could not tell "names the key" from "reads the column". The fix keeps the pin's purpose: the placeholder is allowed in exactly those two files with the reason, and DarlingQueryStoreClutterReader.cs / QueryStoreClutter.cs are asserted to name NEITHER capture-mode column, with the tool's null key and false flag asserted beside it — so a reader wiring the column fails here first and the arm retires deliberately, as the exit criterion asks. Test roster only; no product change.
This was referenced Sep 20, 2026
erikdarlingdata
added a commit
that referenced
this pull request
Sep 20, 2026
…: the V137 eight-column no-reader census is retired whole rather than exempted file by file — #3814 released the clause forty minutes after the rung, #3821 bought one merge by name, and #3796, #3712 and #3783 were each about to red the same method and race to edit it (follow-up to #3813) QsCaptureModeRouteKnobToastRungTests.NoReaderNamesAnyOfTheEightColumnsYet scanned the five product projects, comments stripped, for the eight V137 column names and threw on the first hit. Dev red at 20215a4: DarlingMcpInstructions.cs names query_capture_mode capture_mode_known = false — a pointer, not a read — and the census cannot tell the two apart. #3821 exempted the two files and added a positive arm; green, but the three code halves the rung exists for name the columns in product source outside any exemption (measured: #3796's pushed branch, edit to the method. Three lanes editing one test body whose only job left is to be edited is the race, not the fix. The method and its summary go; the class doc records the history in the file's voice; every other fact stays byte-for-byte, including the (d) no-WRITER arm on StoreSelfMetrics.cs inside the dimension-sweep fact (one file, one lane, #3783 retires it with the row). WithoutComments stays for that arm. No product file touched. Lite.Tests/QsCaptureModeRungTests has no reader-roster fact to retire. Darling.Tests -c Release -p:EnableWindowsTargeting=true: 0 warnings. In-process on this Mac: the class 6/6; the 20215a4 version of the class in the same harness fails exactly the quoted fact; RepoFileAdoptionTests, DocCommentHygieneTests, CommentFilterAdoptionTests and the census list green.
erikdarlingdata
added a commit
that referenced
this pull request
Sep 20, 2026
…: the V137 eight-column no-reader census is retired whole rather than exempted file by file — #3814 released the clause forty minutes after the rung, #3821 bought one merge by name, and #3796, #3712 and #3783 were each about to red the same method and race to edit it (follow-up to #3813) (#3825) QsCaptureModeRouteKnobToastRungTests.NoReaderNamesAnyOfTheEightColumnsYet scanned the five product projects, comments stripped, for the eight V137 column names and threw on the first hit. Dev red at 20215a4: DarlingMcpInstructions.cs names query_capture_mode capture_mode_known = false — a pointer, not a read — and the census cannot tell the two apart. #3821 exempted the two files and added a positive arm; green, but the three code halves the rung exists for name the columns in product source outside any exemption (measured: #3796's pushed branch, edit to the method. Three lanes editing one test body whose only job left is to be edited is the race, not the fix. The method and its summary go; the class doc records the history in the file's voice; every other fact stays byte-for-byte, including the (d) no-WRITER arm on StoreSelfMetrics.cs inside the dimension-sweep fact (one file, one lane, #3783 retires it with the row). WithoutComments stays for that arm. No product file touched. Lite.Tests/QsCaptureModeRungTests has no reader-roster fact to retire. Darling.Tests -c Release -p:EnableWindowsTargeting=true: 0 warnings. In-process on this Mac: the class 6/6; the 20215a4 version of the class in the same harness fails exactly the quoted fact; RepoFileAdoptionTests, DocCommentHygieneTests, CommentFilterAdoptionTests and the census list green.
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.
Partial #3797 — the reader and the MCP tool (arms (a), (b), (d), and (c) with capture mode
null). The two viewer surfaces are the second lane the issue's own sequencing names. Does not close it.The lie
Nothing in the product could say which databases were cluttering Query Store, why, or what it cost the servers hosting them — while every input for that answer was already in the store.
The case that motivated it (2026-09-20): on the largest production store, one database out of dozens carried 92–96% of the
query_storecollector's per-database read time; on the second store class the plan dimension was taking ~755k new distinct plans a day. Both were read off hand-run SQL against the store, because the four facts that compose the answer were each on their own surface and none of those surfaces put them beside each other: the V80 fan-out rollup oncollection_log(fanout_item_count/slowest_item/slowest_item_ms, #2472) says which database the collector spends its time in;plan_idon the rawquery_store_statsrows says how many plans a query carries and how fast new ones arrive;query_store_healthsays what the store is configured to keep; theQDS_*deltas inwait_statsandMEMORYCLERK_QUERYDISKSTOREinmemory_clerkssay what Query Store itself costs the instance. The maintainer's intent, verbatim spirit: not a new query — analyse what we've already collected. This is that.The mechanism
DarlingQueryStoreClutterReader— four statements, one per arm, each with its own honest grain and its own retention, and one small clerk read.v_collection_logforcollector_name = 'query_store'runs with a fan-out: per (server, database) how often it wasslowest_item(runs_slowest/runs_observed), the discrete median and p95 ofslowest_item_mswhen it was, the run'sduration_msmedian for scale,slowest_share_pct= the discrete median ofslowest_item_ms / duration_ms—get_collection_health's fanout.dominance is slowest-vs-mean, not a concentration verdict — publish the slowest item's share of the pass directly #3502 verdict figure, the slowest item's share of the whole pass — anddominance_ratio: this database's median slowest cost over the POOLED median of every other database's slowest cost on the same server (anothersCTE joining runs where a different database was slowest). Named and described as a different quantity fromget_collection_health'sdominance(slowest × items / run), so the two cannot be read as one. Runs with no fan-out (fanout_item_count IS NULL— a plain run, or an enumeration that yielded no items, which is every run on a replica) and zero-duration runs are not in the denominator.query_store_statstable byplan_id, notquery_plan_hash:plan_idis the identityMAX_PLANS_PER_QUERYcaps, the keyquery_store_plan_mapholds one row per (sodistinct_plansis what the plan dimension grows by), and it is inidx_query_store_stats_server_db_query_plan_time, so the whole arm is an index-only walk of one server's rows where a hash-keyed count would fetch every heap row in the window; a shape hash also collapses parameter-sniffed recompiles and would under-count exactly this churn (PayloadDimensions' first reason). Per (server, database):distinct_queries,distinct_plans,plans_per_query_p95/_max(discrete percentile over the per-query plan counts),plans_seen_onceandnever_seen_twice_fraction(plans under exactly onecollection_timeover all plans — meaningful because the collector re-fetches an OPEN interval every cycle while itslast_execution_timeadvances, so a plan seen once ran inside one cycle's span and never again; null under two collections),plans_first_seen_in_windowandnew_plans_per_day(arrivals after the database's first collection in the window, over the days its collections span; the store keeps no first-seen stamp, so a plan idle before the window and run again inside it counts as new — the tool says so).query_store_healthcapture per database INSIDE the window (DISTINCT ON, not aMAX(capture_time)anchor: the newest capture is per database), with its owncaptured_at, every option the health row carries,readonly_reasondecoded through the sharedQueryStoreReadonlyReason, andquery_capture_mode: null,capture_mode_known: false,capture_mode_notenaming query_store_health does not collect QUERY_CAPTURE_MODE or WAIT_STATS_CAPTURE_MODE — the one option that names a plan-churn factory is the one the health row omits #3796's rung. Not wired to a column that does not exist yet; Lane 2 / the rung flips it.QDS_*wait type in the window fromv_wait_stats, the COLLECTOR's stored deltas summed (no differencing here, so a restart cannot manufacture a negative), the rate formed only from rows withsample_interval_seconds > 0(rated_wait_msovermeasured_seconds, both sums over the same rows) and published aswait_ms_per_hour— a C# quotient over a measured span, never a cadence — withrows_unknowable(the (0, 0) restart rows) androws_without_interval(pre-V127) counted beside it.excluded_wait_typesNAMES the fourQDS_*sleep waitsIgnoredWaitDefaultsdrops at collection, derived from that list rather than restated, and the tool filters them again by name so a row that ever carried one lands inexcluded_wait_types_present_in_storerather than in the proxy.memory_clerkisMEMORYCLERK_QUERYDISKSTORElatest and window max beside the newest capture of ANY clerk, because the collector stores the top 25 clerks over 1 MB and the clerk's absence is a rank, not a zero —clerk_in_latest_capturesays which. The block ends with the window's baseline discontinuities throughDarlingTrendReader.GetBaselineDiscontinuitiesAsync, the trend tools' own markers, reused rather than reinvented.Every statement takes
server_id = ANY($1::int[]), deliberately: the one-server read binds a one-element array and the fleet reference binds every enabled SQL Server target, so the reference is computed by the SAME arithmetic as the number it is a reference for.percentile_discthroughout — a discrete percentile is a value some run really had, and it side-steps PostgreSQL's missinground(double precision, integer)(DarlingOversizedPlanBacklogReader's reasoning). The replica census reads the bit off the health row and never offserver_properties.ag_replica_role, which only knows Always On and readsStandaloneon an RDS read replica.QueryStoreClutter— the pure half, no store access, executed against planted rows inQueryStoreClutterTests:Compose(union of every arm's databases, ordered worst-first),Judge(the band and its reasons), the derivations (RunsSlowestPct,DominanceRatio,NewPlansPerDay,NeverSeenTwiceFraction,PctOfCap,WaitMsPerHour),DiscreteMedian(PostgreSQL'spercentile_disc(0.5)exactly — the live test cross-checks the two on the same rows),IsReplicaServer,ComputeFleetMedian,Recommendations.DarlingMcpQueryStoreClutterTools.get_query_store_clutter—server_name,hours_back(24, capped by the shared validator),limit(50),include_fleet_median(false),as_of. Rows are cut throughMcpHelpers.BoundPagewithtruncated/databases_returned/database_count. Thewindowblock carries the requested edges beside the raw tier's reach —window_truncated/effective_start/effective_hours_backoffDarlingDataReader.GetQueryStoreWindowFloorAsyncwithget_query_store_top's ninety-minute slack — nested rather than flat because this payload ALSO carries a page cut and the two facts must not share a block (McpPayloadContractCensusTestsholds them apart; the tool joins the window-floor rosters and its description ends withMcpHelpers.WindowTruncatedDescription).next_toolsper row are the reads that carry the detail, in the{tool, reason, suggested_params}shape the analysis findings use, only tools this server hosts. The miss ladder isget_query_store_top's: engine capability → the recorded Query Store state → the collector's own last outcome → the plain miss.Why decomposed arms, not a score
The issue asked for rows "ranked by a composite the payload decomposes into its three arms with each arm's raw numbers". A composite that is a NUMBER — a weighted sum of a share, a percentile and a fraction — would have to invent the weights, and the first operator to ask "why is this database a 7.3" could not be answered from the row. So the composite is the BAND (
HealthSeverity, the one spelling every band on this wire uses — #3703's canon, written through the enum's ownToString()so it cannot drift by hand) besideverdict_reasons, each a token naming the arm and the bar it crossed (read_cost_dominant,plan_churn_high,one_shot_plans,plans_per_query_at_cap,storage_near_cap,qs_read_only,qs_off,qs_read_only_replica,not_measured), with the bars published underthresholdsso a reader can disagree with them on the evidence. Rows are ORDERED by band, then the read-cost share, then plans per query — the ranking the issue wanted without a number nobody can audit.The bars are stated, not measured: production is uniform at 200 plans / 21 days / 8 GB, so configuration will not explain clutter differences today and churn will; the fleet had one database at 92–96% of the pass.
read_cost_dominantneeds the database to be the slowest on at least half the runs (one bad run is a run, not a database) AND a fan-out of at least two databases (one database has a 100% share by construction); then 50% of the pass is Warning and 80% Critical.plan_churn_highisplans_per_query_p95at 4 / 10.one_shot_plansis half the plans seen once, over at least 20 plans.storage_near_capis 90% ofmax_storage_size_mb.qs_read_only(not the replica bit) is Critical — the cap case IS clutter at its terminal state. Unknown means unmeasured and never escalates: a database with no runtime rows, no fan-out run naming it and no configuration (or Query Store OFF) says so rather than reading as Healthy — the "zero is a measurement" rule applied to a band.Replicas. A database whose
readonly_reasoncarries bit 8 — the engine saying "read-only BECAUSE this is a readable secondary", the mechanism-agnostic flagQueryStoreCollector's enumeration already gates on (readonly_reason & 8 = 0, #1558, which is why a replica has noquery_store_statsrows and no fan-out runs in the first place) — readsexcluded: true,excluded_reason: qs_read_only_replica, verdict Unknown with that one reason and no other: its read cost and churn are its primary's, its configuration is replicated, and judging any of them would file a defect against the wrong server (the topology ruling, 2026-09-20).server_is_replicasays when every recording database on a server is one, theqs_overheadblock is still reported (waits and clerks are real on a replica), and the fleet reference excludes such servers. Tested as a bit, not an equality: 65544 (cap + replica) is still a replica.What it does NOT do
server-tabs.jspanel, no Viewer tab.nullwithcapture_mode_known: falseon every config row and at the top level.query_store_healthdoes not collectQUERY_CAPTURE_MODEuntil query_store_health does not collect QUERY_CAPTURE_MODE or WAIT_STATS_CAPTURE_MODE — the one option that names a plan-churn factory is the one the health row omits #3796's rung lands (Lanes 1 and 2 this wave); the churn recommendations say the mode is uncollected and name both readings (ALLbeside churn → AUTO;AUTObeside churn → the workload) rather than guess.include_fleet_mediandefaults false because it walksquery_store_statsandwait_statsfleet-wide over the window — on the largest store that is the read deadline's whole budget (20 s client-side, 15 sstatement_timeouton the managed store'smcprole), and a default call that times out is a tool nobody uses. With it on,fleet_medianis the discrete median ofslowest_share_pctandplans_per_query_p95over every DATABASE on every enabled SQL Server target that is not a replica (only servers that fanned out over ≥ 2 databases enter the share population), and of the QDS rate over those SERVERS (each server's sum of its included per-type rates — the per-type rates add, the per-type measured seconds do not), each with the population it was drawn from andreplica_servers_excluded.QueryStoreHealthCollector, thequery_store_healthcolumns,get_query_store_health,PgMigrations,CHANGELOG.md, or any viewer file. No table, no rung.slowest_share_pctkeepsget_collection_health's meaning (the slowest item's share of the pass) and the run-frequency figure isruns_slowest_pct;dominance_ratiois the cross-database ratio the brief defined and is described as NOTget_collection_health'sdominance.Lite
Verified against the brief's hypothesis, which was wrong in the direction that matters: Lite HAS the
collection_logfan-out columns (Lite/Database/Schema.cs:60-62,DuckDbInitializer.cs:1471-1475, written byRemoteCollectorService.cs:854), and itsquery_store_stats/query_store_health/wait_stats/memory_clerkstables are generated from the same shared collector definitions. It does not havequery_store_plan_map/query_plan_dim— and this reader does not read them either, becauseplan_idon the fact rows is all the churn arm needs. So a Lite twin is a DuckDB port of the four statements (percentile_disc→quantile_disc) over the same pure judgment: a "not ported yet", not a SKU boundary, and theCrossAppMcpToolInventoryPinTestsratchet entry says so in those words. Out of scope here by the issue's own sequencing (reader + MCP first) and the brief's Darling-only deliverable.Registration
The seven sites a new Darling tool lands on:
DarlingMcpHostService(WithGeminiCompatibleTools<DarlingMcpQueryStoreClutterTools>()),DarlingWebEndpointscatalog descriptor + dispatch (/api/read/get_query_store_clutterwithserver,hours,limit,include_fleet_median,as_of), theDarlingMcpInstructionscensus sentence (157 tools / 70 unique) and Tool Reference row, the rootREADME.md(both Darling counts),llms.txt(88-157),Darling/README.md(a Query Store clutter bullet under the core reads), and the Lite inventory ratchet.McpPayloadContractCensusTests' window-floor rosters (WindowFloorBlocks,WindowFloorTools,SecondBoundCutKeys[window_truncated],CutNoteKeys[truncation_note]) gain the file — roster additions, no rule change.Tests
Executed on this Mac through the built
Darling.Tests.dll(-c Release -p:EnableWindowsTargeting=true, WindowsDesktop framework entry stripped from the runtimeconfig, xunit v3 in-process):QueryStoreClutterTests— 49 facts: every judgment boundary on both sides by the thresholds' NAMES (the replica bit beside a would-be-Critical share and churn → Unknown with one reason; 65544 is a replica, 65536 is not; nothing measured → Unknownnot_measured; OFF → Unknownqs_off; measured and quiet → Healthy with no reasons; read cost at 90 / 79.9 / 50 / 49.9 % and under the runs gate and on a one-database fan-out; churn at 10 / 9 / 4 / 3; one-shots over 40 vs 19 plans and under one collection; the cap with and without a config row; storage at 90.0 vs 89.99 %; the worst arm wins and every arm keeps its reason), the derivations,DiscreteMedianon six populations, the excluded set equals the shared ignore list's fourQDS_*entries,IsReplicaServer,Composeordering,ComputeFleetMedianwith a replica server and a one-database fan-out excluded, the recommendations' knobs, the tool surface and parameters, the description's claims, every statement's text, and the six registration sites.QueryStoreClutterLivePostgresTests— againsttimescale/timescaledb:2.28.1-pg18on aScratchPostgresdatabase (#1776 own-store), through the REAL tool: three databases with alphaslowest_itemon 8 of 10 runs at 9000 of 10000 ms (asserted:runs_observed10,runs_slowest8,runs_slowest_pct80,slowest_item_ms_p50/p959000,run_duration_ms_p5010000,slowest_share_pct90,others_slowest_item_ms_p503000 —percentile_discover beta's 4000 and gamma's 3000 —dominance_ratio3.0, verdict Criticalread_cost_dominant; beta'sdominance_ratio0.44 against the others' 9000); a run with no fan-out, a zero-duration run and another collector's run that must not count; plan churn with alpha at one plan per query (plans_per_query_p951,never_seen_twice_fraction0.0,new_plans_per_day0.0) and beta's one query carrying six (distinct_plans9,plans_per_query_p956,plans_seen_once3,never_seen_twice_fraction0.333,plans_first_seen_in_window3,new_plans_per_day36.0 over the two hours its collections span, verdict Warningplan_churn_high); gamma measured and Healthy with no reasons;db_offUnknownqs_off; the NEWEST of two health captures (4096 MB, not 2048) with its stamp; the window floor (window_truncatedtrue,effective_hours_back6.0 against a 24-hour request);QDS_LOADDBfrom three rated rows, one (0, 0) row and one pre-V127 row (wait_ms_total1900,measured_seconds180,wait_ms_per_hour36000,rows_unknowable1,rows_without_interval1),QDS_BLOCKING_TASK7200/h, totals 2020 ms and 43200/h, the plantedQDS_ASYNC_QUEUEinexcluded_wait_types_present_in_storeand not in the proxy, aPAGEIOLATCH_SHrow ignored; the clerk at 640.25 MB in the newest of two captures; the fleet reference with 3 enabled targets, the reason-8 replica server excluded (shares 90/40/30 → 40; plans 1/6 → 1; one server's QDS rate 43200); the page cut atlimit2 (worst two,truncatedtrue,database_count4,fleet_mediannull with the opt-in note); the replica server (server_is_replicatrue, its one row excluded with the reason and the decoded bit,next_toolsstopping at the composition sources, the overhead block real); an empty server through the miss ladder tounavailable; a badlimitand a badhours_backrefused through the shared shapes. Positive control: with theothersCTE's<>flipped to=, the first live test fails atothers_slowest_item_ms_p50(expected 3000, actual 9000). A second live fact runs the reader alone and assertsQueryStoreClutter.DiscreteMedianover its three shares is the 40 the fleet block published.0bcbd50b3:RepoFileAdoptionTests,StragglerCommandTimeoutTests,LiveCleanupConversionRatchetTests,ViewerCommandTimeoutTests,MeasurementContractCensusTests,McpPageContractTests,McpPayloadContractCensusTests,FactSourceRegistryTests,DocCommentHygieneTests,TsqlConventionGuardTests,McpReadCommandTimeoutTests,McpLatestSnapshotStampTests,AsOfWindowAnchorTests,DarlingWebEndpointsTests,DarlingCustomViewsTests,ServerPageTabsTests,BaselineDiscontinuityRenderTests,McpToolTypeRegistrationTests,ReadmeDerivedCountPinTests,McpZeroIsAMeasurementTests,CommentFilterAdoptionTests,CollectorStateContractTests,DarlingMcpConfigHistoryToolsTests,DarlingMcpDataToolsTests— 687 facts.LivePostgresCollectionHygieneTestsreds on this Mac on clean dev too (PresentationFrameworkload during assembly-wide reflection — the WPF harness limit), so it is CI's; this PR's live class carries the#1776 own-storemarker and mints its own database.CrossAppMcpToolInventoryPinTests6/6 through a throwaway net10.0 harness compiling that class andParitySource(Lite.Tests.dllitself hangs at discovery on the Mac).HasValue/is intinstead ofis { }soTsqlConventionGuardTests' member walk reads them whole, rather than growingKnownTruncatedRanges.PerformanceMonitor.Darling.Service,Darling.TestsandLite.Testsbuild-c Release -p:EnableWindowsTargeting=truewith 0 warnings.Which component(s) does this affect?
Darling/README.md, rootREADME.md,llms.txt— tool counts and one bullet)Checklist
-c Release -p:EnableWindowsTargeting=true, every touched project)Darling PostgreSQL testsjob is its second execution)Partial #3797