Repository navigation
PostgreSQL sessions: a window with no session capture still grades connection saturation from pg_stat_database.numbackends as a level-only card that says its states are unobserved, and the Aurora wait-profile advice names the window mean against its routine (partial #3691, lane 26) - #3791
Merged
erikdarlingdata merged 1 commit intoSep 20, 2026
Merged
Conversation
…nnection saturation from numbackends as a level-only card, and the Aurora wait-profile advice names the window mean (partial #3691, lane 26)
erikdarlingdata
deleted the
fix/3691-saturation-level-card-and-mean-prose
branch
September 20, 2026 14:32
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.
Two small honesty items on the PostgreSQL-target analysis engine, file-disjoint from each other, one PR. Lane 26 of #3691.
PARTIAL for #3691 — do not close. Two checklist lines, quoted verbatim:
numbackendsis unprivileged) is the other half of that line and stays OPEN; it is the coordinator's call, and this PR does not touch it.PgTargetAdvice.Anomaly.csComposeWaitProfileRatio(~:258) does not name the window mean…" — done.Item 1 — the saturation card exists as a level-only card when no capture exists but
numbackendsdoesThe lie. #3782 moved
PG_CONNECTION_SATURATION's numerator topg_stat_database.numbackends— the universal one-minute level — but kept lane 3's gate: the session-capture read's empty was the family's empty. A quiet OLTP pool that tripped no capture rule in the window got no saturation fact at all, even at 96 % of its usable ceiling, because the card's state breakdown, redaction verdict and newest-capture figure all came frompg_session_statesand emitting without them changed what the card said. #3782's body named this as the honest next step.What changes, and from which table (
Darling/PerformanceMonitor.Darling.Analysis/PgTargetFactCollector.Sessions.cs). The capture read's empty now only records "no capture" (hasCapture = rowsStored > 0 && peakTotal > 0; the locals are zeroed instead of returning). Without a capture: the redaction gate is not taken (the redacted-majority rule is over stored rows — zero rows are neither redacted nor visible), the idle-in-transaction holders read is not run (the holders ARE the captures' rows), the ceiling is still looked up off lane 2's context facts, and the level is still read (PgTargetNumbackendsPeakSql, unchanged). When the level decides (coverage ≥NumbackendsCoverageFloor, #3782's rule) the fact is emitted as the level-only card:Value= the level's peak instant ÷ usable,numerator_source = 1,numbackends_partial = 0, the coverage counts,peak_numbackends+ its age, the ceiling keys, andcaptures_with_rows = 0— and NONE of the capture-derived keys: nopeak_total_sessions, no state split, nopeak_idle_in_transaction_share, nolatest_*, nopeak_age_s, norows_redacted_share. Absence is the stamp: a share of 0 would claim "nothing parked" of states nobody observed. When the level does not decide and there is no capture — a pre-V133 store, or one mid-migration — the family is silent exactly as v1 was (logged at debug with the coverage): a part window's level is the capture-peak lie in a new coat, and there is no capture peak to fall back to. No SQL changed; still three commands, three deadlines, one degrade.Every reader of the absent keys reads "not measured", and it is pinned, not assumed.
PgTargetScorer.Sessions.cs— the parked-share amplifier's predicate now asksTryGetValue("peak_idle_in_transaction_share", out var parkedShare) && parkedShare >= IdleInTransactionShareBar: the key first, then the bar. Behaviourally identical today (GetValueOrDefaultread 0 < 0.25) — the change is that "not measured" is never compared as a 0 %, and the test source-pins the shape soGetValueOrDefaultcannot creep back. No bar, no boost, no lineage moves;ScoreSessionsFactuntouched (gradessaturation_ratiothe same from either shape).PgTargetRelationshipGraph.Saturation.cs(not edited) — the saturation ↔ idle gate reads the share withGetValueOrDefault ≥ bar; absent → false → no edge in either direction beside a fired idle fact. Pinned.ComparisonBanding.BaselinedValueFor(not edited) — returns null withoutpeak_total_sessions, so compare_analysis sigma-bands the PostgreSQL baselined metrics, so a 6× TPS surge on a PostgreSQL target stops reading "stable" (#3691 W1/W2) #3713's compare banding takes the absolute rule for the level-only row rather than a sigma against a bucket built from capture counts. Pinned (null for the level-only card, 40 for the capture-composed one).PgTargetAdvice.Sessions.cs—ComposeSaturationwitnesses the level-only shape by the same absent key banding does. The headline and division sentence are the level's (lane 25's text); the breakdown sentence is replaced by: "No session capture in the window: the count is pg_stat_database.numbackends — the backends attached to a database, every minute, whether or not any session tripped a capture rule — and state, application and idle-in-transaction shares are unobserved (the collector stores a session capture only when some session had a transaction open past its floor, so a window with none is a pool that tripped no rule, not an empty one). Whether these slots are held by working sessions or parked ones cannot be said from this window."; the coverage sentence reads "numbackends carried a value at 241 of the window's 241 one-minute pg_database_stats samples; no capture stored session rows in the window."; the remediation's tool sentence saysget_pg_session_stateshas no rows for the window instead of pointing at an empty page. The idle fact's cross-reference sentence (ComposeIdleInTransaction) no longer prints "with 0% of the peak capture idle in transaction" beside a level-only card — unreachable in one pass (the idle fact needs a capture) but honest if the pairing ever arrives. The static block's "The state breakdown always comes from the peak capture" is now "…comes from the peak capture when the window stored one; a window with no capture states the level alone and says its states are unobserved."Byte-identity for a window WITH a capture, executed. The capture keys are stamped in lane 3's exact order (the
if (hasCapture)blocks sit where the initializer entries were), and the gated e2e asserts the with-capture fact's whole ordered key list — 25 keys, lane 25's, before the scorer adds its own. The advice's new sentences are asserted absent for four with-capture fixtures (level decided / mid-migration / pre-V133 stamped / pre-lane unstamped), and lane 25's exact-string pins pass unchanged.Item 2 —
ComposeWaitProfileRationames the window meanSince #3780 the Aurora wait-profile detector fires the trusted arms only when the window MEAN clears the bar as well as the peak and stamps
mean_ms_per_sec/mean_ratio/mean_modified_z; the composer still stated the peak alone, so a reader took one hot five-minute collection's number for the whole window's. The sampled composer (PgTargetAdvice.Wait.cs, #3765) already named its mean; #3773's SQL Server enrichment had no PG-target twin.PerformanceMonitor.Analysis/PgTargetAdvice.Anomaly.csnow adds ONE sentence on the trusted arms, in the brief's shape, after the contributors: "The window's mean rate was 1507.2 ms/sec against a routine of 200 — 8.8 robust sigmas above it — so the whole window sat high, not one delta; the detector fires only when the mean clears its bar as well as the peak." — the mean's robust sigmas on the gate arm (mean_modified_z > 0), else its multiple on the ratio arm (the stampedmean_ratiofirst, the quotient overbaseline_meanas the belt). Onis_newthe bar is on the peak alone (#3741's ruling), so the mean is plain context inside the existing parenthesis — "(CPU excluded; the window's mean was about 1507.2 ms/sec)" — and no gate is claimed. A fact without the mean (pre-#3780) composes byte for byte as before (pinned on both arms). Still "the engine measured"; never "estimated from sampling", never "spent". No secondaurora_stat_*mention —AuroraOnlySqlIsGatedTests' roster class for this file is unchanged.Lineage
No bar, ramp, floor or boost is added or moved.
ConnectionSaturationWarning/Critical0.8 / 0.9 stay measured (2026-09-19 + 2026-09-20 C1, #3782);NumbackendsCoverageFloor0.5 stays definitional;IdleInTransactionShareBar0.25 stays measured and still gates only a capture's share. No PG-target anomaly bar is touched.Co-fire gating
Unchanged in declaration: three saturation amplifiers, same boosts, same keys. The parked-share arm cannot match a level-only card (no share); the CPU and offered-vs-delivered arms read siblings and can. The graph's edges are untouched.
What it does NOT do
PG_MONITORING_PERMISSIONSstill replaces it). That is the other half of the checklist line and the coordinator's ruling — stated on the face, left open.PgTargetFactKeys, change any SQL, touchFactScorer/FactAdvice/ a root partial / the graph file /ComparisonBanding/PgSessionStatesCollector/PgDatabaseStatsCollector, or a rung (V135 on dev). No production read.pg_sessionsfamily and theANOMALY_PG_WAIT_PROFILEcomposer, behind thepg_arms the routing pins re-prove).Tests
Darling/Darling.Tests/PgTargetSessionsTests.cs(+2 unit facts, aLevelOnlyfixture, one static-block pin moved, the gated e2e extended with a fifth server and a key-order pin):TheLevelOnlyCard_CarriesNoCaptureKey_GradesTheSame_AndEveryReaderOfTheAbsentKeysReadsNotMeasured: the 11 capture keys absent by name;ScoreBase1.0 / lineage 1 / severity 1.0 through the realScoreAllwith 3 arms declared and none matched; the parked predicate false on the card and true on a capture-composed 30/90 (reflection over the realAmplifiers); the scorer source pinned toTryGetValue(…parkedShare)and noGetValueOrDefault("peak_idle_in_transaction_share"); a fired idle fact beside the card opens no edge either way (two stories);BaselinedValueFornull vs 40; the idle fact's cross-reference sentence by exact string; the collector's gating in stripped source (hasCapturedefinition, the redaction gate under it, the holders read directly under anif (hasCapture), the no-numerator return before the fact, the reader's row optional).ComposeSessions_LevelOnly_StatesTheLevelAndThatStatesAreUnobserved_AndAFactWithACaptureIsByteIdenticalToLane25: headline + first sentence (lane 25's), the no-capture sentence and coverage sentence by exact string, no "State breakdown" / "0 active" / "0 sessions" / "newest capture" / PARKED, the measured clauses stand, the remediation's tool sentence, pending-restart; four with-capture fixtures reach none of the new text and keep lane 25's tool sentence and breakdown.…-quiet) with the level server's series (30 every minute, one instant at 93) and ceiling and nopg_session_statesrow. Collector alone: ONE sessions-source fact, 93/97, source 1, partial 0,peak_numbackends93 at 5,400 s, 241/241,captures_with_rows0, the 11 keys absent,BaselinedValueFornull, scored 1.0/1.0/lineage 1 with no arm matched, no idle fact, no permissions advisory. Through the REALanalyze_serveranchored at the window's end: the card at 1.0 with the exact level headline, the division sentence, the no-capture sentence, the coverage sentence, no breakdown, the remediation's no-rows sentence;get_analysis_factsshows source 1, 93,captures_with_rows0 and nopeak_total_sessions/ share. Then the quiet store NULLed to 101/241 → no sessions fact; NULLed everywhere → no sessions fact (v1's silence). The with-capture level server additionally asserts its exact 25-key ordered metadata before scoring.Darling/Darling.Tests/PgTargetAnomalyTests.cs(+1 unit fact; the gated wait-gate e2e gains two asserts): the gate-arm sentence by exact string in its position (after "led by Lock:relation.", before "This is a shift…"); the ratio arm's multiple from the stampedmean_ratioand from the quotient when unstamped;is_new's context clause with no σ / × / gate claim; a pre-#3780 fact's surrounding text by exact string with no "mean" anywhere, headline equal to the stamped fact's; never "estimated from sampling" / "spent". The live e2e composes the detector's REAL shifted fact and asserts the sentence from its own stamped mean, routine and sigmas.Executed here, not only compiled: a net10.0 harness (
AssemblyName=Darling.Tests, 34 PgTarget / census / hygiene classes incl.PgTargetFactCollectorTests,PgTargetSharedSwitchRoutingTests,PgTargetThresholdLineageTests,PgTargetMeasuredLineageTests,StoreSqlClockDisciplineTests,DocCommentHygieneTests,RepoFileAdoptionTests,FleetIdentifierScrubTests,CommentFilterAdoptionTests,AsOfWindowAnchorTests,FactCollectorCommandTimeoutTests,FactSourceRegistryTests,MeasurementContractCensusTests,StragglerCommandTimeoutTests,LiveCleanupConversionRatchetTests,LivePostgresCollectionHygieneTests,PgTargetBetweenWaves*,PgTargetWaitTests,PgTargetSampledWaitTests,PgTargetNamedHopsTests,CollectionCaveatsTests) under<worktree>/obj/mactest/against a throwawaytimescale/timescaledb:2.28.1-pg18on Docker contextdesktop-linux(role and databasedarling, migrated by the fixture to V135), deleted before commit and torn down after: 427 / 427 green withDARLING_TEST_PGset — every gated e2e in the set ran, including both of this lane's and lanes 3 / 14 / 18 / 25's. First execution of every other census is CI's Windows job.Builds (
-c Debug,-p:EnableWindowsTargeting=truewhere net10.0-windows):PerformanceMonitor.Analysis,PerformanceMonitor.Darling.Analysis,PerformanceMonitor.Darling.Service,Darling.Tests,Lite.Tests,deprecated/Dashboard.Tests— 0 warnings, 0 errors on every one.Which component(s) does this affect?
How was this tested?
Above. Throwaway container only; no production store or fleet server was read.
Checklist
dotnet build -c Debug)pg_arms)Partial for #3691 (lane 26). CHANGELOG deliberately untouched — the coordinator splices this wave's entries. Not armed (review-dark window).