diff --git a/dag/gunbc/recurring_failure_mode/guard_precondition_discharged_by_the_route_that_uses_it.dag b/dag/gunbc/recurring_failure_mode/guard_precondition_discharged_by_the_route_that_uses_it.dag new file mode 100644 index 00000000000..5c1dd7b4bc9 --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/guard_precondition_discharged_by_the_route_that_uses_it.dag @@ -0,0 +1,28 @@ +module gunbc.recurring_failure_mode.guard_precondition_discharged_by_the_route_that_uses_it + +import std.types { NonEmptyStr } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data guard_precondition_discharged_by_the_route_that_uses_it: RecurringFailureMode = RecurringFailureMode { + identity: "guard_precondition_discharged_by_the_route_that_uses_it" as NonEmptyStr, + + receipts: [ + "**a guard that stops discriminating because its precondition moved is not a guard that failed -- it is one that was SILENTLY RETIRED, and it will keep reporting PASS forever** (INVALID STATE: a check is current, correct, and executing exactly as designed, and its answer has stopped carrying information because the condition it keys on is no longer reachable on the population it guards. Nothing is stale and nothing is broken. The check is dead and every consumer still reads its PASS as evidence. HARM: a failed check is loud and a retired one is indistinguishable from a healthy one, so the deficit never ranks for repair; worse, the guard continues to be CITED as coverage, and a second mechanism that would otherwise have been built is not built because this one is believed to exist.", + + "RECEIPT, MEASURED ON THIS REPOSITORY THE NIGHT THE ROUTE CHANGED: the generated-artifact merge driver refuses a projection only when BOTH SIDES have changed it since the merge base. gunbc#10302 delegated design-ledger regeneration to the heal job, and its declared repair route instructs the author to COMMIT THE PROVISIONAL BYTES. That commit MOVES THE MERGE BASE, after which only one side has changed the projection, so the driver has nothing left to refuse and reports a clean tree -- over a head that deletes rows from the ledger. THE REFUSAL WAS NOT DEFEATED, IT WAS DISCHARGED, BY THE VERY COMMIT THE ROUTE INSTRUCTS. Two pull requests sat in that state at once, one probing clean while deleting twenty-one rows.", + + "THE PART THAT MAKES IT A CLASS RATHER THAN A BUG IN ONE DRIVER: NOBODY WEAKENED ANYTHING. No rung was lowered, no waiver was written, no code in the driver was touched. A change elsewhere invalidated the driver's PREMISE, and DESIGN section 4b(3) governs DELIBERATE drops -- it has nothing to say about a guarantee that evaporates as a side effect. So this class of regression is structurally exempt from the mechanism built to catch regressions, which is why it can persist indefinitely with every roster and every gate reporting green.", + + "DISTINCT FROM THE STALE-TOOL CLASS, AND THE BOUNDARY IS CLEAN. A superseded tool executing in place of the current one is a VERSION fact and is repaired by installing the incoming copy. This is a PREMISE fact: the tool is the current one, it is correct, and it is running as designed. Different mechanism, different remedy, different row.", + + "ADJACENT TO THE NEVER-AUTHORABLE-RED CLASS AND DELIBERATELY NOT MERGED WITH IT, because the adjacency is the finding. DESIGN section 4b instructs an author to ask whether a check's RED is authorable BEFORE writing the check. That question has no owner once the check is written and shipped: this class is THE SAME QUESTION ASKED LATE, and nobody asks it late. A check whose RED was never authorable is born decorative and can be caught at review; a check whose RED was authorable and SILENTLY STOPPED BEING passes every review it ever had, because it was genuinely load-bearing at the moment it was approved. Same terminal state -- permanently green by construction -- reached from opposite ends.", + + "RECOGNITION RULE: FOR EVERY GUARD, NAME ITS PRECONDITION, THEN ASK WHAT WOULD MAKE THAT PRECONDITION PERMANENTLY FALSE AND WHETHER ANYTHING WOULD NOTICE. A guard whose precondition can be discharged by a ROUTINE, INSTRUCTED ACTION is not a guard, it is a coincidence detector. The sharpest form of the question is whether the route the guard protects is itself capable of satisfying the guard's escape condition, because a mechanism that disarms its own check is not a risk, it is a schedule.", + + "A SECOND-ORDER TRAP FOUND WHILE WRITING THIS ROW, AND THE REASON THE REPLACEMENT CHECK IS STATED AGAINST ZERO. The obvious replacement -- compare the projection against main and refuse on deletions -- was first written by declaring the observed deficit, twenty-one rows. Two hours later, with the branch untouched, it was twenty-three: THE DEFICIT IS A FUNCTION OF MAIN, NOT OF THE HEAD BEING JUDGED, so any declared count expires the next time an unrelated pull request lands. THE COUNT IS DATED, THE PREDICATE IS NOT. Zero is main-invariant and survives every main move, which is why the check must test against zero and never against a number someone measured.", + + "RUNG FOUND AT: mitigatable, and the mitigation is that a reviewer independently compared the projection to main instead of reading the guard's verdict. CEILING: structurally guaranteed -- a guard carrying its precondition as a declared, checkable fact rather than as an implicit property of how it is invoked admits a refusal when that precondition becomes unreachable, so no Accepted program contains a guard that has silently stopped discriminating. NEXT-RUNG TRIGGER, a CAPABILITY and not an artifact, and stated so it cannot be satisfied by the instance that produced it: a guard declares the precondition under which its verdict carries information, AND the surrounding mechanism refuses when a guard is consulted on a population where that precondition cannot hold. Repairing the merge driver, or adding one deletion check to one gate, satisfies neither half and leaves every other guard in the tree exposed in exactly the same way.", + ], + + evidence: [], +} diff --git a/dag/gunbc/recurring_failure_mode/roster.dag b/dag/gunbc/recurring_failure_mode/roster.dag index 380b444851c..9adf61fea05 100644 --- a/dag/gunbc/recurring_failure_mode/roster.dag +++ b/dag/gunbc/recurring_failure_mode/roster.dag @@ -106,6 +106,7 @@ import gunbc.recurring_failure_mode.subject_and_its_digest_as_independent_parame import gunbc.recurring_failure_mode.a_written_row_is_not_a_firing_mechanism { a_written_row_is_not_a_firing_mechanism } import gunbc.recurring_failure_mode.required_evidence_absent_reads_as_evidence_of_pass { required_evidence_absent_reads_as_evidence_of_pass } import gunbc.recurring_failure_mode.right_censored_cost_read_as_exact { right_censored_cost_read_as_exact } +import gunbc.recurring_failure_mode.guard_precondition_discharged_by_the_route_that_uses_it { guard_precondition_discharged_by_the_route_that_uses_it } data recurring_failure_mode_roster: List = [ censored_estimator_drops_its_own_tail, @@ -203,4 +204,5 @@ data recurring_failure_mode_roster: List = [ a_written_row_is_not_a_firing_mechanism, required_evidence_absent_reads_as_evidence_of_pass, right_censored_cost_read_as_exact, + guard_precondition_discharged_by_the_route_that_uses_it, ] diff --git a/docs/design-failure-modes.md b/docs/design-failure-modes.md index 96bcbb55d7c..f7e887d00aa 100644 --- a/docs/design-failure-modes.md +++ b/docs/design-failure-modes.md @@ -99,6 +99,7 @@ The exact `RecurringFailureMode.identity` population, which no other projection - `a_written_row_is_not_a_firing_mechanism` - `required_evidence_absent_reads_as_evidence_of_pass` - `right_censored_cost_read_as_exact` +- `guard_precondition_discharged_by_the_route_that_uses_it` --- @@ -209,3 +210,4 @@ The landing measurement partitions the 31 parser-visible identities into **2 cit - **a written rule is how a LATER READER learns what happened; it is not how a PRESENT AUTHOR is stopped, so a ledger that grows without changing what is easy to type buys documentation and no prevention** (INVALID STATE: a failure class is answered by APPENDING A ROW -- to this roster, to a stall roster, to an annotation -- and the row is then counted as the remedy. The class recurs anyway, because at the moment of authoring the dangerous form is still the shortest thing to type and nothing costs more when it is chosen. RECOGNITION RULE, which is the whole row: after filing, ask WHAT IS NOW HARDER TO DO THAN IT WAS BEFORE. If the honest answer is nothing, the filing was a RECORD and not a REPAIR, the class rung did not move, and it must be reported as UNREMEDIED rather than as covered. WHY IT IS NOT MERELY WEAK BUT ACTIVELY MISLEADING: a filed class gets CITED AS COVERAGE, so a reviewer meeting it reads it as handled and the filing converts an open deficit into a closed-looking one while leaving the deficit exactly where it was -- a DESIGN section 4b(1) rung wearing a 4b(2) costume, which is this ledger own version of rung inflation. An unrepaired filing is therefore WORSE than no filing, not equal to it. WHY THE RECALL DOES NOT FIRE: a rule filed under its SUBJECT MATTER is retrieved by thinking about that subject matter, and an author executing a step attends to THE GOAL, not the class of the step. Nothing in `retire the superseded poller` cues `I am about to type a pattern that can match myself`. THE TEST RUN ON A REAL POPULATION THE SAME NIGHT IT WAS WRITTEN, AND IT CAME BACK MOSTLY NEGATIVE: across ten class-filings required in one day, the identity-join rows made nothing harder (`sort -u` is exactly as easy to type as `sort`); the prose-adjacency, field-adjacency and digest-beside-subject rows made nothing harder (no lens refuses a digest passed beside its subject, and that signature is still the natural one to write); the empty-reading rows made nothing harder (the short read is still shorter than the head-filtered one, which is precisely why four people reached for it). ONE of the ten changed what is easy, and IT WAS NOT A FILING: a schema hazard was answered by computing the affected population and commenting on each of the five pull requests about to hit it, delivering friction to five named authors rather than prose to a ledger. A second was initially scored as a climb and the correction is the sharper result: the carrier ALREADY HAD THE RIGHT SHAPE and nothing about it was built that day; what the day produced was the DISCOVERY that a wrong thing was writable beside it, because an author wrote a fabricated previous-rung into a drop row, A REGEN RAN GREEN OVER IT, and a reader happened to look at the field. NO MECHANISM WAS WATCHING. Corrected score: ONE push-friction instance that expires when five pull requests land, ZERO climbs, ONE discovery -- and the discovery is the least repeatable item in the list, since the next occurrence is written where nobody is reading and the green regen is identical. A LUCKY READ IS NOT COVERAGE. THE TWO KINDS OF FRICTION ARE NOT INTERCHANGEABLE AND ONLY ONE COMPOUNDS: PUSH friction is delivered to named authors at the moment of impact and EXPIRES when their changes land; PULL-PROOF friction removes the constructor, so nothing needs delivering to anyone ever again. A day producing one of each must not report two. THE CONCLUSION THE AUDIT FORCES, STRONGER THAN THIS ROW STARTED: retrieval-by-recall is not a mechanism that becomes adequate at a smaller ledger size -- IT IS THE WRONG MECHANISM AT ANY SIZE, because the retrieval cue never arrives regardless of how few rows there are. Every row real deliverable is THE FRICTION, and the prose is its RECEIPT rather than its product. RUNG FOUND AT: mitigatable, and this row is an instance of what it describes, which is why it carries a trigger rather than resting on having been written. CEILING: structurally impossible for any class whose dangerous form can be removed from the vocabulary entirely -- an unwritable form needs no rule. NEXT-RUNG TRIGGER, a capability and not an artifact: for each filed class, a named ARTEFACT OF FRICTION -- a lens that refuses the shape, a carrier with no unsafe constructor, a wrapper shorter to invoke than the raw form -- so that a filing arrives WITH a change in what is easy, and the obligation is symmetric: whoever ASKS for a row owes the friction artefact or the plain sentence that nothing got harder and the class stands UNREMEDIED.) - **a gate that admits when its required evidence has not reported, because the admission arm keys on OBSERVED FAILURE rather than on OBSERVED SUCCESS.** INVALID STATE: a required check exists, is correctly configured, and is consulted -- and the consulting arm asks `has anything reported a failure` where the guarantee needs `has everything reported a success`. Between those two questions sits the state where nothing has reported at all, and it is admitted. HARM, AND THE REASON THE CLASS SURVIVES REVIEW: every artifact reads as present and correct. The gate is enumerated in the required roster, it is active, it blocks a reported failure exactly as advertised, and a reader auditing the configuration finds no drift -- because there is none. The defect is in the QUANTIFIER, and a quantifier has no configuration surface to inspect. DISTINGUISHING FACT, AND IT IS THE RACE RATHER THAN ANY FIELD: the class is only reachable inside the window between the evidence being DEMANDED and the evidence ARRIVING, so it is invisible to any observation taken after that window closes -- afterwards the check has reported, the record looks ordinary, and only the ORDER of two timestamps distinguishes an admitted merge from a blocked one. RECOGNITION RULE: for every gate, find the arm that admits and read what it is quantified over. If it enumerates the evidence that HAS arrived and asks a property of each, the empty enumeration admits. If it enumerates the evidence that is REQUIRED and asks each for a success, it refuses. The two spellings are one word apart and behave identically on every input except the one the class lives in. DISTINCT FROM `absorbing_fallback`: that arm WIDENS when it cannot compute an answer and is at least loud about doing work; this arm NARROWS to the empty set and is silent, because a fold over nothing returns its seed and nobody wrote the seed down as a decision. **SPECIMEN (eager-bear-107, gunbc#10236, 2026-09-03), and it landed a break rather than merely permitting one.** The pull request pushed head d8cd3034 at 19:49:33Z, GitHub created its `witnesses` run at 19:49:40Z, and the merge completed at 19:49:43Z -- three seconds after run creation, before any job of it reported. That run then concluded with `required-witnesses-build` and `required-witnesses-floor` both FAILURE, and the head it certified nothing about landed on main as cfe19ea7, adding two duplicate declarations to THIS MODULE that refused main at resolve until a repair pull request landed. WHICH LANE CAUGHT IT IS PART OF THE FILING, because the two main flakes are separable in this evidence and a reader who conflates them loses that: on the post-merge main run at cfe19ea7 the duplicates reddened `required-witnesses-build` while `required-witnesses-floor` was GREEN, so the break is not the cost class this repository's other main flake belongs to and cannot be waved away as more floor variance. THE DETECTING LANE WORKED AND WAS TWENTY MINUTES LATE, which is the shape of this class rather than an aggravating detail: `required-witnesses-build` refused the duplicates correctly -- `generated-artifact CarrierRefused cause=resolve`, the authority declining to answer -- and its job completed at 20:04:14Z against a merge at 19:49:43Z, an unadjudicated interval of twenty minutes and thirty-one seconds. NOTHING WAS MISROUTED AND NO LANE WAS MISSING. **A RETRACTION IS RECORDED HERE BECAUSE THE MISREADING IS ITSELF AN INSTANCE OF A ROSTERED CLASS.** An earlier revision of this row said the catcher was `heal-generated-artifacts` and that it was event-conditional, on the evidence that heal FAILED on the pull-request run and was SKIPPED on the main run of identical content. The job graph refutes it: heal died at step 2, `Checkout triggering branch head`, at 19:52:01Z, with `Regenerate every committed generated artifact` SKIPPED -- the regenerator never ran, so heal detected nothing, and it failed because the merge had deleted the branch head it wanted three seconds after the run was created. A downstream consequence of the merge was read as a detection of the defect. That is `green_reported_over_a_population_the_instrument_does_not_own` inverted -- a RED reported over a population the instrument never reached -- and the recognition rule transfers exactly: A JOB'S CONCLUSION IS NOT EVIDENCE ABOUT THE SUBJECT IT IS NAMED FOR UNTIL ITS STEP RECORD SHOWS IT REACHED THE STEP THAT JUDGES. It survived four readers passing a narrative and was caught by one who read the job graph. Ruleset 16178731 carried zero divergence from `gunbc.repo_ruleset` desired state throughout. Over the forty most recently merged pull requests, six had no `witnesses` run that completed successfully on their own head before `merged_at`. **THE SAME SHAPE IN THIS REPOSITORY'S OWN MODEL, which is what makes it a class and not an incident:** `gunbc.merge_lifecycle` `merge_enabled` folded `policy_admits` over the receipts found for a head from `init: false`, so the absent-receipt verdict was a caller-local constant standing in for a policy fact. There the seed was the SAFE answer and the harm was the mirror image -- the live behavior became unrepresentable, no witness could go red on it, and the module named a policy stronger than the live one as live for two months. RUNG FOUND AT: mitigatable, and only by human habit. CEILING: structurally guaranteed -- the merge queue construction makes the queued ref's run a precondition of landing rather than a fact observed beside it. NEXT TRIGGER: `gunbc.guarantee_stall` `merge_admission_terminal_verdict_stall`. FILED AS A STALL AND NOT A RUNG DROP: a 4b(3) drop asserts a REGRESSION and nothing regressed -- GitHub's rule has evaluated reported check runs this way since the ruleset was created, so the capability was never held and a previous rung would be invented. What existed was 4b(1) inflation, corrected by making the live policy representable. - **a right-censored cost read as an exact one** (an instrument stops because a POLICY THRESHOLD fired before the subject completed, and the figure it emits is a LOWER BOUND on the true cost. Carried in the same field, column or type as a completed measurement, it is then summed, ranked, compared against a line, or deflated into a budget as though it were the cost. WHAT MAKES IT INVISIBLE IS THAT THE BOUND LOOKS LIKE DATA: it has the right units, the right magnitude and the right shape, so nothing about the value marks it as incomplete. AND THE MAGNITUDE IS APPROXIMATELY THE CEILING THAT STOPPED IT, which inverts every ranking built on it. A preempted row reports a figure near the budget, so it sorts ABOVE genuinely expensive completed rows and a 'worst observed' derived from the population describes THE CEILING, NOT THE MACHINE. The remedy sized from it is then sized against a policy constant that the operator chose, wearing the authority of a measurement. RECOGNITION RULE: WHEREVER A COST, DURATION, SIZE OR COUNT CAN BE TRUNCATED BY A DEADLINE, BUDGET, RETRY CAP, PAGE LIMIT OR TIMEOUT, ASK WHETHER THE STOPPED CASE AND THE COMPLETED CASE INHABIT THE SAME CARRIER. If one field, column or constructor holds both, the conflation has already happened and no consumer can undo it -- the information distinguishing them was destroyed at the write, not at the read. The tell is a field named for the quantity (`cpu_ms`) rather than for the measurement's completeness, beside a separate flag nobody joins to it. THIS IS THE INVERSE OPERATION OF `censored_estimator_drops_its_own_tail` AND THE TWO MUST NOT BE MERGED. There, censored observations are EXCLUDED from an estimate and the statistic is biased low with no bound; here a censored observation is INCLUDED and read as exact. Dropping the tail and admitting the tail as a point are opposite mistakes over the same population, and a repair for one is not a repair for the other -- a system can and did commit both about the same artifact. It is also distinct from `window_rendered_subject_misattribution`: there a correctly-measured figure is attributed to the wrong subject; here the subject is right and the figure is not a measurement at all. SPECIMEN, gunbc#10210. `required_floor_claim_cost.tsv` carried one `cpu_ms` column for every claim. A claim the per-claim CPU deadline preempted goes INTERRUPTED-BEFORE-VERDICT and reports where the POLL OBSERVED THE CEILING -- 500ms against a 500ms budget, or 502ms -- while a completed claim reports its cost. The floor cost distribution's bands, percentiles, worst-row and inflation pairing consumed the column undifferentiated, so the implied-budget derivation deflated a ceiling by a ratio computed partly from ceilings. RUNG FOUND AT: BELOW THE FLOOR, WHICH IS NOT RUNG 1 AND THE DISTINCTION IS THE POINT. Rung 1 requires harm CONTAINED by total operations, typed outcomes, bounds, rollback or isolation. A column rendering a bound and a completion under one name contains nothing: it does not refuse, bound or prevent, and a censored value consumed where an exact cost is read is a FABRICATED PLAUSIBLE OUTPUT, which DESIGN section 4b places outside the ladder and forbids outright. This row was first filed claiming `mitigatable` and that was refused by review; the correction is recorded because the inflated reading was written by the author of the repair, inside the change that fixed it. IT IS EXPLICITLY NOT THE *OUTSIDE THE MODELED GUARANTEE* BOUNDARY ONE SENTENCE AWAY IN DESIGN. The cost is measured and then misrepresented; it is neither external, nor undecidable, nor unstated intent. A class that reaches the ladder only by ceasing to fabricate has not climbed a rung -- it has become eligible to be ranked. ATTAINABLE CEILING: STRUCTURALLY IMPOSSIBLE, because membership is decidable at the WRITE. The instrument always knows which arm it took -- it stopped the subject itself -- so the distinction is available at the moment the row is produced and needs no inference at any consumer. A carrier with disjoint constructors makes the conflated state unconstructible rather than merely refused. NEXT-RUNG TRIGGER, AND IT IS THE WHOLE PAIRING RATHER THAN ANY ONE OF ITS PARTS. Each half alone is satisfiable while the class stays alive, which is why a trigger naming less than all four is a trigger that retires the row while the harm persists: (i) DISJOINT CONSTRUCTORS, so a bound and a completion cannot inhabit one value; (ii) DISJOINT WIRE FIELD NAMES, because a shared column re-fuses them at the artifact boundary no matter how the in-memory type is shaped, and a consumer projecting that column gets an empty cell rather than a figure near the ceiling; (iii) EVERY ARITHMETIC CONSUMER REQUIRING THE EXACT TYPE IN ITS SIGNATURE, so summing, ranking or deflating a bound is a compile refusal rather than a discipline; and (iv) A DYNAMIC MIXED POPULATION THAT REFUSES RATHER THAN FILTERING, because silently dropping the censored members is `censored_estimator_drops_its_own_tail` -- the repair for one failure mode arriving as the other. THE FOURTH CLAUSE IS THE ONE AUTHORS OMIT, and omitting it converts this class into its inverse in a single edit that looks like a fix. A GUARD THAT EXCLUDES THE CENSORED POPULATION BY A CORRELATED PROXY IS NOT THIS REPAIR AND IS `incidental_denominator_as_wall`. In the specimen a verdict-absence flag very nearly separates the two populations, because a deadline-preempted claim also reaches no verdict -- but the axes are independent by construction: an unwound claim reaches no verdict with EXACT clocks, and a claim can reach its verdict while its cost is a bound. A witness keyed to the proxy stays green under a fold that reads the bound as a cost, because its fixture is excluded before the cost is consulted, so the proxy guard also DEFEATS THE EVIDENCE that would detect the class. THE REPAIR IS THEREFORE TWO ROWS, EACH FIXING ONE INPUT AND VARYING THE OTHER, and one of them alone proves nothing about the axis it is named for.) +- **a guard that stops discriminating because its precondition moved is not a guard that failed -- it is one that was SILENTLY RETIRED, and it will keep reporting PASS forever** (INVALID STATE: a check is current, correct, and executing exactly as designed, and its answer has stopped carrying information because the condition it keys on is no longer reachable on the population it guards. Nothing is stale and nothing is broken. The check is dead and every consumer still reads its PASS as evidence. HARM: a failed check is loud and a retired one is indistinguishable from a healthy one, so the deficit never ranks for repair; worse, the guard continues to be CITED as coverage, and a second mechanism that would otherwise have been built is not built because this one is believed to exist.RECEIPT, MEASURED ON THIS REPOSITORY THE NIGHT THE ROUTE CHANGED: the generated-artifact merge driver refuses a projection only when BOTH SIDES have changed it since the merge base. gunbc#10302 delegated design-ledger regeneration to the heal job, and its declared repair route instructs the author to COMMIT THE PROVISIONAL BYTES. That commit MOVES THE MERGE BASE, after which only one side has changed the projection, so the driver has nothing left to refuse and reports a clean tree -- over a head that deletes rows from the ledger. THE REFUSAL WAS NOT DEFEATED, IT WAS DISCHARGED, BY THE VERY COMMIT THE ROUTE INSTRUCTS. Two pull requests sat in that state at once, one probing clean while deleting twenty-one rows.THE PART THAT MAKES IT A CLASS RATHER THAN A BUG IN ONE DRIVER: NOBODY WEAKENED ANYTHING. No rung was lowered, no waiver was written, no code in the driver was touched. A change elsewhere invalidated the driver's PREMISE, and DESIGN section 4b(3) governs DELIBERATE drops -- it has nothing to say about a guarantee that evaporates as a side effect. So this class of regression is structurally exempt from the mechanism built to catch regressions, which is why it can persist indefinitely with every roster and every gate reporting green.DISTINCT FROM THE STALE-TOOL CLASS, AND THE BOUNDARY IS CLEAN. A superseded tool executing in place of the current one is a VERSION fact and is repaired by installing the incoming copy. This is a PREMISE fact: the tool is the current one, it is correct, and it is running as designed. Different mechanism, different remedy, different row.ADJACENT TO THE NEVER-AUTHORABLE-RED CLASS AND DELIBERATELY NOT MERGED WITH IT, because the adjacency is the finding. DESIGN section 4b instructs an author to ask whether a check's RED is authorable BEFORE writing the check. That question has no owner once the check is written and shipped: this class is THE SAME QUESTION ASKED LATE, and nobody asks it late. A check whose RED was never authorable is born decorative and can be caught at review; a check whose RED was authorable and SILENTLY STOPPED BEING passes every review it ever had, because it was genuinely load-bearing at the moment it was approved. Same terminal state -- permanently green by construction -- reached from opposite ends.RECOGNITION RULE: FOR EVERY GUARD, NAME ITS PRECONDITION, THEN ASK WHAT WOULD MAKE THAT PRECONDITION PERMANENTLY FALSE AND WHETHER ANYTHING WOULD NOTICE. A guard whose precondition can be discharged by a ROUTINE, INSTRUCTED ACTION is not a guard, it is a coincidence detector. The sharpest form of the question is whether the route the guard protects is itself capable of satisfying the guard's escape condition, because a mechanism that disarms its own check is not a risk, it is a schedule.A SECOND-ORDER TRAP FOUND WHILE WRITING THIS ROW, AND THE REASON THE REPLACEMENT CHECK IS STATED AGAINST ZERO. The obvious replacement -- compare the projection against main and refuse on deletions -- was first written by declaring the observed deficit, twenty-one rows. Two hours later, with the branch untouched, it was twenty-three: THE DEFICIT IS A FUNCTION OF MAIN, NOT OF THE HEAD BEING JUDGED, so any declared count expires the next time an unrelated pull request lands. THE COUNT IS DATED, THE PREDICATE IS NOT. Zero is main-invariant and survives every main move, which is why the check must test against zero and never against a number someone measured.RUNG FOUND AT: mitigatable, and the mitigation is that a reviewer independently compared the projection to main instead of reading the guard's verdict. CEILING: structurally guaranteed -- a guard carrying its precondition as a declared, checkable fact rather than as an implicit property of how it is invoked admits a refusal when that precondition becomes unreachable, so no Accepted program contains a guard that has silently stopped discriminating. NEXT-RUNG TRIGGER, a CAPABILITY and not an artifact, and stated so it cannot be satisfied by the instance that produced it: a guard declares the precondition under which its verdict carries information, AND the surrounding mechanism refuses when a guard is consulted on a population where that precondition cannot hold. Repairing the merge driver, or adding one deletion check to one gate, satisfies neither half and leaves every other guard in the tree exposed in exactly the same way.