Repository navigation
guards(reach): MIN_GUARDS_EXAMINED must sit in a window, and a stale pin fails as a puzzle instead of an instruction #17818
Description
Activity
- added sub-issues
on Oct 2, 2026 This issue now owns the saturated-reach-floor class
Promoted to class owner rather than filing a sixth issue above the instances. The reason for not opening a new umbrella: this issue is already a sub-issue of #15826 alongside #17400 and #17819, and it already proposes the mechanism fix. A new umbrella in the same tree would duplicate its content and add a number for a defect that already had several.
Instances now wired as sub-issues:
Instance Guard How it presented #17517 docstring-restatement reach floor mainsits exactly at the cap, so any PR adding a public symbol goes red#17142 hooks-path-overridereach floorre-pinned three times on 2026-09-19/20 (6412→6421→6473→6481); skips=1 + growth=400leaves room for under ~1 net filethis issue MIN_GUARDS_EXAMINEDdouble duty as a reach floor and as the check that the floor is tight enough to notice a dropped .glob(term, forcing anarrowed < FLOOR <= fullwindow that moves as the tree growsMilestone moved v0.12.0 → v0.9.5 - CI and guards, where both instances already sit. A class owner scheduled later than its own children cannot be worked in order.
Two corrections to the set as it was originally described (five siblings):
- guards(reach): the hooksPath floor decayed to 14 files of headroom, and nothing reports a floor that is close #16183 is not a fifth instance — it is tech-debt(guards): the hooks-path-override reach floor trips on ordinary PRs — re-pinned three times in one night #17142 seen earlier. Same guard,
hooks-path-override's reach floor, at two points in its decay: guards(reach): the hooksPath floor decayed to 14 files of headroom, and nothing reports a floor that is close #16183 at floor 6027 against population 6413 ("decayed to 14 files of headroom"), tech-debt(guards): the hooks-path-override reach floor trips on ordinary PRs — re-pinned three times in one night #17142 after three re-pins at 6473→6481 against 6881. Two witnesses to one defect, which raises its priority and not its count. Closed as a duplicate against tech-debt(guards): the hooks-path-override reach floor trips on ordinary PRs — re-pinned three times in one night #17142, which carries the sharper allowance arithmetic. - bug(guards): the "tests excluded" reach floor counts 729 test files — its filter is suffix-only #17159 is a different defect and has been re-homed directly under tech-debt(guards): 79 of 133 tree-scanning guards can report clean having examined nothing #15826. "The 'tests excluded' reach floor counts 729 test files — its filter is suffix-only" is a floor measuring the wrong population, not a floor without headroom. The symptom rhymes; the cause does not.
So the class is three guards, not five.
The constraint the fix must not violate
Recorded here because it is the obvious shortcut and it produces a guard that can never fail:
Do not derive the floor from the tree. A floor computed by the same enumerator it guards always agrees with itself.
The property to assert is the window —
narrowed < FLOOR <= full— failing with a message that names the legal range, so a stale pin reads as an instruction rather than a puzzle. That is this issue's existing proposal and it is what makes the class fixable once instead of re-pinned per instance.Acceptance shape for whoever takes it: the window assertion lives in the reach framework, not in each guard; a negative control proves a floor derived from the tree fails the new assertion; and each of the three instances is verified under the new mechanism rather than re-pinned.
- guards(reach): the hooksPath floor decayed to 14 files of headroom, and nothing reports a floor that is close #16183 is not a fifth instance — it is tech-debt(guards): the hooks-path-override reach floor trips on ordinary PRs — re-pinned three times in one night #17142 seen earlier. Same guard,
Closure evidence — all 5 criteria met, AC1 with a location deviation
Verified against merged
origin/main(PR #17951, merge commit12e1a56).AC verdict evidence in merged code 1 — the window asserted in one place, message names range and re-pin value MET in substance, different file _guard_reach_census.py:166-194window_complaint, message at:187-188:"MIN_GUARDS_EXAMINED is {floor}; it must be in ({narrowed}, {full}] -- re-pin to {full}.", asserted byguard_reach_floor_window_17818_test.py:42-51. The criterion namesguard_reach_meta_test.py; the constant and invariant moved to the census module when that file was split at the 600-line ceiling (_guard_reach_census.py:5-13). One place, as required — just not the place the criterion named2 — negative control both directions MET guard_reach_floor_window_17818_test.py:54-66parametrizedoffset [0, -1]reproduces the132 == 132state;:69-73assertsfull + 1refused andfullaccepted. Driveswindow_complaintwith wrong floors rather than mutating the live constant, so it cannot go vacuous3 — narrowed < fullretained separatelyMET guard_reach_meta_test.py:450, with:446-449stating it is retained and is not the window, citing this issue4 — comment records the measured pair and date MET _guard_reach_census.py:104-107:RE-MEASURED 2026-10-04 (#17870, #17818), 172 matched after exemptions, 140 without the glob alternative, legal window(140, 172]5 — no derived floor, with the reason MET _guard_reach_census.py:119-122: a floor computed by the same enumerator it guards "always agrees with itself and can never fail"; repeated atguard_reach_floor_window_17818_test.py:30-33Independent re-measurement on current
origin/main(applying the merged_ENUMERATORand_EXEMPT_NON_SCANNINGtogit ls-treeblobs, not the working tree): 361 trackedrepo_tests/*_test.py, full = 176, narrowed = 142,MIN_GUARDS_EXAMINED = 170(_guard_reach_census.py:126).142 < 170 <= 176— the window holds, 6 below full.- added a commit that references this issue
on Oct 4, 2026 - added a commit that references this issue
on Oct 4, 2026
Finding
guard_reach_meta_test.py'sMIN_GUARDS_EXAMINEDdoes two jobs, and only one of them is visible when it goes stale.:257len(guards) >= MIN_GUARDS_EXAMINED:355len(narrowed) < MIN_GUARDS_EXAMINED:257is tight enough to notice if.glob(were dropped from the enumerator:355is the non-vacuity check on:257. It is the reason a regression that silently narrowed the enumerator would fail loudly instead of reporting clean over a fifth fewer guards, which is the blind spot #16147 was filed for.The consequence nobody wrote down: the constant must sit in a window.
Above the narrowed reach or
:355cannot fire; at or below the full reach or:257fails. That window moves as the tree grows, so the pin needs periodic re-measurement — and when it goes stale the failure surfaces on whichever innocent PR happens to add the guard that closes the gap.Measured, 2026-09-29
Ten days of ordinary guard growth carried the narrowed reach from 104 to 131. Two unrelated PRs then each added an
rglob-based guard, and each became "the 132nd":repo_tests/model_revision_pinning_enforced_17804_test.pyrepo_tests/tts_address_env_names_17782_test.py:121Both went red on
python-suite shard 8/12withassert 132 < 132, and neither PR was defective. Fixed in #17817 by re-pinning to 165 (top of the window, which maximises time to the next re-pin — the same choice the 2026-09-11 and 2026-09-19 re-pins made). #17799 carries a witness comment rather than a second patch.Why this is worth a change and not just another re-pin
The re-pin is correct and the treadmill is inherent — the window moves, so the pin must be re-measured. What is wrong is that a stale pin fails as a puzzle rather than an instruction. Today's message says the floor "cannot detect the loss ... raise it or the mutation is unguarded", which tells the reader something is wrong but not what value is legal. Diagnosing it took reading the docstring, re-deriving both reach numbers by hand, and reconstructing the window from two assertions in different tests.
Proposed change
Assert the window as one invariant, with a message that names the legal range:
so a stale pin fails with "
MIN_GUARDS_EXAMINEDis 132; it must be in (132, 165] — re-pin to 165" instead of leaving the reader to derive it.Explicitly rejected: deriving the floor from the tree. It is the first thing anyone proposes when a pin goes stale, and it destroys the check — a floor computed by the same enumerator it guards always agrees with itself and can never fail. The hand-pinned number is the whole mechanism. Recorded in the constant's comment on #17817 so the next reader does not re-derive it as an improvement.
Also rejected: replacing
:355withnarrowed < full. That looks like the durable form of the same property and is not::354already assertsnarrowed < full("the.glob(term is load-bearing").:355asserts something:354cannot — that the floor would notice. Dropping it would remove the only check on the floor's tightness, which is the non-vacuity property this umbrella exists for.Acceptance criteria
guard_reach_meta_test.pyasserts the windownarrowed < MIN_GUARDS_EXAMINED <= fullin one place, and the failure message names the legal range and the value to re-pin to.132 == 132state reproduced deliberately), and with it set above the full reach it also goes red. Per tech-debt(guards): 79 of 133 tree-scanning guards can report clean having examined nothing #15826, a check that cannot fail is the defect this issue is about.:354(narrowed < full) is retained, not merged into the new invariant — it is a different property.Notes for the owner
Scope is one constant and one assertion in one file — deliberately small, and separate from #17817 which only re-pinned the value.
A class observation, not a filing: a reach floor saturating against its own population and reddening innocent PRs has at least four known instances with no umbrella owning the class — #17517 (docstring-restatement floor,
mainat exactly zero headroom, also shard 8/12), #16183 (hooksPath floor down to 14 files of headroom), #17159 (tests-excluded floor counting 729 test files), #17142 (hooks-path-override floor tripping on ordinary changes), plus this one. Whether that deserves a class umbrella rather than five sibling issues is an owner call; this issue does not assume one.Refs #16147 (the mechanism and the blind spot it was built for), #17517 (sibling instance), #17817 (where this instance was fixed), #17799 (second witness).