Repository navigation
The measurement contract had ten rules and two tests: the list, numbered once, and censuses for rules 1, 2, 3, 5 and 6 (partial #3653) - #3701
Merged
Conversation
Closed
39 tasks done
…red once, and censuses for rules 1, 2, 3, 5 and 6 (partial #3653) #3540 stated the contract in one sentence and its review numbered ten rules; two numbers reached the tree (rule 4 — every family persists its interval; rule 7 — every family seeded) and the other eight stayed a sentence in an issue. This writes the list once, in Lite.Tests/MeasurementContractCensusTests' summary, with each rule's bound and status: 4 and 7 keep the numbers their tests gave them, the six remaining named rules take the free slots in the body's order, and slots 9 and 10 are left empty rather than invented — the review's enumeration is not on the record. Pinned tonight, over source and schema, each with a positive control and a population floor so an empty offender list cannot be a dead regex: - Rule 1 (readers NULL-not-0 on unknowable): no product SQL divides by sample_interval_seconds except through NULLIF(…, 0); every derived interval_seconds alias routes the stored value through NULLIF (two PgBaselineProvider arms are the named allowance — they read a #3698 successor aggregate whose WHERE already dropped the interval-0 collection, and the census asserts that predicate on the named source); every division by the alias sits under a positive guard; every rate arm that falls back to ELSE 0 is rostered shrink-only (four file-I/O trend columns on both SKUs, nine PostgreSQL trend rates, two baseline wait arms — each dead text under its own WHERE). - Rule 2 (rates divide by measured elapsed): zero divisions of a delta by an assumed cadence, SQL and C#, both SKUs — and it stays zero. - Rule 3 (epoch → ClearServer + marker), as a call-site census over #3694's ServerEpoch: exactly the two carriers observe; every forget in the product is the comparator's or a host remove path's (exact set, both directions); both hosts drain the discontinuity account and compose the measurement onto the collection_log note; forget precedes measure precedes persist. Residuals rostered: the five families scheduled before the carrier (read off both hosts' schedule order), and pg_wait_stats, which has no carrier. - Rule 5 (rollups aggregate interval > 0 only), in the Darling half against the real TimescaleSupport constants: the two #3698 successors carry the predicate, query_stats_baseline carries the equivalent delta_execution_count > 0, and the roster names what does not — the superseded legacy pair and the three hourly rollups over query_stats / procedure_stats, whose min() and sample_count read a restart's (0, 0) row as a quiet sample. - Rule 6 (per-second names divided at comparison): every *_per_sec(ond) alias in product SQL is a quotient or a window over one; no collector payload column carries the name. - Rule 8 (gauges never delta'd) is not census-able until cntr_type is stored; the perfmon payload's lack of that column is pinned so the rung reds this row. Two files because the lite CI filter does not reach Darling.Storage or Darling.Analysis and CrossAppGuardCiGateTests fails a Lite guard PR CI cannot run: the Darling half sweeps those two trees with the same regexes and holds the continuous-aggregate census. Test-only; no product code. Every fact executed here (Lite: WPF-hosted harness, 10/10; Darling: mactest harness, 7/7; the whole Darling.Tests assembly runs with the same 188 platform reds as dev) and mutation-checked: twelve planted defects each turned exactly the one fact that guards them red.
erikdarlingdata
force-pushed
the
fix/3653-measurement-census
branch
from
September 19, 2026 07:46
a0034e2 to
67936c1
Compare
This was referenced Sep 19, 2026
erikdarlingdata
added a commit
that referenced
this pull request
Sep 19, 2026
…ned to hide it: every CASE WHEN interval > 0 THEN delta / interval now ends at END, the PostgreSQL trend readers carry the NULL instead of reading it back as 0, and both census rosters are empty (partial #3653) (#3707) #3701's measurement-contract census rostered fifteen rate arms whose CASE fell back to ELSE 0 - the file-I/O throughput trend on both SKUs, nine LAG-differenced PostgreSQL trend rates in DarlingPgTrendReader, and PgBaselineProvider's two ms_per_sec arms - as dead text under their statements' WHERE guards. Every one now ends at END (NULL: no interval, no rate), the shape #3540 rule 1 requires and the already-honest siblings write. The nine PgWaitTrendPoint / PgIoTrendPoint / PgDatabaseTrendPoint rate fields become double? and read DBNull as null; get_pg_wait_trend / get_pg_io_trend / get_pg_database_trend publish the null the way the same payloads already spell an untracked write side, and the C#-side twin evictions_per_second follows (: 0 -> : (double?)null). Two of the fifteen were not dead. The baseline arms' LAG fallback for a pre-column collection derives interval_sec = 0 when two collections date_trunc to the same second; IS NOT NULL alone let the row through and ELSE 0 rated it 0 ms/sec into the sample set (PG18 rig, three planted collections: mean 66.7 where the rated two say 100). END alone would have carried a NULL into clean and COUNT(*)ed it (count 3, mean 100), so with_rate's WHERE takes Lite's interval_sec > 0 beside IS NOT NULL, before the restart LAG (count 2, mean 100). Pinned on both texts in DarlingAnomalyBaselineTests; the nine trend arms and their nullable readers pinned in PgTrendReaderTests; both MeasurementContractCensusTests rosters empty and asserted empty.
erikdarlingdata
added a commit
that referenced
this pull request
Sep 19, 2026
…iced it had changed; Aurora's wait counters had no one watching for a restart at all: wait_stats carries the SQL Server identity first in the order, pg_wait_stats carries pg_postmaster_start_time(), and both census rosters are empty (partial #3653) (#3705) * Five families subtracted from the old instance once before anyone noticed it had changed; Aurora's wait counters had no one watching for a restart at all (partial #3653) The SQL Server identity pair (sqlserver_start_time, @@ServerName) now rides wait_stats' batch as a second result set — first in both hosts' order, observed at the end of ReadAsync and before WritePayload's first subtraction — so every SQL Server delta family re-baselines on the epoch pass instead of five of them fabricating an interval from the dead instance. The CPU carrier stays for the operator who disables wait_stats; ServerEpoch remembers per calculator which identity it last forgot to, so the second carrier does not forget the fresh baselines again. Aurora's pg_wait_stats carries pg_postmaster_start_time() as a trailing non-payload column and forgets its own two groups through the new ServerEpoch.ObservePostmaster. Both #3701 census rosters are empty and asserted empty from the product. * The Lite twin of the state-declaring roster (DefaultTraceEventsCollectorDefinitionTests) moves to six with the two new carriers
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 for #3653 (item 16, "the 10-rule measurement contract as census"). Does not close the issue. Test-only: two new census files, no product code.
What does this PR do?
The contract had ten rules and two tests. #3540 stated the measurement contract in one sentence — "every delta family persists interval; readers NULL-not-0 on unknowable; rates divide by measured elapsed; epoch change → ClearServer + marker; rollups aggregate interval>0 only; per-sec names divided at comparison; gauges never delta'd" — and #3614 added the seeding rule. The review that produced the issue numbered ten; two of its numbers reached the tree (
DeltaFamilyIntervalColumnTestscalls the interval rule rule 4,DeltaFamilySeedingCensusTestscalls the seeding rule rule 7), and the other eight stayed a sentence in an issue, un-pinned.The list, once.
Lite.Tests/MeasurementContractCensusTests' summary is the numbered list, each rule with the bound it rests on and its status (pinned by which test / pinned here / rostered / not census-able and why). The numbering is honest about what the record holds: 4 and 7 keep the numbers their tests gave them; the six remaining named rules take the free slots in the body's order (1 NULL-not-0, 2 measured elapsed, 3 epoch, 5 rollups, 6 per-second names, 8 gauges); slots 9 and 10 are left empty rather than invented — the review's enumeration was never written into the issue or its comments, and the body's order cannot be the review's (the interval rule is first in the body and fourth in the review; the epoch rule is fourth in the body and cannot be seventh). Nothing keys on a number; re-numbering is a comment edit.What is pinned tonight, in the two existing rule tests' idiom — each fact reads source or schema, states the bound it rests on, and keeps a shrink-only roster. Every negative census carries two controls, because an empty offender list agrees with a dead regex: a positive control (a fixture the regex must fire on) and a population floor (the swept text must hold at least N of the thing the rule governs).
sample_interval_secondsexcept throughNULLIF(…, 0); the regex reaches the denominator through any run of parens and function openers that are notNULLIF((CAST(,MAX(,COALESCE(), and the control proves it fires on every such shape. (b) Every derivedinterval_seconds/interval_secalias whose definition reads the stored column routes the value throughNULLIF— the three-state… IS NULL → LAGtest may name the column bare; the value may not. TwoPgBaselineProviderarms are the named allowance (IntervalAliasPassthroughsDefendedByTheAggregatePredicate, Darling half): re-pointed by The wait and perfmon baselines stop counting every restart's fabricated zero as a quiet sample: interval-honest successor aggregates replace the legacy pair in place, the provider reads whichever supply covers its window and gates the LAG heuristic on a NULL interval, the legacy pair retires by a self-executing coverage condition, the startup backfill reads coverage off the materialization, and the Daily-routed calendar answers its unmaterialized days from raw (partial #3653: A6 + A10 mechanical half) #3698 atperfmon_interval_baseline/wait_stats_interval_baseline, whose ownWHERE … IS DISTINCT FROM 0has already dropped the interval-0 collection, so the passthrough cannot see a 0 — and the census asserts that predicate on the named source, so re-pointing either arm at raw reds the allowance. (c) Every division by the alias sits under a positive guard, and every rate arm whose CASE falls back toELSE 0is rostered shrink-only (RateArmsThatFallBackToZero): the two file-I/O trend columns on both SKUs, nine PostgreSQL trend rates, the two baseline wait arms. Each is dead text under its statement's ownWHERE … > 0/IS NOT NULLtoday; rostered because it is the shape the rule forbids, and a census that counts only live defects lets the next one arrive dead and go live in a refactor. The honest end state isEND(NULL) on each — a product edit, not this lane's./ 60,/ 300,/ 900,/ 1800,/ 3600,/ 86400), in SQL (delta_*dividend, no intervening slash — a/ 1000.0 / 60unit chain on a total is not a rate) and in C# (aDelta-named identifier as the dividend, soDefaultMaxGapSeconds / 60is outside by construction). Measurement-layer campaign: the delta honesty contract (11 findings, one keystone) #3540's credits said there were none; this pins zero-and-stays-zero, floored on the 65 + 11 divisions by the measured interval that do exist.ServerEpoch: exactly the two carriers observe (CpuUtilizationCollector→ObserveInstance,PgStatementStatsCollector→ObserveStatements); everyClearServer/ClearGroupscall in the product is the comparator's or a host remove path's — an exact set with counts, both directions; inside each observation the forget precedes the measure precedes the persist of the replaced pair; both hosts drain the discontinuity account after every collector run and compose the measurement onto thecollection_lognote (identity_epoch_changes=1/statements_epoch_changes=1— the A collector definition cannot contribute to collection_log.error_message, so a collector that knows why it returned nothing has nowhere to record it #3161 seam — pinned as the constants a reader keys on), and the carriers declare their state keys. Two residuals rostered shrink-only and READ off the product:FamiliesThatSubtractOnceBeforeTheCarrier= {latch_stats, procedure_stats, query_stats, spinlock_stats, wait_stats}, derived from both hosts' schedule order (CollectorScheduleDefaults.Allkey order for Darling,ScheduleManager.GetDefaultSchedules()for Lite) so moving the carrier's columns onto the first collector empties it;FamiliesWithoutAnEpochCarrier= {pg_wait_stats}.TimescaleSupportconstants by reflection, not source text): of the 22CREATE MATERIALIZED VIEWconstants, 8 read a delta family and aggregate adelta_*column. The two The wait and perfmon baselines stop counting every restart's fabricated zero as a quiet sample: interval-honest successor aggregates replace the legacy pair in place, the provider reads whichever supply covers its window and gates the LAG heuristic on a NULL interval, the legacy pair retires by a self-executing coverage condition, the startup backfill reads coverage off the materialization, and the Daily-routed calendar answers its unmaterialized days from raw (partial #3653: A6 + A10 mechanical half) #3698 successors carrysample_interval_seconds IS DISTINCT FROM 0and are the registered members in the pair's positions;query_stats_baselinecarries the equivalentdelta_execution_count > 0(bound stated: a positive execution delta is only produced from a subtraction the calculator could make); the rosterRollupsThatAggregateUnknowableRowsnames what does not — the superseded legacy pair (perfmon_baseline,wait_stats_baseline; not registered, retiring bySupersededBaselineRelations' coverage condition) and the three hourly rollupsquery_stats_hourly,procedure_stats_hourly,query_stats_db_hourly. On those three a restart's (0, 0) row costs the sums nothing, butcount(*) AS sample_countcounts it as a sample on all three andmin(delta_*)reads it as a real minimum on the two that carry a min; the daily tier is hierarchical from them and inherits both. A CAGG cannot be altered in place; the fix is The wait and perfmon baselines stop counting every restart's fabricated zero as a quiet sample: interval-honest successor aggregates replace the legacy pair in place, the provider reads whichever supply covers its window and gates the LAG heuristic on a NULL interval, the legacy pair retires by a self-executing coverage condition, the startup backfill reads coverage off the materialization, and the Daily-routed calendar answers its unmaterialized days from raw (partial #3653: A6 + A10 mechanical half) #3698's shape (successor under a new name,WITH NO DATA, backfill, coverage-gated retirement) and moves the hourly refresh phase grid — a lane, reported to the coordinator, not a line here. A second fact states why the other 14 aggregates are outside the rule (non-delta source, or hierarchical from another aggregate).*_per_sec(ond)alias in product SQL (47 + 23) is a quotient — its select item contains a division — or a window over one (LAG(ms_per_sec)); no collector payload column carries the name; the perfmon/sec-named counters are stored asdelta_cntr_valuebeside their interval and divided by every reader. Bound stated: the C# payload keys that carry these names copy a reader field the SQL alias populated and are not censused.cntr_typeis not stored (Brains-review campaign: deferred structural residue (from #3538 / #3539 / #3540 / #3541) #3653 A7's rung), so nothing in the tree can say which perfmon rows are gauges.TheGaugeRule_WaitsOnTheCounterTypeRungpins the fact the wait rests on — nocntr_typecolumn in the perfmon payload, one delta call for every counter, levels and rates both inDefaultCounters— so the rung reds the row and the census is owed. The viewer item's/sec-suffix proxy is not pinned; that lane has not landed.Why two files. The
liteCI filter reachesLite, the sharedPerformanceMonitor.*libraries (viacore), the Darling Service and the Darling Viewer — and notDarling.StorageorDarling.Analysis.CrossAppGuardCiGateTestsfails any Lite guard whose source read PR CI cannot run (#2839). So the Lite file sweeps exactly the ten trees it names, andDarling/Darling.Tests/MeasurementContractCensusTestssweeps the other two with the same regexes (duplicated deliberately — a cross-project equality pin would itself be a read the gate has to reach) and holds the Darling-only artifact, the continuous aggregates. It usesRepoFile.Rootonly (no LF reader), soRepoFileAdoptionTestsneeds no entry; neither file filters source lines by comment prefix, soCommentFilterAdoptionTestsneeds none — SQL is read throughCSharpSourceWalker.StringLiteralBodieswith SQL comments blanked (newlines kept), C# throughStripCommentsAndStrings, so prose that quotes the forbidden shape (this repository's comments quote it often) cannot count as the shape.What it does NOT do. No product code: the three hourly rollups, the eleven
ELSE 0arms and the two passthrough aliases are rostered and reported, not fixed. It does not recover rules 9 and 10. It does not census the C# payload keys for rule 6, the DST bucket smear (Q6), or the viewer's rendering (A7). It does not touchCHANGELOG.md,McpPageContractTests.cs, or either existing rule test.Which component(s) does this affect?
How was this tested?
Test-only. Both projects build
-c Release -p:EnableWindowsTargeting=truewith zero new warnings (Lite.Tests carries dev's pre-existing xUnit2000 onLogTailOverlapThresholdPinTests.cs:95; Darling.Tests 0/0).Every fact was executed here before push, not only compiled: the Lite half through a throwaway WPF-hosted harness (net10.0-windows,
Microsoft.WindowsDesktop.Appremoved from the runtimeconfig) — 10/10 green, 2.2 s; the Darling half through the mactest harness (net10.0,AssemblyName=Darling.Tests) — 7/7 green, 0.3 s; the whole realDarling.Testsassembly runs on the Mac with the same 188 platform reds dev shows (WPF / SqlClient / install paths), none naming this file or the adoption censuses;CrossAppGuardCiGateTests13/13 green against the tree with the new Lite file in it. Re-run green after rebasing onto dev at 3676970.Mutation-checked: twelve planted defects, each restored afterwards, each turned exactly the one fact that guards it red and nothing else — a bare
/ sample_interval_seconds; an alias definedELSE sample_interval_seconds; a rate arm givenELSE 0;/ 60in SQL;deltaValue / 60.0in C#; a removedClearServeron Lite's remove path; a per-second alias passed through raw; aPgBaselineProviderallowance re-pointed at raw; a successor CAGG stripped of its predicate (reds rule 5 AND the allowance defense); a rosteredELSE 0retired without leaving the roster; a PostgreSQL per-second alias passed through raw;query_stats_db_hourlygiven the predicate without leaving the roster.Population floors as measured tonight (each set well under the measurement, as dead-sweep detectors): Lite half — 1,089 files, 112
sample_interval_secondsmentions in SQL, 30NULLIF(…, 0)denominators, 29 derived-alias definitions (25 stored-backed), 45 divisions by the alias, 65 deltas over a measured interval, 47 per-second aliases. Darling half — 106 files, 9NULLIFdenominators, 24 alias divisions, 11 measured, 23 per-second aliases, 22 CAGG constants, 8 governed.Checklist
dotnet build -c Debug)