Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e1e381a
A receipt that expires before it finishes is a subject-surface defect
Sep 3, 2026
e1c6d38
Three files in the measured closure, not five in a directory
Sep 3, 2026
8d16294
Take the count out of the row entirely; name the instrument
Sep 3, 2026
832d6ba
Merge origin/main; drop two duplicate declarations main cannot resolve
Sep 3, 2026
1658cad
Merge remote-tracking branch 'origin/main' into session/snappy-koi-87…
Sep 3, 2026
35055a7
Merge remote-tracking branch 'origin/main' into session/snappy-koi-87…
Sep 3, 2026
39c8043
Re-file the row in split shape: one file, one roster entry
Sep 3, 2026
6e88621
Merge remote-tracking branch 'origin/main' into session/snappy-koi-87…
Sep 4, 2026
d54c25a
chore: regenerate drifted generated artifacts (ci auto-heal)
Sep 4, 2026
66a4405
Merge remote-tracking branch 'origin/main' into session/snappy-koi-87…
Sep 4, 2026
69ef45b
chore: regenerate drifted generated artifacts (ci auto-heal)
Sep 4, 2026
6d2f312
Merge remote-tracking branch 'origin/main' into session/snappy-koi-87…
Sep 4, 2026
c144a0f
chore: regenerate drifted generated artifacts (ci auto-heal)
Sep 4, 2026
d5331b3
Merge remote-tracking branch 'origin/main' into wip271
Sep 4, 2026
5cbb01f
chore: regenerate drifted generated artifacts (ci auto-heal)
Sep 4, 2026
eb8abd9
Merge origin/main: authorities merged, ledger projection left provisi…
Sep 4, 2026
6b2ce8d
chore: regenerate drifted generated artifacts (ci auto-heal)
Sep 4, 2026
025d057
Merge origin/main (lap 2): authorities merged, ledger projection left…
Sep 4, 2026
22fd5d0
chore: regenerate drifted generated artifacts (ci auto-heal)
Sep 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module gunbc.recurring_failure_mode.receipt_subject_surface_outlives_its_own_production_time

import std.types { NonEmptyStr }
import gunbc.recurring_failure_mode { RecurringFailureMode }

data receipt_subject_surface_outlives_its_own_production_time: RecurringFailureMode = RecurringFailureMode {
identity: "receipt_subject_surface_outlives_its_own_production_time" as NonEmptyStr,

receipts: [
"**a receipt whose validity is denominated in the RAW CONTENT of a high-traffic closure has an expected lifetime SHORTER THAN ITS PRODUCTION TIME, so the wall it feeds is unreachable in practice and is therefore never exercised** (INVALID STATE: an admission gate is pinned to a digest ranging over the closure CONTENT of many entries, and producing the evidence that satisfies it takes hours while the surface it ranges over is edited in minutes. Every dispatch is invalidated before it returns. Nothing is silently wrong -- the gate REFUSES correctly, every time -- and that is precisely the harm: A WALL THAT CAN NEVER BE SATISFIED IS INDISTINGUISHABLE, IN THE LEDGER, FROM A WALL THAT HOLDS, while contributing no evidence about the property it guards. Its RED is permanent and its GREEN is unreachable, so it stops discriminating. MEASURED, NOT IMAGINED: on gunbc#9725 the wet-lane receipt cost 2h31m to produce and was pinned to a semantic-subject digest over the closures of eighteen routed self-host entries plus the wet-route module. Between the dispatch tree and the first run that reached a verdict, files INSIDE that closure moved, landed by UNRELATED pull requests, none of them the receipt's own author, and A SINGLE AFTERNOON'S ARRIVALS WERE ALREADY SUFFICIENT. THE COUNT IS DELIBERATELY NOT CARRIED HERE, and its absence is part of the finding: the first attempt to state it was taken from a file-level diff, overstated, and was corrected against the measured closure WITHIN THE SAME EVENING, before this row had even landed -- a transcribed measurement is unreachable from the thing that produced it, so it rots while nobody touches either end. Worse, the severity moved OPPOSITE to the count: fewer arriving files means a SMALLER surface was already enough, so a reader anchored on the number would have read the correction as good news. NAME THE INSTRUMENT INSTEAD, and re-derive rather than quote: enumerate the closure with `v1_compiler.bin.claim_batch` `--print-entry-closure` over the routed entries -- a non-evaluating mode that prints the population the RESOLVER retained, not an import re-walk -- and intersect it against the files changed since the dispatch tree. Run it beside a positive control whose membership is known, because an empty intersection and a dead instrument print the same thing. The gate refused with `subject-mismatch axis=semantic-subject`, the run was otherwise clean at 3596 planned, 3596 executed, 0 claims failed and 0 unexpected failures, and the receipt was dead. WHY THE OBVIOUS REMEDIES ARE NOT REMEDIES, both of which were proposed and priced before being rejected: FREEZING the surface asks an entire fleet to stop touching the most-trafficked module in the repository for the duration of one receipt, which purchases one landing by spending every other lane's night -- and the surface is high-traffic FOR THE SAME REASON it is in every closure, so the two halves of the problem are one fact. WAITING FOR A QUIET PERIOD does not fix the mechanism, it lowers the arrival rate until a dispatch gets lucky, and getting lucky is not a property of the mechanism -- WAITING IS THE TREADMILL RUN SLOWER. And WAIVING the axis to land the artifact would admit it by disabling the property it exists to establish; where a NEIGHBOURING axis is already waived under a declared drop, that waiver was sound ONLY BECAUSE this axis still held, so waiving both leaves not a weakened guarantee but none. RECOGNITION RULE: for any gate pinned to a digest, compute two quantities and compare them -- the TIME TO PRODUCE the evidence, and the MEAN TIME BETWEEN EDITS to the surface the digest ranges over. If production time exceeds the edit interval, the gate is unreachable and every refusal it emits is a scheduling artefact rather than a finding about the subject. The tell is a refusal whose remedy is `re-run it and hope`, and a ledger that reads as a held wall while its green has never once been observed. THE ROOT IS THE SUBJECT SURFACE, NOT THE SCHEDULE: a digest that ranges over raw file bytes makes every edit inside the closure -- including edits that change no semantics, per DESIGN section 4c -- move the subject, so the lifetime is denominated in the WRONG UNIT. RUNG FOUND AT: mitigatable, and the mitigation is a freeze nobody can grant. CEILING: structurally guaranteed -- a subject computed from what the routed entries semantically depend on cannot be moved by an edit those entries do not depend on. NEXT-RUNG TRIGGER, a capability and not an artifact: a receipt subject that ranges over the SEMANTIC DEPENDENCE of the routed entries -- the annotation-erased projection of exactly the declarations they reach -- rather than over the bytes of every file in their closure, so that the surface shrinks to what the evidence is actually about and the expected lifetime exceeds the production time by construction. NOT satisfied by a faster dispatch, a quieter window, or a wider waiver, each of which leaves the denominator unchanged.)",
],

evidence: [],
}
6 changes: 6 additions & 0 deletions dag/gunbc/recurring_failure_mode/roster.dag
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ import gunbc.recurring_failure_mode.a_written_row_is_not_a_firing_mechanism { a_
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 }
import gunbc.recurring_failure_mode.receipt_subject_surface_outlives_its_own_production_time { receipt_subject_surface_outlives_its_own_production_time }
import gunbc.recurring_failure_mode.trigger_satisfied_before_the_row_was_written { trigger_satisfied_before_the_row_was_written }
import gunbc.recurring_failure_mode.summary_counters_aggregate_over_a_disposition_set_the_verdict_is_not_in { summary_counters_aggregate_over_a_disposition_set_the_verdict_is_not_in }
import gunbc.recurring_failure_mode.reachability_answered_is_consumed_as_protection_established { reachability_answered_is_consumed_as_protection_established }
import gunbc.recurring_failure_mode.by_name_evaluation_is_a_string_not_a_binding { by_name_evaluation_is_a_string_not_a_binding }
import gunbc.recurring_failure_mode.verification_bound_to_the_revision_it_started_on { verification_bound_to_the_revision_it_started_on }
Expand Down Expand Up @@ -222,6 +225,9 @@ data recurring_failure_mode_roster: List<RecurringFailureMode> = [
required_evidence_absent_reads_as_evidence_of_pass,
right_censored_cost_read_as_exact,
guard_precondition_discharged_by_the_route_that_uses_it,
receipt_subject_surface_outlives_its_own_production_time,
trigger_satisfied_before_the_row_was_written,
summary_counters_aggregate_over_a_disposition_set_the_verdict_is_not_in,
reachability_answered_is_consumed_as_protection_established,
by_name_evaluation_is_a_string_not_a_binding,
verification_bound_to_the_revision_it_started_on,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module gunbc.recurring_failure_mode.summary_counters_aggregate_over_a_disposition_set_the_verdict_is_not_in

import std.types { NonEmptyStr }
import gunbc.recurring_failure_mode { RecurringFailureMode }

data summary_counters_aggregate_over_a_disposition_set_the_verdict_is_not_in: RecurringFailureMode = RecurringFailureMode {
identity: "summary_counters_aggregate_over_a_disposition_set_the_verdict_is_not_in" as NonEmptyStr,

receipts: [
"**a refusal summary whose every counter reads clean, because the counters aggregate over a disposition set that does not contain the one that fired** (INVALID STATE: a run prints a terminal verdict beside a fixed set of counters, and the disposition that actually caused the refusal is not among them. Every number reads zero and the verdict reads REFUSED. The reader is handed a summary that is TRUE IN EVERY FIELD and answers a question adjacent to the one they asked, and the cause is on a different line that the summary does not point at. HARM, AND IT IS WORSE THAN FAILING TO EXPLAIN: the shape FORECLOSES the question. A refusal with four zeros beside it reads as a clean run that refused for no stated reason, which is the exact presentation most likely to be dismissed as flakiness and re-run -- and re-running until it passes is the laundering step that converts a real defect into an unrankable intermittency. A summary that said nothing would send the reader to the log; a summary that says zero four times tells them there is nothing to find. EVIDENCE, TWO INDEPENDENT INSTANCES IN ONE NIGHT ON TWO PULL REQUESTS WITH TWO DIFFERENT CAUSES: `required-floor: verdict=FloorRefused unexpected_failures=0 verdict_incomplete=0 non_verdict_unenrolled=0 stale_non_verdict=0` printed once above a wet-lane receipt subject-mismatch and once above a completed-over-cost refusal. Neither cause has a counter in that line; both were named on the line immediately preceding it. THE COUNTER THAT MOVED IS NOT MISSING FROM THE ARTIFACT -- IT IS IN A DIFFERENT LINE, and that is sharper than saying the cause is printed above the verdict. On a third instance the POPULATION line one row up carries `completed_over_cost_requirement=1` beside `claims_failed=0`, while the verdict line prints its own four zeros. So the verdict line is not silent and not wrong: it is a COMPLETE AND CORRECT SUMMARY OF THE WRONG POPULATION. That makes the class a SUBSET-SUMMARY rather than an omission, and it predicts the rest: ANY disposition outside the aggregation set produces the same four zeros. Two such dispositions are already known -- interrupted-before-verdict at the cpu deadline, and completed-over-cost-requirement -- so the set is under-inclusive in at least two directions rather than one, and the next arm will present identically. A RECEIPT FROM OUTSIDE CI, WHICH SHOWS THE SHAPE IS NOT A PROPERTY OF THIS ARTIFACT: a census column keyed on the interrupted arm counted 16 crossings of the cost line across 60 runs and was published; re-read over THE SAME 60 RUNS with both arms it is 22. The omitted arm was 16 runs ON ITS OWN -- the same size as the one counted, not a tail -- so a summary keyed to a proper subset of the dispositions can be wrong by ITS OWN MAGNITUDE while reading as a confident number. A FOURTH INSTANCE WITH NO SUMMARISATION STEP TO BLAME, WHICH IS WHY IT IS THE SHARPEST: comparing a branch to main by roster cardinality, both sides read 86 while the identity sets were DISJOINT BY ONE EACH WAY -- main carried a row the branch did not and the branch carried a row main did not. Equal totals, two rows apart, and a count comparison reads that as CONVERGED. Had the count been trusted the conclusion would have been that there was nothing to merge, and main's row would have been dropped on the next push with no conflict and nothing to look at. 86 IS NOT A WRONG NUMBER: it is a true statement about cardinality answering a question about membership, and the two coincide often enough that the exception lands exactly where it costs. Here there is no counter, no verdict line and no aggregation -- the whole failure is the substitution of a count for an identity join -- which shows the class is not a property of summary lines at all. THE RULE THAT COVERS ALL FOUR: compare identities, never any count, and compare them in BOTH directions, since a one-sided comparison cannot see what the other side has. THAT RULE IS DERIVED, NOT TALLIED, AND THE DERIVATION IS ONE LINE: WHENEVER TWO LANES EACH APPEND EXACTLY ONE ROW BETWEEN MERGES, THE CARDINALITIES AGREE BY CONSTRUCTION WHILE THE MEMBERSHIPS CANNOT. Count equality is therefore not weakest at the margin -- it is at its most confidently wrong exactly where it is most often reached for, and it carries information ONLY in the case nobody checks, when the two sides happen to append different amounts. A reader who takes away a warning to be careful with counts has taken the weaker statement; the instrument is not to be used on this question at all. THE THREE OCCURRENCES SEEN WHILE WRITING THIS ROW -- one branch at 86, 93 and 94 against main, each with one identity on each side the other lacked, twice on the pull request carrying this very row -- ARE ILLUSTRATIONS AND ARE EXPLICITLY NOT EVIDENCE FOR THE DERIVATION. The derivation PREDICTS them, and a tally a hypothesis predicts cannot also confirm it; counting them as confirmations would be this row's own class committed one level up, in the row that exists to condemn it. They are recorded because they show what the state LOOKS like to someone in the middle of a merge, not because three is a number that establishes anything. RECOGNITION RULE: WHEN A VERDICT IS A REFUSAL AND EVERY COUNTER BESIDE IT IS ZERO, THE COUNTER SET IS INCOMPLETE -- read it as evidence about the summary's coverage, never as evidence about the run. A partition that cannot represent the outcome that occurred is not reporting a clean run; it is reporting that it has nothing to say. THE GENERALISATION, WHICH THREE LANES REACHED SEPARATELY THE SAME NIGHT BY THREE DIFFERENT ROUTES: a key that names ONE ARM of a multi-armed disposition returns a confident, plausible, WRONG NEGATIVE for every case in the other arm. A census column keyed on the interrupted arm, a filter keyed on the deadline that raised it, and a counter keyed on one refusal class each answered cleanly and each missed the sibling arm. THE TELL IS NOT THE VALUE'S MAGNITUDE -- IT IS THAT THE KEY NAMES ONE ARM OF SOMETHING THAT HAS TWO. Ask what the OTHER arm is called before trusting a zero. THE SAME BOUNDARY APPEARS ONE LAYER DOWN, AND IT IS WHY TIGHTENING A NUMBER IS NEVER THE REPAIR. Offered a mechanical discriminator between the two arms -- an interrupted claim's `eval_steps` being pinned to a multiple of the 4096-step budget poll interval -- and measured over `required_floor_claim_cost.tsv` for one run's 3588 rows, it holds at sensitivity 9/9 and specificity 3578/3579. THAT ONE FALSE POSITIVE IS THE WHOLE ARGUMENT. A rule wrong once in 3579 is a HEURISTIC, and DESIGN section 5 forbids dressing a heuristic as a wall, so it may serve as a FORENSIC TELL for reading runs that already happened -- labelled with its measured error rate -- and may never be a check anything gates on. Set the two side by side: the verdict line is a CORRECT SUMMARY OF THE WRONG POPULATION; the step-count rule is a CORRECT RULE OVER THE WRONG GUARANTEE. Both read confidently, both are very nearly right, and NEITHER CAN BE MADE SAFE BY IMPROVING THE NUMBER -- only by changing what is asked. The repair is the same in both places and it is structural: make the two populations DIFFERENT CONSTRUCTORS, so no consumer has to infer which one a row is and no summary can aggregate over a set that omits one. RUNG FOUND AT: mitigatable, and the mitigation is that a reader happens to look one line up. CEILING: structurally impossible -- a summary derived from the SAME closed disposition coproduct the verdict is drawn from cannot omit an arm, because an unrepresented arm has no constructor. NEXT-RUNG TRIGGER, a capability and not an artifact: the summary line is projected from the terminal disposition's own exhaustive match rather than assembled from a hand-chosen list of counters, so adding a refusal arm without adding its counter fails to compile. NOT satisfied by adding the two missing counters, which repairs the instances and leaves every future arm exposed in exactly the same way.)",
],

evidence: [],
}
Loading
Loading