diff --git a/dag/gunbc/recurring_failure_mode/detector_promoted_to_an_actuator_predicate.dag b/dag/gunbc/recurring_failure_mode/detector_promoted_to_an_actuator_predicate.dag new file mode 100644 index 00000000000..a23c44e26ea --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/detector_promoted_to_an_actuator_predicate.dag @@ -0,0 +1,36 @@ +module gunbc.recurring_failure_mode.detector_promoted_to_an_actuator_predicate + +import std.types { NonEmptyStr } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data detector_promoted_to_an_actuator_predicate: RecurringFailureMode = RecurringFailureMode { + identity: "detector_promoted_to_an_actuator_predicate" as NonEmptyStr, + + receipts: [ + "**a correct detector is wired to a side effect that is only valid on a subset of what it detects** (INVALID STATE: a predicate that TRULY and COMPLETELY describes a condition is promoted to select the population an ACTUATOR runs over, without the additional clause that separates the members needing the action from the members for which the same condition is the CORRECT and HEALTHY state. The detection is not wrong at any point. The promotion is. ", + + "**WHAT MAKES IT DANGEROUS IS AN ASYMMETRY BETWEEN READING AND ACTING, and it is the whole reason the classes must be kept apart: OBSERVING a member the predicate correctly returns costs nothing, and ACTING on it can be destructive.** So a predicate can be perfectly validated as a description and still be unsafe as a trigger, and no amount of confirming the DESCRIPTION discovers it. ", + + "**THE RECOGNITION RULE, and it is checkable in one question before any code changes: WAS THE PREDICATE VALIDATED AGAINST THE SPECIMEN THAT PROMPTED IT, OR AGAINST THE POPULATION IT WILL ACT ON?** These are different sets and the second is the only one that matters. The prompting specimen is by construction a member needing the action -- that is why it prompted -- so it can never expose the healthy majority. Nobody asks a detector what ELSE it returns, because it was built from the one thing it was supposed to return. ", + + "**SPECIMEN WITH A RECEIPT, 2026-09-04, gunbc CI sweep, and both halves are mine.** A fleet sweep for parked workflow runs filtered on `status == completed AND conclusion == action_required`. A peer found a THIRD parked shape that filter could not reach -- `conclusion == cancelled` with an empty job list on a live head -- and correctly diagnosed the cause: the population was selected by a CONTAINER FIELD, so it admitted only the shape already seen. That is `population_selector_that_cannot_admit_a_counterexample`, committed inside the sweep whose author had relayed that row hours earlier. The proposed repair was to drop the conclusion predicate and filter on TERMINAL AND ZERO JOBS, which is a true and complete description of the parked state. ", + + "**AND IT WOULD HAVE BEEN CATASTROPHIC AS A TRIGGER.** Run at member grain over the last 100 runs it returns TWENTY-ONE hits across ELEVEN branches, all `conclusion=cancelled` -- and roughly twenty are SUPERSEDED HEADS, cancelled before scheduling because the author pushed again. Zero jobs is exactly CORRECT for those: the run was killed as obsolete. The branch clustering shows the healthy population is the BULK and not an edge -- four runs on one branch, three on another, two on a third. Rerunning them would resurrect dead heads, register checks against commits nobody is trying to land, and spend runner capacity in a queue already measured at eighty-plus minutes deep. **n=1 CONFIRMING, n=20 REFUTING, AND THE TWENTY WERE NEVER QUERIED.** ", + + "**THE MISSING CLAUSE IS LIVENESS, AND IT IS A DISCRIMINATOR RATHER THAN A HEURISTIC: `terminal AND zero jobs AND head_sha == the CURRENT head of an OPEN pull request`.** A superseded run fails the third clause BY CONSTRUCTION -- being superseded is precisely what made its head stale -- so the clause separates the two populations structurally rather than by threshold or confidence. Detect at member grain; GATE THE ACTUATOR ON LIVENESS; then branch on the conclusion only to choose the instrument, since `approve` releases an existing run and `rerun` starts a new attempt. ", + + "**THE CONTROL THAT MADE THE CORRECTED SWEEP'S ZERO READABLE, recorded because the sweep returned zero and a zero is the value a broken join also returns.** After adding the liveness clause the sweep found no parked runs on live heads. That zero was checked by running the head-matcher against a KNOWN-LIVE head -- the author's own open PR -- and confirming it returned one. Without that control the result is indistinguishable from a join that matches nothing, which is `absent_reads_identically_to_never_looked`. ", + + "**A NEIGHBOURING DEFECT, NOT THIS ONE, FOUND IN THE SAME HOUR AND RECORDED HERE ONLY TO SEPARATE THEM.** The sweep's author had been reporting `the fleet is clear` all night. That was true of the population the filter owned -- no runs AWAITING APPROVAL -- and was stated as the wider claim, no PARKED runs. A summary is a predicate too, and it inherits the narrowness of the query beneath it while its WORDS name the wider set. THIS ROW IS NOT ITS AUTHORITY: there is no actuator and no side effect in a status summary, so the distinguishing fact below -- detection and actuation having different admissible populations -- does not obtain, and filing it here would widen this class past its own boundary and fork an authority that already exists. It belongs to `green_reported_over_a_population_the_instrument_does_not_own`, whose subject is exactly an instrument reporting over a population it does not own. Recorded as a neighbour because the two were discovered together and a later reader tracing this specimen should be sent there rather than back here. ", + + "**THE BOUNDARIES, since three roster rows sit adjacent and none covers this.** `population_selector_that_cannot_admit_a_counterexample`: there the QUERY IS WRONG and cannot return the negative; here the query is RIGHT and returns the whole population faithfully. `repair_enumerates_its_own_blast_radius_by_inspection`: there a COUNT of affected sites is stated with no decidable search behind it; here the search is decidable, executed, and correct, and the count is not in dispute. `guard_precondition_discharged_by_the_route_that_uses_it`: there a check stops discriminating because its precondition moved; here nothing has moved and the check discriminates exactly as designed. `green_reported_over_a_population_the_instrument_does_not_own`: there a REPORT names a wider population than the query beneath it owns, with no effect anywhere in it; here the report is not at issue and the defect is an EFFECT admitted on the wrong population. The distinguishing fact for this row is that DETECTION AND ACTUATION HAVE DIFFERENT ADMISSIBLE POPULATIONS and one predicate was used for both. ", + + "**RUNG: 1 (mitigatable)** -- caught by asking the recognition question before wiring a predicate to an effect. ", + + "**CEILING: 4 (structurally impossible), AND THE ROUTE TO IT IS NOT A STATIC SHAPE TEST.** An earlier draft of this row justified its ceiling by saying the property is decidable from the modeled call graph -- whether a predicate reaching an effectful operation carries a clause the pure-observation path does not. That justification is withdrawn: it is SYNTACTIC, and an arbitrary or irrelevant conjunct satisfies it while preserving the invalid state exactly. A check satisfiable by editing the declaration while the realization still lies is the validation-standing-where-construction-was-available tell of DESIGN section 5, so the shape test establishes no rung above 2. What it can honestly do is ENUMERATE CANDIDATES -- effect paths carrying no additional clause at all -- which is a useful lens and not a wall. ", + + "**NEXT-RUNG TRIGGER, the capability and not an artifact, stated so that satisfying it entails the guarantee.** The actuator must DECLARE ITS ADMISSIBLE POPULATION as a predicate over the member, and the effect constructor must require a witness produced by EVALUATING THAT DECLARED PREDICATE on the member being acted on -- so that a detection result has no constructor into the effect at all, and the promotion fails to construct rather than being caught by a reviewer who thought to ask. EXCLUSIVITY IS THE WHOLE OF IT AND EXCLUDING THE DETECTION RESULT ALONE IS NOT ENOUGH: a successful evaluation must be the ONLY constructor of the permit, so that a caller-authored receipt, a bare member, or a true boolean cannot inhabit it either. A permit type carries no safety property of its own -- the property lives entirely in an exclusive constructor that proves the actuator's declared policy over the EXACT subject acted upon, and any additional constructor silently returns the class to rung 1 while the type name still reads as coverage. Both halves are load-bearing and a trigger naming only the second is the grain mismatch section 4b(3) names as its own review tell: a receipt type whose constructor does not require that evaluation is vacuously inhabitable, claims admissibility that no constructor entails, and leaves the class exactly where it was while reading as coverage. The receipt must be grounded in the actuator's own policy or it is decoration, and this trigger is retired by nothing less.", + ], + + evidence: [], +} diff --git a/dag/gunbc/recurring_failure_mode/roster.dag b/dag/gunbc/recurring_failure_mode/roster.dag index a73e9100f2b..f168cb8cb62 100644 --- a/dag/gunbc/recurring_failure_mode/roster.dag +++ b/dag/gunbc/recurring_failure_mode/roster.dag @@ -135,6 +135,7 @@ import gunbc.recurring_failure_mode.witness_that_fails_to_compile_is_absent_rath import gunbc.recurring_failure_mode.instruction_and_subject_resolved_from_different_revisions { instruction_and_subject_resolved_from_different_revisions } import gunbc.recurring_failure_mode.reported_required_refusal_does_not_precondition_landing { reported_required_refusal_does_not_precondition_landing } import gunbc.recurring_failure_mode.corroboration_without_an_independent_derivation_axis { corroboration_without_an_independent_derivation_axis } +import gunbc.recurring_failure_mode.detector_promoted_to_an_actuator_predicate { detector_promoted_to_an_actuator_predicate } data recurring_failure_mode_roster: List = [ a_type_name_asserts_an_algebra_the_arithmetic_does_not_carry, @@ -261,4 +262,5 @@ data recurring_failure_mode_roster: List = [ instruction_and_subject_resolved_from_different_revisions, reported_required_refusal_does_not_precondition_landing, corroboration_without_an_independent_derivation_axis, + detector_promoted_to_an_actuator_predicate, ] diff --git a/docs/design-failure-modes.md b/docs/design-failure-modes.md index f826336a582..8c0436e2ec7 100644 --- a/docs/design-failure-modes.md +++ b/docs/design-failure-modes.md @@ -128,6 +128,7 @@ The exact `RecurringFailureMode.identity` population, which no other projection - `instruction_and_subject_resolved_from_different_revisions` - `reported_required_refusal_does_not_precondition_landing` - `corroboration_without_an_independent_derivation_axis` +- `detector_promoted_to_an_actuator_predicate` --- @@ -269,3 +270,4 @@ The landing measurement partitions the 31 parser-visible identities into **2 cit - **a step's INSTRUCTION and the TREE it operates on are resolved from different revisions** (INVALID STATE: the command a step runs -- which entry point, which function, which path -- is taken from revision A, while the working tree that command is pointed at is checked out at revision B, and nothing in the step binds the two or reports which is which. HARM: the step's refusal is REAL, typed and located, and it names a subject that never carried the instruction. Section 5's located diagnostic is intact and points at the wrong tree, so the repair it invites -- edit the module the error names -- is correct-looking and cannot work, because that module is not what disagreed. THIS IS NOT A STALE-BASE PROBLEM AND CALLING IT ONE SENDS THE FIX TO THE WRONG PLACE. Age of the base is neither necessary nor sufficient: a branch whose instruction and tree both come from the OLD revision is perfectly consistent and refuses nothing, and a branch that integrates the new revision is consistent again. What produces the failure is the SPLIT, and a step can hold it open at any base age. The reason it presents as staleness is that the split is invisible while the two revisions happen to agree, which is most of the time. **SPECIMEN, gunbc#10479, run 33926616205 job 101196425514 (2026-09-04).** The heal-generated-artifacts job refused with NoSuchFunction { name: heal_repair_declaration } while evaluating dag/gunbc/instruments/generated_artifact_gate.dag. The function and the invocation of it landed together in ONE commit, 865fddf03d (#10373) -- .dag definition and workflow argv in the same diff -- so the pair is atomic everywhere and no asymmetric merge resolution is involved. The split is the job's own construction: for a pull_request event GitHub supplies the WORKFLOW FILE from the merge ref, and this job declares ref: github.head_ref because it PUSHES the regeneration back to the branch and therefore cannot run detached on refs/pull/N/merge. Its checkout line reads git checkout --progress --force -B refs/remotes/origin/, not a merge ref. Measured at three revisions: branch head a86d7ed225 had definition 0 and invocation 0, a consistent OLD pair; origin/main had 1 and 1, a consistent NEW pair; what EXECUTED was the invocation from the merge ref against the definition from the branch head. git merge-base --is-ancestor 865fddf03d a86d7ed225 is false. Every other required job runs the merge ref and stayed green, which is why exactly one job reddened and why integrating main cleared it with nothing resolved by hand. **AND THE FIRST ACCOUNT OF THIS SPECIMEN WAS WRONG IN THE INSTRUCTIVE DIRECTION, which is why the population statement is written twice here.** It was first filed as any branch based before 865fddf03d will red this way -- a rule keyed on the BASE. A reviewer then established that both halves landed atomically and concluded the opposite, that a consistent old pair cannot refuse and so the cause must be an asymmetric merge resolution that took one side. Both readings check one ref and infer the other. The measurement that decides it is the checkout line in the job log, and neither account had read it. The population is: the branch HEAD predates the commit that added the invocation, AND the entry point is reached by a step that checks out the head rather than the merge ref -- narrower than base age in one direction, and broader than a bad merge resolution in the other. **SECOND SPECIMEN, gunbc#10490, AND IT IS A MATCHED PAIR RATHER THAN A SECOND SIGHTING.** Reached independently by another lane on a case neither party to the first diagnosis chose, and diagnosed correctly there before this row existed -- which is the evidence the roster is for: the class is recognisable in the wild, not only in retrospect. Re-measured here rather than accepted as reported. RED ARM, head c30c049f68: the definition is absent (git merge-base --is-ancestor 865fddf03d c30c049f68 is false), and on run 33930364431 heal-generated-artifacts failed while required-witnesses-build, required-witnesses-floor and the aggregator all succeeded -- one job red, and it is the one job whose ref differs from the workflow file it is running. GREEN ARM, head 5888fb0106 after integrating main: the definition is present. The property flips with the remedy, which makes the pair discriminating rather than illustrative, and per section 4b(4) it stays enrolled as the arm that would catch a regression in the eventual fix. ONE HONEST GAP IN THAT PAIR: at the time of writing, #10490 green run 33932538855 had not concluded, so the executed green arm is gunbc#10479 at 245416762b, where heal passed in 18m56s after exactly this remedy. Naming #10490 as an executed positive control before its run reports would be the unbacked-execution-claim failure inside the row that files a class about misattributed evidence. **SCOPE, STATED BECAUSE THE CLASS IS WRITTEN WIDER THAN ITS EVIDENCE.** The general shape is a step whose checkout ref differs from the ref that supplied the workflow file, and it is written at that grain deliberately: the next instance will be whichever step next needs to write back to the branch. But BOTH executed specimens are heal-generated-artifacts, which is the only such step in the required workflow today, so the evidence covers one job and the generalisation is reasoning. A reader deciding whether their own red is this class should check their step's ref: declaration, not assume the shape has been observed anywhere else. **DISTINCT FROM ITS THREE NEAREST NEIGHBOURS, and the repair law is what separates them.** upstream_carrier_substituted_for_the_consumer_selected_subject is about deriving a CLAIM about a consumer from a carrier the consumer transforms; there the defect is in a measurement and the repair is to measure the composed subject. Here nothing is measured -- the EXECUTOR pairs the two revisions itself, and the repair is in the step. verification_bound_to_the_revision_it_started_on is one tree MOVING across an interval; here the two revisions are fixed for the whole run and differ by construction, so waiting or re-running changes nothing. receipt_names_a_property_not_the_tree_it_holds_of is an expired GREEN that produces no signal at all; this class produces a loud, correctly typed RED whose subject attribution is false, which is a different failure to catch and a different one to trust. **RUNG: 1 (mitigatable).** The line stops, the diagnostic is typed and located, and the harm is bounded to a misattributed red plus the investigation it misdirects -- there is no silent wrongness here. **CEILING: 3 (structurally guaranteed), and not 4, for a stated reason:** which ref supplies a workflow file is GitHub's decision and sits outside the modeled guarantee, so no constructor of ours can make the two-ref pairing unwritable. What IS reachable is that a step cannot emit an unattributed refusal: the invocation is resolved against the tree the step checked out, and an entry that tree does not define refuses by naming BOTH revisions and classifying the cause as an instruction/subject split rather than as a defect in the module it names. **NEXT-RUNG TRIGGER, a capability and not an artifact: a step whose entry point is resolved from the revision it checked out, with the refusal carrying both revision identities.** What does NOT satisfy it: making this one job check out the merge ref, which it cannot do and still push; renaming or restoring the function; or adding a note telling readers to merge main, which is guidance rather than a mechanism. **RECOGNITION RULE: when a job refuses naming an entry point, function or path that is absent from the branch, ask which revision supplied the COMMAND and which supplied the TREE, and demand both as immutable shas.** The tell is that the refusal's own subject has no history on the branch at all -- git log -S on the branch is empty -- while git show : contains the invocation. Two refs, one of them never named in the error. - **a required check reaches a terminal refusal on the head and the same head is then landed by hand, so the check detects the invalid state without being a precondition of landing.** INVALID STATE: a committed emitted mirror differs from what its authority emits; the required comparator enumerates that mirror, observes the differing bytes, and reports failure before the merge, yet the merge completes. This is an admission failure after detection, not an inert or mis-scoped detector. HARM: hand-maintained projections reach main in either direction -- bytes the authority emits can disappear and bytes it does not emit can appear -- while every later branch inherits a red required lane. A separate actuator may repeatedly report green over its own population, making the repository look converged without touching the drifted mirrors. MEASURED SPECIMEN (gunbc#10273, merged as 5a12090e7a, 2026-09-04). The pull request hand-maintained two files in `v1_compiler.emitted_population`: it removed the 47-line rustc-judged `nested_refinement_cast_fixture_closure_discrimination` pair from `compiler_tests.rs` while emission still produced it, and added 39 lines to `std_measure.rs` that emission did not produce. The required build run 33908874519 executed `claim_executor --required-ci --required-lane build`, reported `planned=156 executed=156 adjudicated=156`, and at 19:17:52Z printed `required-ci: regen FAIL generated surface drift: compiler_tests.rs, std_measure.rs`; its aggregate required `witnesses` check concluded FAILURE at 19:30:00Z. The human merge occurred at 19:59:28Z. Thus a terminal refusal existed for twenty-nine minutes before landing. A second pull-request run was created at 19:59:46Z, after the merge, and is not the evidence this receipt rests on. THE SPECIMEN IS AN INSTANCE OF A MEASURED RATE, NOT AN OUTLIER. Reproduced on 2026-09-04 over the 25 most recently merged pull requests, all merged that same day: for each pull request, join its merged head SHA and `mergedAt` to that commit's check runs, retain `name == witnesses` with `completed_at < mergedAt`, and take the latest by completion time. The closed tally was 13 success, 9 failure, 3 undetermined, total 25. Thus 9 of 25 landed after a terminal red on that exact head, and 12 of 25 landed without an established green from this instrument. THE THREE ARE `undetermined`, NOT VIOLATIONS: no check named `witnesses` completed before their merge, but check names date a receipt and this census did not establish what an earlier roster called the executing check. The population is ONE DAY of merges and supports no extrapolation beyond those 25. The query was controlled first on gunbc#10273 and returned its known `failure` at 19:30:00Z; this matters because an earlier instrument passed an unsupported second `--arg` to `gh api --jq`, suppressed the resulting errors, and rendered every failure as an empty result. DISTINGUISHING FACTS. `compiler_tests.rs` and `std_measure.rs` are members of `v1_compiler.emitted_population`, whose required regen phase compared all 156 planned mirrors and named both paths. They are not members of the distinct `gunbc.generated_artifact` `generated_artifact_registry`: the heal run on the same head reported `HealNoChange`, while the required generated-artifact phase reported `rostered=38 adjudicated=38 matches=38 drifted=0`. Heal runs `tools.generated_artifact_gate` `main_wet` and stages that 38-artifact registry; it does not run or install the 156-mirror required-regen candidate. Its green was true of its own population and could not converge either file. THE CONTENT WITNESS IS NOT THE MIRROR GATE. `nested_refinement_cast_fixture_closure_discrimination` is `#[ignore]`, and cargo test is on no CI step, so no executing merge-path gate covered what the deleted test asserts. The required regen phase nevertheless covered the containing mirror byte-for-byte and went red. Saying the test did not execute therefore explains why its semantics were not independently exercised; it does not explain or weaken the detected mirror drift. DISTINCT FROM `head_landed_by_hand_before_its_own_verification_reported`: there the landing precedes the head's terminal verdict, so improving detector speed cannot help and the record cannot say whether a reported refusal would have blocked. Here the required verdict was terminal and red twenty-nine minutes before the landing. Waiting longer was impossible as a repair because the answer had already arrived. Distinct from `green_reported_over_a_population_the_instrument_does_not_own`: that row concerns a green being read beyond its denominator. Heal exhibits that neighbouring shape here, but the landing defect is established by the red comparator that did own both files. RECOGNITION RULE: join the required check's subject SHA, conclusion time and conclusion to the landing's subject SHA and merge time. If the same head has a terminal required refusal before `merged_at`, yet lands, the detector is neither absent, inert nor late; the landing path did not make its refusal a precondition. Then enumerate every actuator separately before asking why a later green did not repair the state -- shared words such as generated and regen do not make two populations one. RUNG FOUND AT: mitigatable for admission. The comparator mechanically exposed the mirror drift at rung 2, but this row's subject is the consumer of that refusal: admission did not prevent the landing, and repair depended on a later author noticing the red residual and installing a full candidate. A correct detector whose refusal has no accountable consumer is observation, not rung 2 prevention on the landing path. This subsumes the otherwise-separate class `gate_refusal_has_no_accountable_consumer`: the unconsumed refusal is the mechanism established here, so a second row would give one class two authorities. CEILING: outside the modeled guarantee on the human hosting-platform path, and structurally guaranteed on a landing path this repository constructs; the class takes the weaker boundary honestly. The repository can model a landing whose accepted constructor requires a terminal success for the exact ref, but a person pressing the hosting platform's merge control is an external boundary until that path is removed or made to consume the modeled decision. Calling the existing required context a structural guarantee would contradict the specimen: its refusal was present and the external action still occurred. NEXT-RUNG TRIGGER, the same capability already named by `gunbc.guarantee_stall` `merge_admission_terminal_verdict_stall`: a landing path in which terminal SUCCESS for the exact ref that lands is a precondition, sufficient to refuse both absent evidence and an observed FAILURE, human actor included; until that exists, a landing observation that joins every merged head to the terminal verdict present at its merge instant and reports this class explicitly. Adding another comparator, widening heal, or speeding the existing run does not discharge it: the owned comparator already returned the right answer in time.) - **corroboration without an independent derivation axis** (a second reader reaches the same conclusion as the first, and the agreement is counted as confirmation -- but both readings ran the same query over the same lexical projection of the same subject, so the second signature carries no information the first did not. TWO SIGNATURES, ONE EVIDENCE LINEAGE. What makes it dangerous is that it looks exactly like independent replication from the outside, and it is REPORTED as replication: the second reader honestly says they checked. Specimen, measured 2026-09-04 on gunbc: two sessions independently concluded that HTTP listing pagination was modelled in this tree. Both read `extdeps.github.github` `default_per_page` and the `per_page` fields that consume it, and both substituted PAGE SIZE for CONTINUATION CLOSURE. The tree in fact carried no page parameter, no cursor advance, no Link-header handling and no page fold anywhere, so every listing read in the repository was capped at its first page -- and `extdeps.github.github` declared a `Pagination` type with `per_page`, `cursor` and `has_next` fields that NOTHING consumed, which is a shape with no execution behind it. **THE THREE CLAIMS THE SUBJECT ACTUALLY CARRIED, and conflating them is the mechanism rather than an incidental error: page SIZE (how many items one request asks for), cursor SHAPE (how the next request is named), and continuation CLOSURE (whether the sequence of requests was consumed until the authority said there was no next).** Only the first appears lexically in a request declaration. The third appears nowhere unless a fold exists, so a lexical reading can only ever return evidence about the first, and both readings returned it. **Recognition rule: when a second reading agrees, ask which DERIVATION AXIS it changed.** If both readings are the same query over the same projection, the agreement is one observation reported twice. A reading corroborates only when it moves an axis -- operation-graph reachability rather than token presence, an EXECUTING transition rather than a declaration, or a controlled multi-page mutation rather than a read of the shape that would serve one. Any one of those was available and cheap here, and any one would have returned the truth on first contact. **Distinct from `authority_substitution`, where prose invents an A-to-B arrow that no carrier states:** here every sentence either reader wrote about `per_page` was TRUE, and the defect is that a true fact about claim one was accepted as an answer about claim three. Distinct from `bound_shaped_closure`, which is about a CONSUMER concluding a requirement is discharged because a real number satisfied it; this is about two readers' agreement being read as evidence when it is one reading counted twice. Distinct from `reachability_read_as_occupancy`: that class is one substitution made once, this class is the reason such a substitution SURVIVES review. **DISTINCT FROM `population_selector_that_cannot_admit_a_counterexample`, and the boundary is stated rather than assumed because the two rows were filed the same night off the same specimen.** That row is about how a POPULATION is enumerated: a lexical proxy for the predicate makes the verdict unfalsifiable by construction, and this corroboration failure appears there as a receipt explaining why nobody caught it. THIS row is about when a SECOND READING is evidence at all, and it fires with a perfectly well-formed population -- two readers can share one lineage while reading a log, a dashboard or a diff, where no enumeration is involved and no proxy was adopted. **THE DECIDABILITY SPLIT IS THE SHARPEST TELL THAT THEY ARE DIFFERENT OBJECTS RATHER THAN TWO NAMES FOR ONE.** Whether a population's enumerating expression shares a symbol with the predicate evaluated over it is a static question over the same Node graph a lens already reads, which is why that row's ceiling is 3 and its trigger is a constructor. Whether two agents' readings share an unstated premise is not a property of any artifact in the tree, which is why this row's ceiling is 1 and it has no trigger. A repair that closes either one leaves the other exactly where it stood. **RUNG FOUND AT: 1 (mitigatable)** -- the error was caught by a third reader who changed the axis, which is a person and not a mechanism. **CEILING: 1, and the reason is decidability rather than unbuilt work.** Whether two readings share an unstated premise is a property of how two agents derived a conclusion, not of any artifact in the tree; DESIGN section 5 names this the ratchet-forever case, and calling it mechanically preventable would be the `never` trap. What IS decidable, and was therefore repaired rather than rostered, is the specimen's own class: a truncated listing is unconstructible FOR ANY CONSUMER THAT READS THROUGH THE FOLD, because `std.page_fold` `PageFoldOutcome` carries the items only on the arm reached when the serving authority itself declared the listing closed, every other arm is a typed, located refusal carrying no partial result, and `PageFoldState` is `sole_constructor` so a closed-looking state cannot be forged to reach that arm without an authority that said the listing ended. **THE SCOPE OF THAT SENTENCE IS THE FOLD, NOT THE TREE, AND THE DIFFERENCE IS THE WHOLE REASON THIS ROW EXISTS.** No production listing operation consumes `std.page_fold` yet: the GitHub listing surfaces still expose only a page-size parameter, nothing imports `extdeps.github.pagination`, and `page_fold_live` is reached today only by its own witnesses. So every real listing read in this repository is STILL capped at its first page, and the repair to date is that the capability now exists and is executable rather than that any caller has been moved onto it. Writing this row as though the class were closed would be the same substitution the row is about -- a shape that exists read as a capability that runs -- committed by the very entry that names it. **THE REMAINING INTEGRATION OBLIGATION, stated so it can be checked rather than remembered:** one real paginated operation -- `extdeps.github.workflow_runs` `ListForRef` is the intended first -- must demand pages through `page_fold_live` and close on the authority's own Link-header end, with its own live-upstream witness. Until a production caller reads through the fold, the tree's truncation is mitigated by nothing at all; it is merely now REPAIRABLE without further modeling. That work is deliberately scoped out of the PR that landed this row, and this sentence is what makes its absence countable instead of forgotten. The `Pagination` type with no consumers was deleted in the same motion, since a declared shape with no execution behind it is the surface this class reads as capability. **NEXT-RUNG TRIGGER: none, and stating that honestly is the point** -- this row is a review-time recognition rule, and enumerating agreements more carefully does not retire it. What retires an INSTANCE is the axis change: name, before looking, what a second reading would have to execute for its agreement to mean anything.) +- **a correct detector is wired to a side effect that is only valid on a subset of what it detects** (INVALID STATE: a predicate that TRULY and COMPLETELY describes a condition is promoted to select the population an ACTUATOR runs over, without the additional clause that separates the members needing the action from the members for which the same condition is the CORRECT and HEALTHY state. The detection is not wrong at any point. The promotion is. **WHAT MAKES IT DANGEROUS IS AN ASYMMETRY BETWEEN READING AND ACTING, and it is the whole reason the classes must be kept apart: OBSERVING a member the predicate correctly returns costs nothing, and ACTING on it can be destructive.** So a predicate can be perfectly validated as a description and still be unsafe as a trigger, and no amount of confirming the DESCRIPTION discovers it. **THE RECOGNITION RULE, and it is checkable in one question before any code changes: WAS THE PREDICATE VALIDATED AGAINST THE SPECIMEN THAT PROMPTED IT, OR AGAINST THE POPULATION IT WILL ACT ON?** These are different sets and the second is the only one that matters. The prompting specimen is by construction a member needing the action -- that is why it prompted -- so it can never expose the healthy majority. Nobody asks a detector what ELSE it returns, because it was built from the one thing it was supposed to return. **SPECIMEN WITH A RECEIPT, 2026-09-04, gunbc CI sweep, and both halves are mine.** A fleet sweep for parked workflow runs filtered on `status == completed AND conclusion == action_required`. A peer found a THIRD parked shape that filter could not reach -- `conclusion == cancelled` with an empty job list on a live head -- and correctly diagnosed the cause: the population was selected by a CONTAINER FIELD, so it admitted only the shape already seen. That is `population_selector_that_cannot_admit_a_counterexample`, committed inside the sweep whose author had relayed that row hours earlier. The proposed repair was to drop the conclusion predicate and filter on TERMINAL AND ZERO JOBS, which is a true and complete description of the parked state. **AND IT WOULD HAVE BEEN CATASTROPHIC AS A TRIGGER.** Run at member grain over the last 100 runs it returns TWENTY-ONE hits across ELEVEN branches, all `conclusion=cancelled` -- and roughly twenty are SUPERSEDED HEADS, cancelled before scheduling because the author pushed again. Zero jobs is exactly CORRECT for those: the run was killed as obsolete. The branch clustering shows the healthy population is the BULK and not an edge -- four runs on one branch, three on another, two on a third. Rerunning them would resurrect dead heads, register checks against commits nobody is trying to land, and spend runner capacity in a queue already measured at eighty-plus minutes deep. **n=1 CONFIRMING, n=20 REFUTING, AND THE TWENTY WERE NEVER QUERIED.** **THE MISSING CLAUSE IS LIVENESS, AND IT IS A DISCRIMINATOR RATHER THAN A HEURISTIC: `terminal AND zero jobs AND head_sha == the CURRENT head of an OPEN pull request`.** A superseded run fails the third clause BY CONSTRUCTION -- being superseded is precisely what made its head stale -- so the clause separates the two populations structurally rather than by threshold or confidence. Detect at member grain; GATE THE ACTUATOR ON LIVENESS; then branch on the conclusion only to choose the instrument, since `approve` releases an existing run and `rerun` starts a new attempt. **THE CONTROL THAT MADE THE CORRECTED SWEEP'S ZERO READABLE, recorded because the sweep returned zero and a zero is the value a broken join also returns.** After adding the liveness clause the sweep found no parked runs on live heads. That zero was checked by running the head-matcher against a KNOWN-LIVE head -- the author's own open PR -- and confirming it returned one. Without that control the result is indistinguishable from a join that matches nothing, which is `absent_reads_identically_to_never_looked`. **A NEIGHBOURING DEFECT, NOT THIS ONE, FOUND IN THE SAME HOUR AND RECORDED HERE ONLY TO SEPARATE THEM.** The sweep's author had been reporting `the fleet is clear` all night. That was true of the population the filter owned -- no runs AWAITING APPROVAL -- and was stated as the wider claim, no PARKED runs. A summary is a predicate too, and it inherits the narrowness of the query beneath it while its WORDS name the wider set. THIS ROW IS NOT ITS AUTHORITY: there is no actuator and no side effect in a status summary, so the distinguishing fact below -- detection and actuation having different admissible populations -- does not obtain, and filing it here would widen this class past its own boundary and fork an authority that already exists. It belongs to `green_reported_over_a_population_the_instrument_does_not_own`, whose subject is exactly an instrument reporting over a population it does not own. Recorded as a neighbour because the two were discovered together and a later reader tracing this specimen should be sent there rather than back here. **THE BOUNDARIES, since three roster rows sit adjacent and none covers this.** `population_selector_that_cannot_admit_a_counterexample`: there the QUERY IS WRONG and cannot return the negative; here the query is RIGHT and returns the whole population faithfully. `repair_enumerates_its_own_blast_radius_by_inspection`: there a COUNT of affected sites is stated with no decidable search behind it; here the search is decidable, executed, and correct, and the count is not in dispute. `guard_precondition_discharged_by_the_route_that_uses_it`: there a check stops discriminating because its precondition moved; here nothing has moved and the check discriminates exactly as designed. `green_reported_over_a_population_the_instrument_does_not_own`: there a REPORT names a wider population than the query beneath it owns, with no effect anywhere in it; here the report is not at issue and the defect is an EFFECT admitted on the wrong population. The distinguishing fact for this row is that DETECTION AND ACTUATION HAVE DIFFERENT ADMISSIBLE POPULATIONS and one predicate was used for both. **RUNG: 1 (mitigatable)** -- caught by asking the recognition question before wiring a predicate to an effect. **CEILING: 4 (structurally impossible), AND THE ROUTE TO IT IS NOT A STATIC SHAPE TEST.** An earlier draft of this row justified its ceiling by saying the property is decidable from the modeled call graph -- whether a predicate reaching an effectful operation carries a clause the pure-observation path does not. That justification is withdrawn: it is SYNTACTIC, and an arbitrary or irrelevant conjunct satisfies it while preserving the invalid state exactly. A check satisfiable by editing the declaration while the realization still lies is the validation-standing-where-construction-was-available tell of DESIGN section 5, so the shape test establishes no rung above 2. What it can honestly do is ENUMERATE CANDIDATES -- effect paths carrying no additional clause at all -- which is a useful lens and not a wall. **NEXT-RUNG TRIGGER, the capability and not an artifact, stated so that satisfying it entails the guarantee.** The actuator must DECLARE ITS ADMISSIBLE POPULATION as a predicate over the member, and the effect constructor must require a witness produced by EVALUATING THAT DECLARED PREDICATE on the member being acted on -- so that a detection result has no constructor into the effect at all, and the promotion fails to construct rather than being caught by a reviewer who thought to ask. EXCLUSIVITY IS THE WHOLE OF IT AND EXCLUDING THE DETECTION RESULT ALONE IS NOT ENOUGH: a successful evaluation must be the ONLY constructor of the permit, so that a caller-authored receipt, a bare member, or a true boolean cannot inhabit it either. A permit type carries no safety property of its own -- the property lives entirely in an exclusive constructor that proves the actuator's declared policy over the EXACT subject acted upon, and any additional constructor silently returns the class to rung 1 while the type name still reads as coverage. Both halves are load-bearing and a trigger naming only the second is the grain mismatch section 4b(3) names as its own review tell: a receipt type whose constructor does not require that evaluation is vacuously inhabitable, claims admissibility that no constructor entails, and leaves the class exactly where it was while reading as coverage. The receipt must be grounded in the actuator's own policy or it is decoration, and this trigger is retired by nothing less.