Repository navigation
Fixes #3069 - #3077
Fixes #3069#3077
Conversation
…ithmetic it rests on HeaviestHourlyRefreshObservedCeilingSeconds' doc comment presented 864 s as the highest figure recorded under the narrowed refresh window, alongside three companions climbing with volume. A status-verified ten-run series supersedes that characterisation, and the 864 s run ends one second after the boundary the regime split is drawn on, so its regime membership is undetermined rather than post-treatment. The comment now states where the number came from, the status filter it was read under, the transition-run ambiguity, the distribution, the two snapshot readings that are inadmissible for setting a constant and why, and why the value is unchanged in both directions. RefreshCeilingProvenancePinTests derives every summary figure from the constants or from the series the comment publishes and requires the prose to agree.
|
Reviewed the diff (doc-comment rewrite on Correctness — Manually re-derived every figure the new doc comment states (10-run series, 9-run clean series after setting the transition run aside, min/max/mean/median, slot clearances at 900 s, the 594↔306↔36 downward-edit consequence, the 13:30:00→13:44:24 = 864 s clock arithmetic, and the #3069 median discrepancy) against the actual Lite/Darling parity — No parity concern. Security / SQL style — No SQL, no user input, no new external I/O beyond Performance — Test-only change; no runtime/collector code paths touched. Left one inline note on the new test file about the maintenance cost of tightly regex-pinning free-form doc-comment prose (13 patterns that must match near-verbatim wording) — not a bug, but worth considering for how costly future wording-only edits to that comment will be. |
…census RefreshCeilingProvenancePinTests.DocProseFor collects the contiguous /// run above a declaration, which is the COLLECTS kind CommentFilterAdoptionTests already holds DocCommentHygieneTests and both AnalysisPassTokenThreadingTests twins to. The entry states the bound: the walk stops at the first non-/// line, and a truncated walk fails the <summary>/</summary> anti-truncation assertions rather than pinning half a comment. The adjacent kind count read "Two collect a doc-comment run" against three such entries, so it was stale by one before this entry and would be stale by two after.
ReviewWent through the full diff ( Scope check: this touches only Correctness: hand-verified all the arithmetic the new doc paragraph and the pin tests assert:
The Lite/Darling parity: no concern. Security/performance: no input handling, SQL construction, or hot-path code touched; the added tests do in-memory regex/string work only (reading No bugs found. Style follows this repo's established (unusually verbose) doc-comment convention already used in |
…nted claims DocProseFor now strips <b> emphasis and normalises em/en dashes to a hyphen before any pattern sees the prose, so bolding a figure or changing dash style can no longer break a pin. The thirteen patterns lose all seven <b> couplings and the \S dash stand-in, and are trimmed to the span that brackets their numbers: 122 verbatim anchor words down to 96, with the drift sweep still at 45 injections, so nothing stopped being guarded. The parse-miss message now names all three correct fixes - update the pattern, fix the prose, or delete the figure and drop the pin - and says why editing a pattern is sanctioned rather than a loophole: the drift sweep re-derives every case from the pattern, so one widened into a no-op goes red. The population-merge mutation is addressed by ordinal through the same source rewrite the sweep uses, instead of string-replacing an emphasis-tagged reading. s_bounded's doc comment describes the census by count, and nothing held the two together: it read "Two collect a doc-comment run" while three entries already did. All five counted claims are now derived from the map and its entry text, with the kind labels required to account for every entry.
…cludes The snapshot paragraph led with "Two further readings of 342 s and 348 s", which enumerated a series that gains a reading every hour this job runs - a frozen enumeration reading as a complete one. A third reading of 286 s arrived and made it wrong. The rule now leads: the self-metrics snapshot has no status column while HeaviestRefreshRuntimeSql and JobCadenceReadSql filter Success, so no reading from it may set this constant. That is a statement about the source and does not go stale. The readings stay as illustration, carrying an as-at stamp so the list cannot read as complete. The pin's pattern was the same defect with a test around it: "(N) s and (N) s" encoded the arity. It now captures the whole list however long, and Verify requires the as-at scope to be present - checked for presence, not value, because the timestamp is evidence rather than a derived bound.
|
Reviewed. This is a doc-comment + test-only change to Verified by hand, independent of the new pin test:
Lite/Darling parity: no drift here. TimescaleDB compression/refresh scheduling is Darling-only (Postgres/Timescale) per CONTRIBUTING.md's architecture section — Lite uses DuckDB and has no equivalent concept, so no counterpart change is expected or missing. T-SQL style guide: not applicable — no SQL in this diff, only C# doc comments and xUnit tests. Security/perf: none — no I/O, no external input, no new runtime code paths; the new test file only parses/asserts against the checked-in source at test time via No correctness bugs found. Nice touch pinning |
… just date it Dating a list is a step short of bounding it: "the readings so far" carries a scope and still rots, because a doc comment has no timestamp of its own for a relative phrase to be read against. The prose now says "the complete set of snapshot readings up to 04:20Z", a window that has ended, and the pin demands the closing preposition and an absolute stamp rather than any stamp.
ReviewScope: doc-comment-only changes to Correctness — Verified the arithmetic the new doc comment publishes against the pin tests by hand:
No bugs found in the pin/verification logic itself (ordinal-based number addressing, width handling on digit-count-changing bumps, anti-truncation Lite/Darling parity — Not applicable here. Security / Performance — None of concern. Test-only file I/O reads the repo's own One observation, not a blocker: this is a heavyweight mechanism (a second ~800-line test file doing regex extraction over doc-comment prose) to keep a single constant's provenance narrative from drifting. It's well guarded against silently going blind, but it does mean every future wording tweak to that doc comment risks needing a matching pattern update in |
#3075 rewrote CommentFilterAdoptionTests' CLASS summary (the build.yml filter paragraph). This branch edits s_bounded's own doc comment and the map below it, so the two do not overlap and every count derived here is unaffected: 4 COLLECTS + 1 stated bound + 1 SQL + 1 demonstrator = 7 keys, re-counted after the merge rather than assumed.
…tation of it lives The rule has now been derived from scratch twice by different readers and has only ever lived in review threads. ReadmeDerivedCountPinTests implements both halves and states neither: a numeral restating an adjacent list gets deletion offered in its failure message, while a numeral that is program output gets "fix the pattern rather than the count", because a transcript has to keep showing what the tool really prints. A reader currently has to infer that from the disagreement between two failure texts in one file. Three sentences in the class summary, citing #3072 and #3073, naming which kind the thirteen patterns here are and why that puts them on the deletion-sanctioned side. Marked as narration rather than a counted claim, so nothing pins it.
|
Reviewed. This PR is doc-comments-and-tests-only — the constant Verified the arithmetic the new doc comment and
One nit posted inline: the new No security, correctness, or performance concerns beyond that — this is test/documentation infrastructure with no runtime behavior change. |
…ships The paragraph explaining why the patterns can be ASCII-only still credited a \S dash stand-in, which was deleted three commits earlier when DocProseFor gained dash normalisation. Zero of the thirteen patterns use \S and none carries a non-ASCII character, so the comment described a mechanism the code no longer implemented - which is the defect this file exists to catch, one level up. The conclusion was never wrong, only the reason: the patterns are ASCII-only because DocProseFor normalises em and en dashes to a plain hyphen before any pattern runs. The sentence now says that, and names the one literal hyphen below as an ASCII hyphen in the prose rather than a normalised dash. Corrected AND enforced. NoPattern_NeedsToMatchADashVariant asserts no pattern carries a non-ASCII character, and checks the normalisation itself against an arranged doc run through the real extractor, so "the patterns can be ASCII-only because the extractor normalises" is no longer a claim with nothing behind it.
Review summaryScope check first: this PR touches no T-SQL at all — the only production-code diff is to XML doc comments on Correctness: I traced all 13 regex pins in Security / perf: No SQL, no external input, no new file/network/process use beyond reading the test's own source file via The one thing worth raising (left as an inline comment on Nothing here blocks the PR from my read — flagging the complexity/maintenance-surface point for the team's awareness rather than as a defect. |
… look load-bearing Reviewed all thirteen against one criterion: does the pattern pin a figure derivable from the constants or from the published series? Eleven do. Two did not. The pair explaining why #3069's ~347 s median is not reproducible from its own published rows pinned seven captures of arithmetic about a superseded EXTERNAL figure. Nothing downstream depends on it, and the figure it defends has no referent in this codebase - the middle reading it contrasts with is already pinned against the series. So the derivation is out of the prose and the two pins are gone with it; ~347 s stays as a bare quotation, which is the same category as the snapshot readings and correctly unpinned. The slot-clearance pattern also captured the clean count a third time, after the run-count and clean-series pins. Dropped. 11 patterns, 69 anchor words, 37 sweep injections - from 13 / 94 / 45, and from 122 anchor words before the first review round.
|
Reviewed this PR against CONTRIBUTING.md conventions, Lite/Darling parity, security, correctness, and performance. Summary: no issues found. Scope. All three files are Darling-only ( Correctness — verified by hand, not just read:
Security/perf. No new I/O beyond No inline comments filed; nothing rose to the level of a defect. |
HeaviestHourlyRefreshObservedCeilingSecondskeeps the value 864. What changes is what its doc comment claims about where that value came from, plus a pin that holds every figure derived from it to agreeing with the series the comment now publishes.What the doc said, and what it says now
Before, the constant was introduced as "the longest run recorded ... under the narrowed
HourlyRefreshStartOffsetwindow", and its measured-range paragraph read: under the 1-day window the highest figure recorded is the 864 s here, with the drift chart's most recent readings for the same job at 194 s, 225 s and 335 s, "climbing with volume rather than settling".Both halves of that are now superseded. The companions did not keep climbing — the same job went on to 594 s and settled back into the 300s — and 864 s is not demonstrably a maximum of the narrowed regime at all.
Now the comment states, in this order:
13:30:00to13:44:24on the boundary day, on the one store that carries this workload, read from that store's per-run job history with an explicitsucceededcolumn that saidt.HourlyRefreshStartOffsetreached that store's refresh policies at13:44:23— one second before that run ended. So either 864 s is the transition run, in flight whilestart_offsetwas narrowed underneath it and therefore neither cleanly pre- nor post-treatment; or the boundary timestamp was itself derived from that run's completion, in which case the boundary and the constant are the same observation and cannot corroborate each other. Separating those two needs clock times nobody has read.The series, and its status provenance
Ten consecutive runs of this job's refresh policy, each read with an explicit
succeededcolumn and every one of themt, in start order across the ten hours after the boundary:864, 194, 222, 225, 335, 594, 465, 359, 293, 355seconds.Setting the first aside for the reason above, the remaining nine run from 194 s to 594 s, mean 338 s, middle reading 335 s — every one below
RefreshSlotWarningSeconds. The largest clears the 900 s slot by 306 s, where the constant clears it by 36 s.Three things are recorded about the series rather than smoothed over:
00:35:05. By the next look the catalog's last-run figure had already advanced past it.StoreSelfMetrics.BackgroundJobInsertSql(object_kind = 'background_job') recordslast_run_durationwith no status column at all, whileHeaviestRefreshRuntimeSqland Query Store aggregate tax scales serially with fleet size — measure, alert, and evaluate before large onboardings #2136'sJobCadenceReadSqlboth filterlast_run_status = 'Success', so an unfiltered series can carry an aborted run's duration. A test checks that reason against the shipped SQL rather than restating it.Why the value is unchanged, in both directions
Upward is asserted as a failure by design.
TimescaleSupportTestscarriesHeaviestHourlyRefreshObservedCeilingSeconds < RefreshPhaseStepMinutes * 60, built by #3055 so the number could not be renumbered through — past the slot width the refresh runs into its neighbour and the grid needs redesigning, not renumbering. Nothing here touches that assertion.Downward is the subtler trap, and it is why the honest reading of the observation does not license editing the number. Correcting toward the observed 594 s would leave 306 s of margin in place of 36 s — and the reason
CompressionPhaseMinutesexcludes the heaviest slot whole rather than guarding it rests on that 36 s being real. At 864 s the run occupies 14.4 of the slot's 15 minutes, so no minute of it aCompressionPhaseGuardMinutesband could recover; at 594 s it occupies 9.9, and minutes 10 through 14 of that slot become recoverable. A downward edit therefore reopens #3035's exclude-vs-guard design decision rather than merely re-provenancing a number, and eleven hours of one quiet night does not settle that.So the resolution is the one #3069 states for itself — the post-fix distribution came back with its maximum inside the slot, so the constant gets its provenance recorded and the grid stands as designed.
RefreshSlotWarningSeconds, the build-time assertion and #3035's grid are all untouched, and no migration rung is added.The pin, and the evidence that it can fail
RefreshCeilingProvenancePinTestsparses the realTimescaleSupport.cs(resolved from[CallerFilePath], so there is no second copy to go stale) and requires every figure the comment states to follow from the constants or from the series the comment itself publishes. Nothing in it hardcodes 864, 900, 36, 306 or 338.What it derives:
HeaviestHourlyRefreshObservedCeilingSecondsexactly once — the link that makes the transition-run paragraph about this numberRefreshPhaseSlotSecondsminus the listed maximum, and the stated margin equals it minus the constantend - startequals the constant, andend - boundaryequals exactly one second — the transition-run finding, as a subtractionoccupies 14.4 of the 15 minutesequals the constant in minutes andRefreshPhaseStepMinutes, with a separate assertion that the constant is still an exact tenth of a minute so a rounded claim cannot wear an exact one's clothesAssert.Allover the whole clean inventory — every cleanly post-boundary reading is below the constant and below the watch line — rather than one true clause standing in for the set, with the population asserted non-empty firstHeaviestRefreshRuntimeSqlandJobCadenceReadSqlfilter to successful runs,BackgroundJobInsertSqldoes not and carries no status column at all. The predicate is red-proofed in both directions on synthetic copies, because a predicate that could only returntruewould satisfy the two positive lines and prove nothing about the negative one — which is the load-bearing half.Red-proof, run on the committed tree.
EveryNumericPin_ReportsAnInjectedDriftbumps each captured number one at a time in a mutated copy, asserts the pattern still matches (so a mutation that merely broke a regex cannot pass as a caught drift), then requires verification to fail with something other than a parse miss. It ran 45 injections and all 45 were caught; the count is asserted equal to the captured-number total, so a sweep that enumerated nothing goes red rather than green. One at a time is the point: a bump to a middle-ranked series reading changes neither the range nor the middle, and is caught only because the mean is stated too.Verifyalso requires it consumed every pin inPins(), so a pattern cannot sit in the list looking like it guards something.Twelve hand-injected mutations were run separately against the real files, each with a build-exit check distinct from the run so a stale dll could not print a clean
Failed: 0:864->870(still inside the slot, still above the watch line, still an exact tenth)222->223(range and middle unchanged)338->339306->30513:44:23->13:44:22359->35814.4->14.5; slot15->16BackgroundJobInsertSqlgains a status filterHeaviestRefreshRuntimeSqlloses its status filterPins()thatVerifynever consumesOne mutation that did not go red is worth recording: rewording a paragraph heading nothing asserts on. That is a mutation aimed at text the assertions do not read, so it is not a test of the pin — not a gap in it.
Verification, and its scope
Darling.Testscannot run on macOS, so the actual test sources were compiled into throwawaynet10.0xunit v3 harnesses staged in the gitignored projectbin/, each with a build-exit check separate from the run:TimescaleSupportTests: 46 tests, Failed 0, Not Run 0, 15 skipped and every one of them a_AgainstDevPostgreslive-store test. The three facts that read this constant were also run individually by name —CompressionPhaseGrid_ClearsEveryRefreshSlotsGuardBand_AndTheHeaviestRefreshsSlotWhole,TheRefreshSlotReading_CarriesItsOwnVerdict_AndReportsOverrunAsNegativeHeadroom,TheRefreshSlotLogLine_IsLeveledByBand_AndSaysNothingWithoutAReading— eachTotal: 1, Failed: 0.DocCommentHygieneTests: 40 tests, Failed 0, and proved to be reading the edited file by injecting a stacked<summary>into the new doc run and watching two of its facts go red.PerformanceMonitor.Darling.StorageandDarling.Testsboth build with-p:EnableWindowsTargeting=trueand 0 errors; the 49 analyzer warnings onDarling.Testsare all pre-existing xUnit nags in other files, none in the new one. CI's Windowsbuildjob remains the arbiter for the full suite.What is still outstanding, and is not claimed here: the status-filtered per-bucket split of the full per-run series (
collect.store_metrics,object_kind = 'background_job') on the boundary timestamp, giving count, median and maximum each side of it. That is the read that would give the constant real provenance in either direction, it needs a session against the one store that carries this workload, and it was not taken. The doc comment names it as the outstanding read rather than leaving a future reader to rediscover that it is missing.One whole-tree guard this had to join, and a stale count beside it
The first CI round came back with exactly one failure across both suites —
Lite.Tests3402/0,Darling.Tests7794 with a single red, so the new pin's own tests passed on Windows and on the Linux Postgres job. The red wasCommentFilterAdoptionTests.EveryLinePrefixCommentFilter_StatesTheBoundItRestsOn:DocProseForwalks the contiguous///run above a declaration, which is a line-prefix comment filter, and that guard requires every such site to be enumerated with the bound it rests on.It is registered as the COLLECTS a doc run kind — the same kind
DocCommentHygieneTestsand bothAnalysisPassTokenThreadingTeststwins are on. The prefix defines the run rather than approximating comment-stripping, and asking forCSharpSourceWalkerwould leave nothing to read, since the figures being pinned live only in comments. The stated bound is that the walk stops at the first non-///line, so a block comment between the doc run and its declaration truncates it — and that direction is loud rather than quiet, because the collected prose is asserted to open at<summary>and close at</summary>before any figure is compared.The kind count in that class's own doc comment was already stale. It read "Four kinds live here ... Two collect a doc-comment run" against three such entries, so it was wrong by one before this PR and would have been wrong by two after. Corrected to "Four" in the same commit rather than filed, since it is one word adjacent to the line being added and this change is what makes it worse.
Red-proofed locally rather than assumed: removing the new census entry reproduces the exact CI failure, same expected/actual pair (
Lite.Tests/AnalysisPassTokenThreadingTests.csagainstDarling.Tests/RefreshCeilingProvenancePinTests.csat index 4), which is also what confirms the local harness reads the same tree CI does. All four harnesses re-run green afterwards with build exit codes checked separately: pin 5/0,CommentFilterAdoptionTests2/0,DocCommentHygieneTests40/0,TimescaleSupportTests46/0.Review round two: the pin's prose coupling, cut where it was cuttable and defended where it was not
The review granted the arithmetic and objected to maintenance surface — ~80 lines of prose tied to 13 near-verbatim patterns, where a copy-edit touching no number reds CI. Two thirds of that was fair.
Fixed at the extractor.
DocProseForstrips<b>emphasis and normalises em/en dashes to a hyphen before any pattern runs, so all seven<b>couplings and the\Sdash stand-in are gone. Patterns are trimmed to the span bracketing their numbers: 122 verbatim anchor words down to 96, with the drift sweep still at 45 injections — so the reduction cost nothing in coverage. The population-merge mutation now addresses its number by ordinal through the same source-rewrite the sweep uses, instead of string-replacing an emphasis-tagged reading, which would have found nothing if someone unbolded it.The failure message now names all three correct fixes — update the pattern, fix the prose, or delete the figure and drop the pin — and says why editing a pattern is sanctioned rather than a loophole:
EveryNumericPin_ReportsAnInjectedDriftre-derives every case from the pattern you write, so one widened into a no-op goes red. #3073 already ships that same protection (EveryPin_ReportsAnInjectedDrift), and its own handling of the third outcome is split three ways: the prose-pin message lists two outcomes and omits pattern-editing; a code comment above that assertion (ReadmeDerivedCountPinTests.cs:198-200) discourages it, scoped to a formulaic README inventory sentence; and its--test-connectiondenominator sweep directs it outright (:147, "Fix the pattern rather than the count."). So this message states, for the prose kind, the outcome the prose-pin message left unstated — on the mechanism #3073 already carried that makes it safe. Not a divergence from policy, and not an oversight being corrected either: a deliberate split, stated here for the kind that invites editing.The multiset alternative was measured, not argued away. The doc run holds 65 numerals, 39 distinct, and the derived figures repeat:
36four times,594/194/335/9three times each,306/864/10twice. Set-semantics containment false-passes on three of four injected single-figure corruptions, catching only338— the one figure stated exactly once. A count-bearing multiset would catch them only by encoding per-figure occurrence counts, which is the restatement the bar bans and which reds on any rewording that mentions a figure once more or less. The underlying reason is that a numeral bag cannot police which claim a number belongs to, and36versus306— same constant, same slot, different sentence — is exactly the error a future editor makes.The census summary, pinned rather than filed
CommentFilterAdoptionTestshad to gain an entry for the new pin's///walk (the COLLECTS a doc run kind, alongsideDocCommentHygieneTestsand bothAnalysisPassTokenThreadingTeststwins). While registering it,s_bounded's doc comment turned out to describe the census by count and to be wrong: it read "Two collect a doc-comment run" while three entries already did — stale by one before this PR, and it would have been stale by two after. 4 COLLECTS + 1 stated bound + 1 SQL + 1 demonstrator = 7 keys, which is the map's size.The durable finding is the asymmetry: that guard catches a new member by name and nothing caught its own summary drifting, in a file whose entire job is adoption tracking. So the summary is now pinned rather than just corrected. All five counted claims are derived — the kind total plus one claim per kind — from the map and its entry text; none was underivable, and the kind labels are required to account for every entry so the breakdown cannot quietly stop summing to the map.
Note this loose-on-prose/strict-on-numbers shape is available here precisely because a count survives arbitrary rewording as long as the numeral is still there. It is not available for a figure whose meaning depends on which sentence it sits in, which is why the thirteen patterns stay.
Red-proofed four ways, each confirmed red then reverted: prose count wrong against the map; a numeral spelled outside the word vocabulary (the word-to-digit mapping is the load-bearing part, since the prose spells counts as words); a fifth
COLLECTSentry added with the prose untouched; an entry whose bound names no recognised kind. The pin also caught a mistake of mine on its first run — it was anchored on the class summary rather than ons_bounded's own doc comment, and the wrong doc run yields prose with no counted claim in it, so it failed loudly instead of comparing nothing.One more thing the prose was carrying alone
The build-time assertion
CompressionPhaseGuardMinutes * 60 < HeaviestHourlyRefreshObservedCeilingSecondsstill passes at 594 (420 < 594). So it does not protect the exclude-whole decision at all: the reasoning that no minute of the heaviest slot is guard-recoverable was carried by the doc comment with nothing asserting it. That is not fixed here — fixing it means re-deriving #3035 — but it is now stated where the next reader will find it, and it is on #3069.CI
Round two on
c25b262bewas fully green: all 8 checks, including the Windowsbuildat 8m15s,Darling PostgreSQL testsat 4m13s andDarling whole-tree guards. Round one's only failure was the census entry, now fixed. Round three is running on1811b3a66.The snapshot enumeration, and the scope rule it taught
A third snapshot reading (286 s, at the 04:20Z self-metrics snapshot,
total_runs331→332) arrived while this PR was in review, and it made one sentence wrong: "Two further readings of 342 s and 348 s come from the hourly self-metrics snapshot". Unlike the ten-run series — which is scoped to a window that has ended and so cannot be falsified by a later run — that sentence carried no scope and read as a complete enumeration of a set that grows every hour this job runs. A frozen enumeration wearing a complete one's clothes, which is #3072's defect and the thing this PR's own pin exists to prevent.Fixed by deleting the count, not by writing "Three" — #3073's delete class. The paragraph's real subject is the inadmissibility rule: the self-metrics snapshot records
last_run_durationwith no status column whileHeaviestRefreshRuntimeSqlandJobCadenceReadSqlboth filterlast_run_status = 'Success', so no reading from it may set this constant. That is a statement about the source and does not go stale. The readings stay as illustration, scoped.The pin had the same defect with a test wrapped around it. Its pattern was
readings of ([0-9]+) s and ([0-9]+) s come from— the arity was the count, encoded in a regex. It now captures the whole list however long. Proven both directions: appending a fourth reading and cutting back to one both stay green, while folding a status-verified series value into the list reds on disjointness.And the scope has to CLOSE the population, not merely date it. "The readings so far" carries a scope and rots anyway, because a doc comment has no timestamp of its own for a relative phrase to be read against. The prose says "the complete set of snapshot readings up to 04:20Z" — a window that has ended — and the pin demands the closing preposition with an absolute stamp. Red-proofed: replacing it with a relative scope reds, and dropping it entirely reds.
The scope marker is checked for presence, not value. The timestamp is evidence; pinning it to a derived quantity would be inventing a bound this constant does not have.
The provenance correction is now corroborated by contact, not only by absence
An overlap did occur: the refresh ran 03:52:17→03:57:03 and a compression policy fired at 03:52:57, forty seconds into it. Contact made the refresh faster, not slower — 286 s, the fastest reading of its tracked series. So the one mechanism that could have pushed the real post-boundary maximum back toward 864 s and retroactively justified that number did not occur under direct contact. 594 s stands as the post-boundary maximum.
Carrying the bound honestly: the compression run was 0.9 s, which is consistent with compressed quickly without contention or with found little eligible at 04:00 on a Sunday, and
last_run_durationalone cannot separate them. That ambiguity is on the compression side and does not weaken the refresh-side measurement, which is direct. Durations and run counts are observed; start times are derived from the finish-to-start rule.Re-verified after
origin/devmoved, and one credit correctionorigin/devadvanced to0f888e90c(#3075) while this was in review, and it touched the same file —CommentFilterAdoptionTests.cs— withgit merge-treereporting zero conflicts, which is the case worth checking rather than trusting. #3075's edit is confined to that class's summary (thebuild.ymlfilter paragraph); this branch editss_bounded's own doc comment and the map below it, so they do not overlap.origin/devis merged in here so CI runs the combined tree rather than two halves.Every count re-derived after the merge, not assumed: 4
COLLECTS+ 1 stated bound + 1 SQL + 1 demonstrator = 7 map keys; the drift sweep still at 45 injections; all four local harnesses green on the merged tree. Worth noting the check that matters is the pin itself — a grep forCOLLECTSnow returns 5, because it also matchess_kinds' own label table, which is exactly why the count is derived from the map in code rather than counted by eye.Credit correction: the
CommentFilterAdoptionTests"Two → Four" fix repaired a pre-existing stale count, not an adjustment for this PR's entry. Three entries already collected a doc run when the prose said "Two". Adding the fourth made it wrong by two instead of one, but the drift predates this branch.One thing left for #3075's lane rather than taken here. That PR's new summary text says
CrossAppGuardCiGateTests"does see the twoLite.Testskeys below" — a fresh counted claim of exactly the kind this PR pins, one doc run away from the one now pinned, and derivable (count map keys prefixedLite.Tests/). It is correct today. It is not pinned here because it is another lane's just-landed prose and the census pin deliberately coverss_bounded's doc run only; flagging rather than silently extending.The two-kinds numeral policy, written down where the second implementation of it lives
This reasoning has now been derived from scratch twice by different readers, and both times it lived only in a review thread. It is repo policy and it is sharper than anything either #3072 or #3073 states individually:
ReadmeDerivedCountPinTestsimplements both halves and states neither, so the rule has to be inferred from the disagreement between two of its own failure texts. Three sentences now sit in this class's summary, citing both issues, naming which kind the thirteen patterns here are — derived arithmetic restated in prose, hence the deletion escape throughout — and marked explicitly as narration of an existing rule rather than a counted claim, so nothing pins it. A pin on a sentence about pinning is where this stops being useful.A stale justification in this PR's own new file, and why it was re-pointed rather than deleted
Review found
RefreshCeilingProvenancePinTests.cs:97-99justifying its ASCII-only patterns by a\Sdash stand-in — a mechanism deleted three commits earlier, whenDocProseForgained dash normalisation. Verified before fixing: zero of the thirteen patterns use\S, and zero carry a non-ASCII character; the one literal hyphen, in([0-9]+)-second slot, is a plain ASCII hyphen in the prose.That is exactly the defect this file exists to catch — a comment claiming a mechanism the code no longer implements — occurring one level up, in the guard's own commentary, about its own patterns. Conceded rather than argued.
Re-pointed, not deleted, because only the reason was wrong. The patterns are still ASCII-only on purpose; what makes that possible is
DocProseFornormalising—and–to a plain hyphen before any pattern runs, so none of the thirteen has to match a dash variant. Deleting the sentence would have lost a true and load-bearing fact.Corrected and enforced, since the replacement sentence makes a checkable claim and leaving it as prose would repeat the mistake more slowly.
NoPattern_NeedsToMatchADashVariant_WhichIsWhatTheNormalisationBuysasserts no pattern carries a non-ASCII character, and drives the realDocProseForover an arranged doc run so the normalisation claim has something behind it. Red-proofed both ways: an em dash injected into a pattern reds, and neutering the em-dash normalisation reds — the latter caught by this test alone.The asymmetry this is the second instance of.
CommentFilterAdoptionTestscaught a new member of its census while nothing caught its own summary drifting; these pins watchTimescaleSupport.cs's doc run while nothing watches this file's own prose. The boundary is probably right — pinning a test file's commentary is where this stops paying — but two instances make it a pattern rather than an incident, and it is named in the lane report rather than built, because the honest scope of this fix is one sentence and one assertion.Proportionality, and the two patterns that did not earn their place
Review's second concern was the ratio: ~1,054 lines of regex-driven prose verification against a doc comment on a constant whose value does not change. Legitimate, and the second concern on this axis — the first produced 122 → 96 anchor words. Applying the reviewer's own framing to a re-audit produced a real cut: 13 → 11 patterns, 94 → 69 anchor words, 45 → 37 injections.
The ratio conflates two things. The coupling to prose is 11 patterns, mean 6.3 anchor words each. The rest — the injection sweep, the ordinal source-rewrite,
Verify's consumption check, the anti-truncation guards, and 177 lines of doc comment — is what makes the pin trustworthy, and none of it needs editing when the prose changes; a copy-editor touches at most one pattern per reworded sentence. 337 of the 844 lines are comments and blanks.Dropped as incidental: two patterns pinning seven captures of arithmetic that explained why #3069's
~347 smedian is not reproducible from its own published rows. That figure has no referent in this codebase, nothing downstream depends on it, and the reading it contrasted with is already pinned against the series. The derivation is out of the prose and both pins are gone with it;~347 sremains a bare quotation — the same category as the snapshot readings, correctly unpinned. A third pattern captured the clean count for the third time; that capture is gone too.The 11 that remain each derive a figure from the constants or from the published series, and each was wrong or unprovenanced in the version this PR replaces: the series itself (must contain the constant exactly once),
end − start == 864,end − boundary == 1, stated count vs rows listed, the five clean-series statistics,Slot − max/Slot − Ceilingtwice over,Ceiling/Slot/margin,Ceiling / 60andRefreshPhaseStepMinutes, the series minimum, and the snapshot readings' disjointness and closed scope.Bound on the claim, because overselling the pin would be the same mistake as the
\Ssentence. The constant's value is not what this guards and is not unguarded either —TimescaleSupportTestscarries the build-time envelope assertion andpeak.ClearOfSlotSecondsindependently pins 306. This pin guards the provenance narrative, which is what nothing else could guard and precisely what #3069 was filed about.Coverage re-proved after the cut, each red then reverted: middle reading
335 → 336; clearance306 → 305; constant864 → 870; a non-extremal series reading222 → 223, caught only via the stated mean; margin36 → 63.