Repository navigation
CI: required witnesses check builds only the compiler, on a hosted runner - #11742
Conversation
The required fold cost ~100 self-hosted runner-minutes per PR push (build lane ~30 min, floor ~47 min, heal ~26 min) on a ~45-runner fleet; queues reached 49 minutes and the merge queue stalled. On run 35462055101 the floor's 4,185 claims executed in 53 s; the rest was corpus preparation (14.3 min), reach probes (11 min) and bookkeeping. witnesses.yml is now emitted by the new gunbc.compiler_gate_workflow: one job, `witnesses` (the ruleset's required check), on ubuntu-24.04-arm, running `cargo build --release -p v1-compiler --bin gunbc`. Hosted runners join no ctrl-jobserver, so cancel-in-progress is on for pull_request runs; merge_group and heal revalidation keep their immutable concurrency groups. gunbc.witness_floor_workflow stays in the tree and is no longer emitted; the module header names the dissolve-on condition for switching back. Regenerated with generated_artifact_gate main_wet; `main` passes. witnesses.yml is the only generated artifact that changed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 331d80d926
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| uses: checkout_action, | ||
| with: Present { value: [kv(key: "persist-credentials", value: yaml_bool(b: false))] }, |
There was a problem hiding this comment.
Bind heal dispatches to the expected SHA
When a workflow_dispatch supplies expected_healed_sha, this checkout ignores that input and the new job also omits the former exact-head preflight. If the dispatched branch advances from H1 to H2 before GitHub resolves or checks out the run, the compiler can build H2 successfully while the concurrency group still identifies the run as heal-H1, creating a successful revalidation for the wrong commit. Preserve the checkout ref: ${{ inputs.expected_healed_sha || github.sha }} and verify both github.sha and the checked-out HEAD before building.
Useful? React with 👍 / 👎.
REVIEW WAS RIGHT: THE FIRST CUT DID NOT RESTORE THE GATE. The repository ruleset requires ONE status, `witnesses`. The clippy job published its own status beside it, so a green compiler lane and a red clippy lane still left the required status green and the pull request mergeable. That is an executing step with the wall still unbuilt -- the decoration DESIGN section 4b names, arriving one level up from a missing check, and it is exactly the defect the job was added to fix. `witnesses` is now the AGGREGATOR and the lanes run beneath it: compiler: the build lane, renamed from `witnesses` clippy: cargo clippy --all-targets -- -D warnings witnesses: needs [compiler, clippy], if: always() It reads each lane's own `needs.<lane>.result` rather than inferring one from its own success, and always() means a failed lane cannot skip the verdict. A lane that did not conclude `success` is a refusal, including skipped and cancelled: the step fails loudly on `failure` and separately on any non-success, because a RED lane and a lane that produced NO CONCLUSION are different facts and only the first is a statement about the diff. This is the shape the workflow carried before #11742 collapsed it to a single job. WHY NOT THE RULESET. Requiring a second status there would work, and it would put a merge-blocking fact outside the repository where the model can neither see it nor regenerate it. The aggregation keeps the gate derivable from the authority that emits the workflow. CLIPPY STILL RUNS EXACTLY ONCE. repo_self_clippy_command has one authority (gunbc.repo.repo_self_build) and, with this change, one executor: the clippy lane. gunbc.contributor_onboarding_path only NAMES the command, which is DESIGN section 6's "name the instrument, never transcribe its output", and no git hook invokes it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…cation THE FOLLOW-UP POPULATION. The census that types a `uses` row is a resolve of its module, and the population is not static while the cut is in flight: main gained rows after the measurement and every merge of main brought more. The 21 that arrived that way are declared in gunbc.plans.demand_restatement_follow_up with their commit range, each module carrying its own row count, and the D13 plan entry renders them -- so the roster has an executing consumer rather than sitting as a dangling row. Deleting them unmeasured is the fail-open this cut exists to avoid: an empty derived demand is exactly the row whose deletion flips its function from effectful to pure. THE RECEIPT. CI is build-only since #11742, so a green check executes no claims. docs/receipts/effects_1_cut_c_claim_invocation.sh is the scoped invocation for this head: every enrolled witness module the deletion touched plus every witness module that directly imports one, 83 entries and 1222 claims, derived from `git diff --name-only origin/main...HEAD` rather than hand-listed. Verified with `bash -n`; the per-entry --functions pairing is there because claim_batch refuses an --entry without one, which a first smoke run established. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…annot publish it WHY BY HAND. heal-generated-artifacts regenerates .github/workflows but CANNOT publish it: on head 36abd8f it reported success, logged `[file] write .github/workflows/fleet-converge.yml (89904 bytes)` in its own workspace, and emitted a repair-candidate manifest holding only .gitattributes and docs/design-rung-drops.md -- no workflow path, consistent with a GitHub App token being unable to push .github/workflows. Since #11742 removed the regen gate from PR CI, nothing detects this drift either, so the authoring PR must carry the bytes. Operator ruling (lively-wren-426, 2026-09-20): commit them, but DERIVE them, never type until it looks right. WHAT CHANGED AND WHY EACH FOLLOWS FROM THE .dag. Exactly two lines, the two `gunbc run` argvs the ci_spec targets own: org_actions_observe --entry dag/gunbc/fleet/org_actions_converge.dag --function org_actions_converge_wet -> --entry dag/gunbc/fleet/org_actions_inspection.dag --function org_actions_inspect_wet (gunbc.ci_spec gunbc_ci_org_actions_inspect_target) app_control_plane_observe --entry dag/gunbc/fleet/app_control_plane_converge.dag --function app_control_plane_converge_wet -> --entry dag/gunbc/fleet/app_control_plane_inspection.dag --function app_control_plane_inspect_wet (gunbc.ci_spec gunbc_ci_app_control_plane_inspect_invoke) Nothing else: the three remaining `org_actions_converge` mentions are the Secret Manager remedy prose naming org_admin_app_key_access_converge_with_supplied_token, whose module and function both still exist. CORROBORATION, NOT PROOF. main's current file is 89902 bytes and this branch matched it exactly before the edit; the four substitutions add 2 bytes, landing on 89904 -- the byte count heal independently produced from the same authority. A matching length could still hide a differing delta, so the real check is the heal run on this pushed head: if these bytes are right heal finds NO drift and regenerates nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ript THE PROJECTIONS ARE REGENERATED, not promised. reviews 68943 and 68967 both called this and both were right: a stated intent to regenerate is not the regeneration, and the committed markdown was a second, divergent answer while it stood. docs/design-rung-drops.md now carries the purity-gate drop row (tools.docs_projection_gate regen) and docs/plans/demand-engine-program.md carries the D13 follow-up bullet (generated_artifact_gate main_wet -- the plans projection has a different writer than the ledger one, which is why the first regen moved only one file). THE ROWS FIELD IS GONE. review 68967 caught my own argument closing on me: I declined the folded total because it had no consumer, which left the per-module count with no reader -- the same DESIGN 3c red one level down. Nothing here renders a number into markdown, so the roster is module paths and nothing else, and the next cut re-resolves each module to type its rows anyway, so it measures the counts rather than trusting a number carried from an earlier head. THE RECEIPT SCRIPT IS DELETED. review 68967 called it a hand-authored projection of an instrument's output, which it was; it stood only because the #11742 build-only gate left this PR owing a claim receipt by hand. #11791 put a real floor back on the PR path, so the PR's own floor run is that receipt and the transcription has no remaining purpose. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rge hazard Both come from bright-swift-259's handoff and existed only in that lane. The ensured provider-state directory emits install -d -m 0755, and install -d CHMODS an existing directory. If srv1's provider-state root is currently 0700 -- what a provider CLI would plausibly leave under a umask -- C8's first apply silently widens a credential directory to world-readable. Never verified against a host because no wet effects were permitted. The record now says to stat it first. The merge hazard produced a green CI run over a revision that had reverted 99 files of other lanes' work, including witnesses.yml to a pre-#11742 roster, which is the failure shape this program cares about. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…uses the lane (#11829) * Required gate: bind the receipt's adjudicator, so a refused floor refuses the lane The floor job of gunbc.compiler_gate_workflow ran claim_executor with --measurement-receipt and bound nothing that read the receipt back. Under that flag a completed measurement carrying blockers exits 0 -- the blockers are the receipt's content, and the verdict belongs to the D0-ADJUDICATE step that gunbc.witness_floor_workflow binds after the producer. The gate did not bind it, so a refused floor and a passed floor were indistinguishable at the job conclusion: PR #11821 run 35497139573 logged 'floor refused ... phases_run=2 phases_failed=2', evaluated no claim, and concluded success. A required lane that cannot go red is DESIGN section 5's fail-open arm, live on main since #11742. Repair (roadmap manager decision, option B): the floor job re-binds gunbc.witness_floor_workflow required_ci_measurement_bound_steps -- D0-MEASURE (seal an unreached receipt), D0-PUBLISH (upload it), D0-ADJUDICATE (read it back, exit 1 on any blocker) -- immediately after the run step, exactly where the floor authority binds them, so one receipt has one refusal mechanism (section 3). The alternative, dropping --measurement-receipt so the run step itself exits 1, was refused: it fuses a refused floor with a killed runner and loses the receipt. witnesses.yml regenerated from its authority (tools.generated_artifact_gate main_wet_one): 61 added lines, the three steps, nothing else. Wall: test.claim.compiler_gate_workflow_witness_test asserts over the emitted job's step positions that the adjudicator is bound after the producer, and over the emitted yml that it is present. Both were red on main before this change. Blast radius, stated plainly: every floor success between #11742/#11761 and this landing is unverified. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * File the failure-mode row for the class this PR repairs DESIGN 4b: every newly discovered error class files one row under dag/gunbc/recurring_failure_mode/. The class here is a required lane binding an instrument that RECORDS its verdict into a receipt and binding nothing that reads the receipt back, so a completed measurement carrying blockers concludes success. The row carries the two executed receipts (PR #11821 run 35497139573; merge_group run 35550476069 green over 'floor refused'), the sediment the darkness accumulated once the adjudicator could refuse, the boundaries against the two nearest rows (required_evidence_absent_reads_as_evidence_of_pass, where nothing reported; required_lane_green_over_a_population_it_never_offered, where the denominator is partial), and states the ceiling as structurally impossible with the capability trigger: a bound step naming an output artifact carries its adjudicating consumer in the same value. The claim landed in this PR is the rung 2 step, not the ceiling. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Drop the emitted-yml claim: the drift gate and the job claim already compose to it The claim over the emitted bytes re-rendered the whole workflow to read two substrings, and the floor adjudicated it at 97132 eval steps against the 72300 a new witness is allowed (the claim over the job costs 55109 and passes). The budget refusal is the tell rather than the rule that was broken: the cheap way to keep it was a 4b(3) drop, and DESIGN forbids buying reach with a debt row. It was also redundant. The drift gate establishes that the committed yml IS the projection of gunbc.compiler_gate_workflow, and the surviving claim establishes that the authority binds the adjudicator after its producer, so the bytes carry it by composition -- two facts with one home each, not one fact asserted twice. The deletion is recorded on the carrier with the measurement that forced it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…at judged it Manager ruling, 2026-09-22, from an incident: gunbc#11998's floor job concluded SUCCESS while its own log read `verdict=FloorRefused, phases_failed=1`. Not a flake and not a stale base -- the floor builds claim_executor from the CHECKED-OUT HEAD, and that head predates f5bd9b0 (gunbc#11829), which binds the adjudicator so a refusal reaches the job conclusion. gunbc#12050 carries the same witnesses plus that commit and fails. Same source, opposite verdicts, one commit between; #11829's own message states the blast radius as every floor success between #11742/#11761 and its landing. SO A SUBJECT TREE DOES NOT IDENTIFY A VERDICT, and this module is where that has consequences, because it is the one thing in the corpus that compares verdicts ACROSS TIME. Two drifts, and the provenance roles covered only the first: TREE DRIFT same adjudicator, different subject -- the three roles. GATE-SEMANTIC DRIFT same subject, different adjudicator -- nothing recorded it. `NativeVerdictAdjudication { authority, receipt_identity }` lands on the report AND on the baseline, because the bar and the run must be in the same meaning of green for a comparison to say anything. The receipt identity is Optional because an adjudicator that decided inline HAS no receipt -- a different fact from one whose receipt went unrecorded, and only the first is representable here. THE COMPARISON SHORT-CIRCUITS ACROSS A MEANING BOUNDARY rather than running and adding one finding beside its results. A per-identity regression computed against a bar from a different definition of green is not a weaker reading of the same fact, it is a reading of a different one, and emitting both would let a reader take the regressions at face value and treat the boundary as a footnote. The finding says NOT A BAR IN THE CURRENT MEANING. THE PAYOFF IS NOT THAT INCIDENT, it is the next gate strengthening: today the discriminator is "does the judged head contain f5bd9b0", which works and is unrememberable. With the adjudicator on the verdict, a strengthening makes older verdicts not-verdicts-in-the-current-meaning automatically, and nobody has to recall a commit hash (A3). ALSO IN THIS COMMIT, AND IT IS A CORRECTION TO MY OWN PROSE. The module cited `session/sharp-bear-756` at 6032d50 building the emitted crate clean as though this lane had measured it. It did not. I attempted the reproduction -- one remote dispatch over that tree -- and it reached `compile.normalize` before the runner's own deadline ended it, so the attempt is INCONCLUSIVE rather than negative. The figure is now cited to its author and labelled relayed, which is what `extdeps.external_authority` `CitedFigureStanding` asks of a figure this repository did not produce, and what DESIGN section 4d means by not promoting an inference for being useful. Nothing in the construction depends on which reading is right: they are two values of one field. 44 claims, twenty-seven authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…12049) * Pkg10 Tier 1: a required lane that emits the two retained v2 closures and builds them Nothing on the merge path emits a v2 closure and compiles the result. Every required lane reads the corpus through the interpreter or through the seed's own Rust, so a defect that is invisible under evaluation and fatal under emission reaches main green. That is not a hypothesis: gunbc.recurring_failure_mode bounded_natural_arithmetic_evaluated_as_unbounded_int records it in as many words ("their emitted Rust is produced by nothing on the merge path") and took out both retained native subjects at once, and it happened again on 2026-09-21 when #12004 pulled base16 into the closure and broke main's native self-host build with no required check noticing. This adds `emit-build`, a required lane on a GitHub-hosted arm runner that runs `gunbc test //gunbc/instruments:self-host` and `gunbc test //gunbc/instruments:v2-native-cli` -- one step each, so a regression names the compilation that broke. Both instruments already carry their own controls (the self-host row injects a type error into its own emitted module and requires cargo to fail alone on a diagnostic naming it; the CLI row pins the door's refusal arm), so this change adds no new control vocabulary, only execution on the acceptance path. WHAT IT IS NOT. It touches no line of gunbc.rung_drop v2_native_route_off_the_merge_path's declared population -- all five are route adjudication or execution of the derived v2.test.* universe -- so that row stays Standing and unnarrowed and its restoration trigger is untouched. The lane is named for emit-and-build rather than for the native route precisely so a reader meeting the green does not read it as coverage of the drop. Two defects found and closed on the way: - The aggregate's `needs` and the workflow's jobs list were two spellings of one fact. A job present in the workflow but absent from `needs` runs and cannot block. That join is now an emission conjunct: a workflow whose gate does not reach every lane is not emitted at all. Its RED is authorable at the fixture boundary, both directions, and the env/script half it does NOT cover is stated on the carrier rather than implied. - The aggregate hand-spelled `${{ needs.<id>.result }}` as string literals. `-` is subtraction in the Actions expression language, so a hyphenated lane id renders EMPTY and the gate refuses forever -- the failure #6f358d269b found and taught extdeps.github.expressions to avoid. All four lanes now render through that authority; the three dot-safe ones are byte-identical, which the regenerated witnesses.yml diff shows. Also recorded, because it cost real time: adding the single line `import extdeps.exec.command { ArgvCommand, argv_command }` to gunbc.cli_invoke, with no other change, makes gunbc.host_effect_realize fail to resolve at `no field 'verdict' on type 'U'` -- a module that edge does not touch. Bisected against main at f5bd9b064a. gunbc.gunbc_cli_command is the conforming home for the argv shape independently of that (it is gunbc.claim_executor_cli's shape, not cli_invoke's), but the finding is written on the carrier so the next author does not rediscover it. Evidence: 11 claims in test.claim.compiler_gate_emit_build_lane_witness_test all pass on this head; the generated-artifact gate reports no drift. The lane's wall on its real runner class is measured by this PR's own run and goes to the operator before the check is made required. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Pkg10 proper: the identity-grain progress guard for the native lane `native_route_admission` answers one question about one run and it is COMPLETE ON ONE HEAD: is this receipt well-formed, does its population join its universe, does every reached verdict agree with the floor. What it cannot see is the only thing a frontier lane exists to report -- whether the head in front of it can do LESS than the head behind it. That blindness is not theoretical. The emitted-native compiler refuses most of the universe today, and admission COUNTS those exclusions rather than refusing them, because a capability limit is not a divergence. So a change that makes the emitter refuse EARLIER for a subject it used to carry to `eval` produces a receipt admission accepts, and the lane goes green while the frontier moved backwards. A count cannot catch it either: exclusions rise here and fall there and the total is unchanged. The guard is at IDENTITY GRAIN, which is what DESIGN section 5 requires of a monotone debt contract, and all three of its conditions already held here: the universe is DERIVED from the tree's `v2.test.*` declarations rather than edited, `NativeRouteTestIdentity` is the identity with its own equality, and this change supplies the third -- every removal carries a typed disposition. Three things worth reading for: - SUBSTITUTION CANNOT SATISFY THE BASELINE, and it FALLS OUT of identity grain rather than being checked for. A renamed subject is a different identity, so the join never matches it and the old identity goes missing owing a disposition. A `SubjectRenamed` disposition is then checked hardest of the three: the target must be observed AND must itself attain at least what the original had, so a rewrite that quietly lowers the bar reds under its own name instead of passing as bookkeeping. - A DISPOSITION IS A CHECKABLE CLAIM, NOT AN EXEMPTION. An exemption cannot be falsified and decays into a list of things people stopped wanting to fix. Each arm here says something the run can contradict, and a deletion declared for a subject the run still discovered is refused. - PROGRESS PRESERVED IS NOT REQUESTED-TESTS-PASSED. The report carries both and the verdict reads only the second, so a head where five subjects newly pass and one regressed is RED with good news in it -- the encouraging number can never green the guard. Artifact-production failure is a finding of the guard rather than a precondition of it, so "the build broke, ignore the guard" is not a shape a reader learns. The three agreement arms deliberately collapse to ONE attainment band. They are different facts and admission must keep them apart, but ordering them against each other would mean claiming a subject moving from correctly-red to correctly-passing is progress on THIS axis -- it is the floor's reference that changed, not the emitted compiler's reach -- and a guard reading it that way would red the lane for a legitimate expected-red roster edit. CONSUMPTION. Nothing in production calls this fold yet and the module says so: it is a declared frontier under DESIGN section 3c with its named consumer (the Tier 2 native-lane job) and its trigger (the operator's cadence and coverage call, open on #12043) written on the carrier. The order and the join are cadence-independent, which is why they land ahead of that answer. No baseline is authored here either -- a baseline committed before a run that can produce one is a literal copied from nothing. Evidence: 22 claims in test.claim.native_route_progress_guard_witness_test, all passing, twelve of them authored REDs -- the earlier-refusal regression admission cannot see, the lost agreement, the undisposed removal, the contradicted disposition, the disposition with no baseline row, both rename failures, both artifact-production arms, the malformed reading, and the rising-agreement-count case that must not green a lost position. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Land the lane present and NOT blocking, with its standing declared rather than inferred from a missing edge Operator ruling (v2 foundation manager, 2026-09-22): the emitter's import gap is a real modeling change plus consumer adaptation, not close enough to stop the merge queue on, so `emit-build` lands PRESENT and NOT REQUIRED and flips required in a one-line follow-up once main's self-host builds. The straightforward way to do that is to leave the job out of the aggregate's `needs`, and it is wrong for the reason the previous commit's conjunct existed: a non-blocking standing inferrable from an ABSENCE makes a forgotten edge and a deliberate interim the same bytes. So the conjunct is not removed, it is strengthened into a roster where every non-aggregate job DECLARES whether it blocks: CompilerGateLaneStanding = LaneBlocks | LaneAnnouncedNotBlocking { flip_trigger } and `compiler_gate_standings_agree` refuses emission in four directions: a job with no row, a row for no job, a LaneBlocks that `needs` does not read, and a `needs` entry no row declares blocking. `needs` is now DERIVED from the blocking rows rather than listed. Flipping emit-build to required becomes one word on one row; forgetting to flip it leaves a row whose trigger anyone reading the roster can see, instead of an edge nobody can see is missing. The trigger is written as DESIGN section 4b(2) requires -- it names the CAPABILITY and what that capability must be sufficient for, not an artifact: a head of main on which both instrument labels exit zero, so that requiring the lane blocks merges only for defects the head in front of it introduced. It also records that the 12m33s from run 35686128136 is a RED run's wall and a lower bound, not the figure the required-lane decision turns on. `every_non_blocking_lane_names_what_would_flip_it` refuses a row whose trigger does not state what it is sufficient for, so an empty string cannot satisfy it. Also from review 69935 (APPROVE, no findings): dropped `emitted_subject_build_population`, whose only caller was the witness. The reviewer explicitly declined to file it; it is one line and a projection with no production consumer is DESIGN section 3c's red however small, so it goes and the claim derives from `emitted_subject_build_rows` directly. Evidence: 17 claims pass, six of them authored REDs, including `the_emit_build_lane_is_announced_and_does_not_block_yet` -- written so that the follow-up which flips the row must come here and say so, rather than leaving a stale claim asserting a standing the workflow no longer has. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review 69973: the roster joined `needs`, which gates nothing — so fold the whole gate from it instead THE FINDING IS CORRECT AND IT IS THE SHARP KIND: the previous head moved the fail-open one surface along and asserted it had been removed. `needs` is not what makes a lane block. The aggregate is `if: always()`, so a `needs` edge only ORDERS the job; the verdict is computed entirely from the hand-spelled env triple and the three shell conditionals beside it. Joining the standings roster against `needs` alone therefore left a THIRD spelling of "which lanes block" unjoined, and the diff conceded as much in its own refusal string. The scenario that row scheduled: the follow-up that flips `emit-build` to `LaneBlocks` adds the word and the `needs` edge, forgets the script clause, and gets a green `compiler_gate_lane_standings_hold`, a green emission, and a lane that still cannot block -- with the roster now ASSERTING that it does. That is rung inflation by the exact mechanism the header paragraph warned about, one surface in. THE REMEDY IS CONSTRUCTION, NOT A WIDER CHECK. `needs`, the env bindings, the echo line and every conditional are now FOLDED from `compiler_gate_lane_rows`, so a blocking lane without a variable, or a variable no clause reads, has no constructor. Two facts move onto the row to make that possible: `var_name` (a shell variable name and a job id are different namespaces -- `emit-build` is not a variable name -- so deriving one from the other means a mangling rule whose only consumer is this list), and `arm`, because the fleet lane's fork carve-out is a property OF THAT LANE and carrying it as a hand-written fourth line is what let the script drift from the roster in the first place. THE EMITTED GATE IS UNCHANGED EXCEPT FOR ONE IMPROVEMENT NOBODY ASKED FOR, which is the safety receipt for the refactor: the regenerated witnesses.yml differs in exactly one byte-range -- the failure message now also prints `floor=$FLOOR`, which the hand-written text TESTED in its condition and omitted from its report. Every conditional, the `!= success` comparison, the fork carve-out and the SAME_REPO expression are byte-identical. Five new claims read the surfaces that actually decide, since the ones over `needs` demonstrably could not: the env block binds exactly the blocking lanes plus SAME_REPO (exact count, so a stray binding reds as well as a missing one); every blocking lane is read by a conditional; the announced lane reaches NEITHER surface (its variable would render empty, compare unequal to success and refuse every run); only the fork-skippable lane carries the skip notice; and the unobserved arm still refuses every state but success, so the derivation did not quietly widen the guard that caught FLOOR="abandoned" on run 32883390033. 22 claims pass, seven of them authored REDs. The refusal string and the header paragraph that conceded the unchecked half are corrected rather than left to read as a standing debt that no longer exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review 69968: key the join and remove the copied accumulators, before the first run mints a baseline Both findings are correct and both are fixed. DESIGN section 6 makes the first unconditional -- "a proven cost-shape defect ... is ALWAYS fixed, regardless of the realized n" -- and the reviewer's timing point is the sharper one: this lands before the first real run, so there is no realized n to argue about and no baseline yet keyed on the old shape. THE JOIN IS KEYED, NOT SCANNED. `native_progress_observed_for` was a full linear scan of the observed population called once per baseline row, and the disposition fold re-walked ALL baseline rows plus the whole observed population per disposition. The baseline is one row per member of the derived `v2.test.*` universe, so both were O(n*m) over a corpus-sized population. Three one-pass `Map` indices (observed, dispositions, baseline) replace them, built once in `native_progress_report`. THE KEY IS THE EXISTING IDENTITY AUTHORITY AND NOT A SECOND ONE. `native_route_identity_qualified` is what the route already keys its subjects on, and the module now states WHY it is injective rather than assuming it: a module qualified name may carry dots but a declaration name may not, so the last dot always divides them. A key without a complete canonical preimage is the conformance-identity defect, and minting a second key beside the route's own would be the section 3 fork. THE ACCUMULATORS ARE REMOVED RATHER THAN MADE CHEAPER. `list_append(left: acc, right: ...)` inside a fold pays a full O(n) right-fold per step -- the measured trap `v2.std.algebra` `list_snoc_item` exists for. Rather than swap in `list_snoc_item`, the three fold-accumulators become `list_flat_map`, which deletes the accumulator instead of discounting it; the report's four-way nest becomes one flat_map over a list of lists. The two `list_append`s left are over fixed-arity pairs of small lists, not accumulators in a loop. The witness's dangling `fn id` and the two unused imports (`NativeDivergence`, `NativePassedExpectedRed`) are deleted, plus an `Optional` import the earlier Optional-constructor change had already made unused. 22 claims still pass, unchanged in count and in meaning: the repair is a cost-shape change with identical semantics, which is what the unchanged verdicts establish. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The pre-Context rungs, and the third verdict a two-state guard gets wrong Manager ruling, 2026-09-22, from a fact measured the same day: the route does not die at Prepare, it dies BEFORE the per-test stages exist. main at c4464fc75d9 with no diff refuses at the emitted cargo build with four E0425 in src/extdeps_numeric_base16.rs -- a rostered substrate class spanning seven-plus modules, not a missing import -- and gunbc#12043's emit-build lane reproduces it on every head it has run. THE MODEL AS WRITTEN COMMITTED THE CONFLATION THE RULING NAMES. Its lowest rung was `refused at prepare`, which presupposes a binary that ran. A run that never produced one yields an empty population, and an empty population made every baseline row read as "vanished, owing a disposition". That is loud, so it was not the silent form of the failure -- and it was the WRONG CAUSE, wrong in the direction that rots: it says the subjects went away when the truth is that nothing could look at them. WHAT LANDS: - NativeRunReach -- emission attempted -> source emitted -> emitted crate built -> executable started. A WHOLE-RUN fact, deliberately not per-identity: no subject has an individual answer to "did the crate build". - AttainUnreached, OFF the ordered ladder. It has no rank, and the missing rank is the point: giving it -1 would make every comparison answer "regressed" -- true- sounding, useless, and the same conflation one layer in. Its comparison guard is kept rather than assumed, because a total function quietly answering `false` would report a regression for a subject nothing looked at. - ProgressUnobserved as a THIRD verdict. It blocks -- a merge candidate that established nothing is not a pass -- and it is a different RED from ProgressLost because it sends a reader to the earlier rung rather than into a diff. This is not an arm waiting for a bad day: it is the state main is in right now, and a two-state verdict would report that as a corpus-wide regression. - NativeObservationProvenance and native_progress_baseline_advance. A measurement against a named stale tree is evidence worth KEEPING and must never advance the live ratchet (A3: a baseline advanced from a tree that no longer exists asserts a position no current head can be held to). Reading is not advancing, so a historical report still produces a verdict with its tree named; three typed refusals -- historical, unreached, progress-lost -- because they have different remedies. THE REACH IS A FIELD ON THE REPORT, NOT A CEILING IN THIS MODULE, and the manager's own correction an hour later is what tests that: session/sharp-bear-756 at 6032d50be7d builds the emitted crate clean (exit_status=0, warning_count=0 under RUSTFLAGS=-D warnings, wall 575s) while main still stops at the build. Two runs, two NativeRunReach values, one model -- no observation fabricated for main, no ceiling written down, and nothing here to edit on the day that branch lands. That was the stated test of whether the rungs are drawn in the right place. A GREEN EMITTED BUILD ESTABLISHES ReachCrateBuilt AND NOTHING ABOVE IT, said on the carrier because the temptation is immediate. Context, Prepare, Entry, Eval and Pass have produced no observations on any head, and a stage advances from what a run observed -- the same rule the provenance refusal enforces one paragraph down. Evidence: 32 claims pass, eighteen authored REDs. The ten new ones include the state main is actually in (unobserved, not lost), the per-identity unreached subject reading as unreached rather than regressed, and all four arms of the advance refusal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The third verdict fixed what the lane reports and left the findings still lying The reviewer of 5397b6d asked one question: is there a red for the case my own defect had -- a run that produced no binary, whose baseline rows must report unreached rather than missing? There was not, and the reason there was not is that THE DEFECT WAS STILL THERE. Making `ProgressUnobserved` a verdict arm fixed what the LANE reports. It left the FINDINGS untouched: with an empty population every baseline row still fell down the `Absent` path and came out as `BaselineMemberMissingUndisposed` -- "the subject vanished and owes a disposition" -- the exact misattribution that section exists to remove, surviving one layer in under a verdict that had stopped repeating it. `w_RED_a_run_that_died_at_the_emitted_build_is_unobserved_not_lost` PASSED THROUGHOUT, which is precisely why it could not catch this: it asserts the verdict, and the verdict was already right. THE REMEDY IS A SHORT-CIRCUIT, NOT A WIDER `Absent` ARM. Below the top rung there is no population to be absent FROM, so "is this subject missing" is not a question this run can be asked, and answering it at all is the defect. The disposition side short-circuits for the same reason and a sharper one: `DispositionContradictedByRun` asks whether the run still discovered the subject, and a run that discovered nothing would answer "uncontradicted" for every disposition -- an answer that looks like agreement and is ignorance. THE NEW RED ASSERTS THE FINDING KIND, not the verdict, and it is qualified by its own revert arm rather than by assertion: with the short-circuit replaced by `if false`, `w_RED_a_run_with_no_binary_reports_every_row_unreached_not_missing` FAILS, and with it restored it passes. It asserts the absence of any missing-subject finding and an exact count of two unreached ones, because a presence-only check would have passed over the bug in both directions. This is also the claim a later refactor is most likely to undo: short-circuiting below the top rung reads as a special case until you remember there is no population to be absent from. The comment on the carrier says that in as many words. 34 claims, twenty authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review 70018 and the three-role ruling: the rename arm, the rank the comment claimed, and branch evidence that may not raise the floor FOUR CORRECTIONS, and three of them are the same class -- a repair applied to one path and not its sibling, which is the shape this module keeps producing because its whole subject is not lying about what was observed. 1. THE RENAME ARM RE-COMMITTED THE MISATTRIBUTION THE LAST COMMIT REMOVED (review 70018). The direct path routes an unreached reading to its own finding; the rename path handed its target straight to `native_attainment_at_least`, which answers `false` for an unreached reading BY CONSTRUCTION -- so a rename whose target nothing could look at was reported as `RenameTargetBelowBaseline`, "the rename lowered the bar", when the truth is "nothing looked at it". The module's own annotation claimed unreached readings were routed before reaching the comparison, and on that path it was false. The new finding names the TARGET, not the original: the target is the identity the run failed to reach. 2. THE RANK WAS A PROPERTY OF A PARAGRAPH, NOT OF THE TYPE. The annotation said `AttainUnreached` has no rank; the function gave it 0, colliding exactly with a prepare-stage refusal. Nothing reached the collision, which is what makes it the kind of defect a later refactor inherits as a fact -- and a property stated only in prose is one nothing holds, since no Accepted program reads a comment. `native_attainment_rank` now returns `Optional<Int>` and every caller says what it does about the absence. 3. PROVENANCE IS THREE ROLES, NOT TWO (manager ruling). `LiveRunOnHead | HistoricalAgainstTree` is admitted-or-not, and it collapsed a distinction with teeth. A BRANCH observation and a STALE MAIN observation are both "not the current baseline" and are nothing else alike: the first was never main and can NEVER be refreshed into one, the second was main and is refreshed by re-measuring. The defect was live -- a branch run that preserved progress returned BaselineMayAdvance, letting one branch enforce a bar no merge candidate ever cleared against every other lane. session/sharp-bear-756 is exactly that case today: capability demonstrated, main unchanged. It is an ARM rather than a discard because it answers a question a baseline cannot -- is this possible right now -- and folding it into the historical arm would make its remedy "re-measure it", an errand that cannot finish. 4. THE JUDGED TREE AND ITS RELATION TO MAIN are now what the provenance arm IS, which is this module's answer to the standing rule that a report must state both. The relation is the arm; the sha is its field; a report that could not say which tree it judged could not choose an arm. The tree is the receipt's `tested_tree`, classified here rather than re-sourced. 40 claims, twenty-four authored REDs. The new ones assert FINDING KINDS and REFUSAL NAMES rather than verdicts, because in every case above the verdict was already right while the layer under it lied. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * A verdict is identified by the tree it judged AND the adjudication that judged it Manager ruling, 2026-09-22, from an incident: gunbc#11998's floor job concluded SUCCESS while its own log read `verdict=FloorRefused, phases_failed=1`. Not a flake and not a stale base -- the floor builds claim_executor from the CHECKED-OUT HEAD, and that head predates f5bd9b064a (gunbc#11829), which binds the adjudicator so a refusal reaches the job conclusion. gunbc#12050 carries the same witnesses plus that commit and fails. Same source, opposite verdicts, one commit between; #11829's own message states the blast radius as every floor success between #11742/#11761 and its landing. SO A SUBJECT TREE DOES NOT IDENTIFY A VERDICT, and this module is where that has consequences, because it is the one thing in the corpus that compares verdicts ACROSS TIME. Two drifts, and the provenance roles covered only the first: TREE DRIFT same adjudicator, different subject -- the three roles. GATE-SEMANTIC DRIFT same subject, different adjudicator -- nothing recorded it. `NativeVerdictAdjudication { authority, receipt_identity }` lands on the report AND on the baseline, because the bar and the run must be in the same meaning of green for a comparison to say anything. The receipt identity is Optional because an adjudicator that decided inline HAS no receipt -- a different fact from one whose receipt went unrecorded, and only the first is representable here. THE COMPARISON SHORT-CIRCUITS ACROSS A MEANING BOUNDARY rather than running and adding one finding beside its results. A per-identity regression computed against a bar from a different definition of green is not a weaker reading of the same fact, it is a reading of a different one, and emitting both would let a reader take the regressions at face value and treat the boundary as a footnote. The finding says NOT A BAR IN THE CURRENT MEANING. THE PAYOFF IS NOT THAT INCIDENT, it is the next gate strengthening: today the discriminator is "does the judged head contain f5bd9b064a", which works and is unrememberable. With the adjudicator on the verdict, a strengthening makes older verdicts not-verdicts-in-the-current-meaning automatically, and nobody has to recall a commit hash (A3). ALSO IN THIS COMMIT, AND IT IS A CORRECTION TO MY OWN PROSE. The module cited `session/sharp-bear-756` at 6032d50be7d building the emitted crate clean as though this lane had measured it. It did not. I attempted the reproduction -- one remote dispatch over that tree -- and it reached `compile.normalize` before the runner's own deadline ended it, so the attempt is INCONCLUSIVE rather than negative. The figure is now cited to its author and labelled relayed, which is what `extdeps.external_authority` `CitedFigureStanding` asks of a figure this repository did not produce, and what DESIGN section 4d means by not promoting an inference for being useful. Nothing in the construction depends on which reading is right: they are two values of one field. 44 claims, twenty-seven authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Two independent observations of the emitted build, at the strength they actually have The relayed reading stays relayed -- this lane still has not reproduced it -- but the evidence behind it is now stated properly rather than as one session's figure. TWO INDEPENDENT OBSERVATIONS on compositions including session/sharp-bear-756 at 6032d50be7d: that session's own (exit_status=0, warning_count=0 under RUSTFLAGS=-D warnings, self-host emit and build 575s), and gentle-bee-234's on a DIFFERENT composition including the same head (same clean build, 1361s, and further -- a discriminating cargo red and clean-root-versus-poison behaviour). This lane's attempt remains the third and is INCONCLUSIVE, not a contradiction: a single remote dispatch reached compile.normalize and was ended by the runner's own deadline. THE WALL SPREAD IS THE USEFUL PART AND IS NOW ON THE CARRIER. 575s versus 1361s for the same nominal work is the likely reason a deadline killed the third attempt, so the next person to try should budget for the upper figure rather than the headline one. That is a fact about reproducing the result, and it is exactly what a reader takes from a transcribed number and cannot take from a headline. AND THE READING IS SYMMETRIC, which is the half that is easy to get wrong in whichever direction one is already leaning: a third party timing out is not evidence against a result, and two independent builds are not evidence that it always builds. DESIGN section 4d asks for both arms -- do not assert as deduced what is inferred, and do not under-assert what the evidence supports -- and the standing stays CitedFigureStanding cited to its authors either way. Nothing in the construction moves. They remain two values of one field, which is the whole reason `reach` sits on the report rather than being a ceiling here. 44 claims unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review 70058: a bar is a different type from a reading, and a second consumer for the provenance identity TWO CHANGES, and the first is the fourth time this ladder has had to learn the same thing. 1. A BAR IS NOT A READING. `AttainUnreached` was representable on a baseline row, and the comparison answered `false` for an unreached BAR exactly as it once did for an unreached READING -- the misattribution already repaired twice, on the direct arm and on the rename arm, surviving on the third side. And it was reachable through the module's OWN INTENDED MINTING ROUTE: a run reaches the population, reports AttainUnreached for a subject not yet in the baseline, produces no finding (the row fold is driven by baseline.rows), verdicts preserved, is admitted to advance, and the consumer mints a baseline freezing an unreached bar -- after which every later run reports ProgressRegressed for that subject forever, against a bar of "nothing looked at it". THREE REPAIRS OF ONE SHAPE IS THE SIGNAL THAT THE SHAPE IS WRONG, so this is not a third guard clause. `NativeBaselineAttainment` has no unreached arm, so the invalid state has no constructor (DESIGN section 5). ONE LADDER still: `native_baseline_rank` is total and primary, and the observed rank derives from it through `native_observed_as_baseline` -- the one-way projection that is ALSO the minting gate, because "can this reading be a bar" and "what rank does this reading have" are the same question. The baseline side of the comparison no longer has a failure arm; there is nothing to ask. `native_progress_mint_baseline` is the only route from readings to rows, and it RETURNS what it could not take rather than dropping it: a subject silently missing from a new baseline is indistinguishable from one legitimately removed, which is the disposition question this module already spends a section on. 2. A FOURTH PROVENANCE ARM, FOR A SECOND CONSUMER REACHED FROM THE OPPOSITE END. gunbc#12009 met all three conjuncts of a rung-flip trigger HONESTLY, on a measurement composition -- a head plus two cherry-picked emitter files -- that will never exist as a landed tree. By the letter, compliant; landing it would have flipped a standing to LivePairRequired on a tree where the required observation is impossible. Their phrasing of the shared class is better than mine and is kept verbatim on the carrier: A VERDICT THAT IS ONLY MEANINGFUL RELATIVE TO A CONTEXT THE VERDICT DOES NOT CARRY. A BRANCH ARM DOES NOT COVER IT, which is the tempting fold: a branch head CAN land, so classifying an assembled tree as one asserts a future that will not happen, and a consumer checking "evidence composition equals landing composition" would be handed a tree it must reject as one it may accept. A tree sha does not distinguish the two; both hash. `native_observation_is_on_a_landable_tree` is deliberately a SECOND function rather than a reading of the advance result, because a stale main observation is landable and must not advance -- one question would conflate them. This also moves the provenance identity from one consumer to two independent ones reached from different directions, which is the difference DESIGN section 3c draws between a bet and a modelled fact. 52 claims, thirty authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review 70073 and the accept-to-refuse requirement: derive the discriminator, and stop scoring a removed fail-open as a fall TWO CHANGES. The first is a defect in the central claim of the previous commit; the second is a requirement that arrived from a consumer and would have made this ratchet score today's best change as today's worst regression. 1. THE DISCRIMINATOR WAS PRODUCER DILIGENCE WEARING CONSTRUCTION'S CLOTHES (review 70073). `native_adjudication_same` compared `authority`, a free-form String, while the prose one screen up promised that a gate strengthening makes older verdicts not-verdicts-in-the-current-meaning AUTOMATICALLY. It does not: a strengthening that leaves the spelling unchanged is the NORMAL case -- gunbc#11829 renamed nothing it strengthened -- and leaves `comparable` true, so the guard compares across two definitions of green and reports regressions at face value. DESIGN section 5's own tell, verbatim: satisfiable "by editing the declaration while the realization still lies". The witness proved the reviewer's point rather than mine: its red only fired because a person hand-typed `@ pre-f5bd9b064a` -- the commit hash the comment claimed nobody would need to recall. The comparison is now over `closure_identity`, a `Fnv1a64Structural` of the ADJUDICATING CLOSURE, which moves whether or not anyone renames anything. `authority` survives for a reader and is explicitly not the discriminator. `Fnv1a64Structural` rather than the `ContentHash` union for the reason `v2.std.node` `Hash` takes the same: cross-family comparison of that union is authorable until Phase B, and a discriminator whose job is exactness is the wrong place for a straddle. THE RUNG IS STATED HONESTLY: mechanically preventable, not structural. The residual is a producer hashing the wrong thing, which is now an ACTIVE mistake rather than the ordinary case. `receipt_identity` was dangling -- written at three sites, read at none -- and is now rendered on the boundary finding, where an absent receipt is itself informative. It is deliberately NOT in the discriminator: two runs under one adjudicator with different receipts are the same meaning of green, and folding the receipt in would make every run incomparable with every other. 2. AN ACCEPT-TO-REFUSE TRANSITION IS NOT AUTOMATICALLY A REGRESSION. gunbc#12009 deletes the global spelling search; on a 132-module closure that makes 106 resolve refusals APPEAR, and 81 of them reach a module that FILE-REFUSES -- the search was inventing answers around sixteen front-end defects, invisible for exactly as long as it existed. DESIGN section 4b puts silent wrongness BELOW the ladder entirely, so a fabricated acceptance becoming an ATTRIBUTED refusal has gone UP. The ladder alone reads it as a fall, and a ratchet that scored it that way would reward restoring the fail-open. So the arm is not "did anything fall" but "is every accept-to-refuse member ATTRIBUTED". Empty is the right answer for a bounded repair and is its done condition; non-empty is expected for an authority migration. The shape is recognised BEFORE any disposition is consulted and only this shape -- no fail-open removal turns an agreement into a divergence or a later stage into an earlier one -- and the roster is SEPARATE from the removal dispositions, because a removal says a subject is gone and this says a present subject's old bar was never real. Conflating them would let each excuse the other. Checked from its own side too: a transition claimed for a subject that did not make one is contradicted by the run. 58 claims, thirty-four authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review 70088: consume the canonical hash equality, and stop transcribing the instruments I name Both findings correct, and the second one has no excuse attached. 1. `native_adjudication_same` RE-MINTED `std.content_hash` `content_hash_eq_structural` -- from the module this one ALREADY IMPORTS FROM -- and did it by casting away the `lower_hex_16` refinement with `as String`, in the one function whose stated job two paragraphs up is to be exact and to refuse comparisons that straddle families. Section 2's test is that net concepts must not grow by re-invention; a hand-rolled compare that erases its operands' type is re-invention with a downgrade attached. Now one call to the authority. 2. TRANSCRIBED MEASUREMENTS IN THE ANNOTATIONS, which is the finding I should not have needed. DESIGN section 6 says it in the imperative -- name the instrument, never transcribe its output -- and I wrote paragraphs ABOUT citing instruments while copying nine of their numbers into the prose beside them: the route's wall and peak, the emit-build lane's wall, both self-host build walls and the spread between them, the emitted file count, the resolve-refusal counts and the file-refusing subset. Every instrument was already named correctly, which is what makes the numbers pure rot: gunbc#12043's `emit-build` lane, the drop row, `session/sharp-bear-756` at 6032d50be7d, gunbc#12009. Each is re-derivable by re-running the thing named, and a figure beside it decays the moment either end moves without anyone touching the other. Section 4c says the rest: no `Accepted` program can read an annotation, so the number was never evidence to begin with. THE QUALITATIVE READINGS SURVIVE INTACT, which is the test that this is a deletion and not a loss -- the route's wall does not fit the acceptance path; main stops at the emitted build; a clean build is reported on that branch head by two observers and not reproduced here; the two walls differ by more than a factor of two, so budget from the slower observer. Those are the facts a reader needs, and none of them required a figure. `NativeVerdictAdjudication` and the `CitedFigureStanding` reasoning are untouched; the reviewer agreed that shape is right, and it is about the STANDING of a figure rather than about carrying one. 58 claims unchanged, thirty-four authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * An identity's position is (rank, cause), and the ladder only ever carried the first Manager requirement, 2026-09-22. My carrier did NOT express this, and it was worse than a gap: the module was DISCARDING a cause it already held. `native_attainment_of_with_stage` pattern-matched `NativeExclusion { cause: _ }` and `NativeDivergence { cause: _ }` and threw both away. Carrying them is recovery, not new modelling, which is the tell that the coordinate belongs here. THE CASE. 47 modules move from `resolve_reason_ambiguous_symbol` to `resolve_reason_unbound_symbol`: same stage, same disposition, same verdict -- and the second is TRUE while the first was manufactured by a fallback searching unrelated modules. The consequence is a person's day: an author told to disambiguate names spends it on names; an author told the provider is missing walks upstream and finds the file that will not parse. A ratchet scoring on attainment alone reports those 47 as NO PROGRESS. THE GENERAL FORM, and taking it once rather than three times is why this lands whole: COMPARE THE PAYLOAD OF AN OUTCOME AT THE GRAIN THE SUBJECT CLAIMS, NOT ONLY ITS VARIANT. It bit this file in TWO places at once -- `AttainRefused` collapsed every fatal reason, and `AttainDiverged` collapsed all four divergence causes, so a subject moving between two kinds of divergence was invisible too. And it applies RECURSIVELY: `NativeRouteExclusionCause` is itself a variant whose payload is the reason symbol, which is the coordinate those 47 actually moved on -- both of them are `CompilerFrontierAttributed`, so a variant-grain comparison calls them identical. The comparison therefore keys on variant AND reason. A CAUSE TRANSITION NEEDS A DISPOSITION, for the same reason accept-to-refuse does: it can go either way and the ratchet cannot tell which without being told. `CauseRegressedUnderANewLabel` is an ARM of the disposition rather than the absence of one, and that is the part worth noticing -- DECLARING IT DOES NOT EXCUSE IT. The guard reds on it under its own name. An author who admits a cause regression gets a located red; an author who says nothing gets `CauseTransitionUndispositioned`. Neither passes, and the two send a reader somewhere different, which is why this is a disposition and not a boolean. Agreement carries no cause -- there is no diagnostic in a verdict that matched -- so an agreement-to-agreement pair has nothing to compare and is not a transition. This is the third requirement to arrive from a consumer rather than from the brief, after newly-refusing-as-regression and unreached-as-empty. All three are the same underlying error at different grains, and this was the subtlest: nothing about the identity changes at all except the cause it carries. 64 claims, thirty-seven authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The accept-to-refuse roster waived where the cause roster classifies Asked to check whether the older roster had the shape I had just argued for, and it did not. `native_progress_rank_comparison` read `Present { value: _ } => []` -- ANY declaration admitted. Both arms were excusing arms, so an author declaring `PriorAcceptanceWasNeverSound` over an acceptance that WAS sound got a silent pass. That is a disposition field working as an escape hatch with a vocabulary on it, which is the exact failure the rest of this module spends its length refusing. `AcceptanceWasSoundAndThisIsARegression` is the third arm and it is the one that makes the roster a classification: it exists so the honest thing can be SAID when a fall is a real fall, and SAYING IT DOES NOT EXCUSE IT. Declared gets a located red naming the regression; undeclared gets `AcceptToRefuseUndispositioned`. Neither passes, and the two send a reader somewhere different -- which is why this is a disposition and not a boolean, and is now the same shape both rosters take. WORTH RECORDING WHY IT WAS ASYMMETRIC: I built the cause-transition roster after arguing the classify-versus-waive distinction explicitly, and did not go back to the roster I had written an hour earlier under the same requirement. The distinction was available and unapplied to the neighbour, which is the same one-path-not-its-sibling shape this module has now corrected five times -- here in the review vocabulary rather than in the comparison logic. 65 claims, thirty-eight authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review 70109: my fix for review 70073 moved the defect out one layer instead of closing it TWO DANGLING DECLARATIONS, and the second is the sixth instance of the class I filed this hour -- with my own claimed fix as the specimen. 1. `native_attainment_is_unreached` had no call site anywhere in the tree. Every site that needs the question asks it through `native_observed_as_baseline`, which is the projection that also gates minting. Deleted rather than given a consumer: a second way to ask one question is the section 3 fork, and this one was the redundant way. 2. `native_progress_finding_text` had zero consumers, and it was the ONLY caller of `native_run_reach_text` and `native_adjudication_receipt_text` -- so the whole rendering subtree hung off a dangling root. THAT IS NOT BOOKKEEPING, because of what the annotation above it claimed. Review 70073 found `receipt_identity` written at three sites and read at none; I rendered it on the boundary finding and wrote that it now "REACHES THE OPERATOR". It reached nobody: the renderer had no consumer either. The defect MOVED OUT ONE LAYER under a paragraph asserting it had closed, which is exactly `a_rule_is_applied_at_the_site_that_prompted_it_and_not_its_sibling` -- filed an hour ago, on five specimens, and this is the sixth. The remedy is the one the reviewer named: the witness now EXECUTES the renderer and asserts the property the annotation claims. Four claims, over the rendered TEXT rather than the finding's presence -- the boundary line carries the receipt and both closure digests; an ABSENT receipt says "adjudicated inline" rather than rendering blank, because an adjudicator that decided inline has none and a reader sent looking for a file that does not exist is worse served than one told there is none; the unreached line names the rung the run stopped at; and a regression line locates its identity. THE ANNOTATION IS CORRECTED RATHER THAN QUIETLY LEFT. Its honest standing: the receipt is rendered, the rendering is executed by the witness, and NO OPERATOR SEES IT YET because nothing in production consumes this module at all -- the same declared-frontier standing as the fold, and no better. The section 3c block now names the rendering surface as part of the same consumer, because it named one only for the fold -- the section itself had the sibling-shaped gap it exists to prevent. 69 claims, forty authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review 70123: the annotation said "at equal rank" and the code compared causes on every advance `native_cause_unchanged` compares causes while DISCARDING the stage, and `native_progress_rank_comparison` invoked it on every non-falling reading rather than only equal-rank ones. So a subject that genuinely ADVANCES -- prepare-stage refusal to eval-stage refusal, which NECESSARILY carries a different cause because it refused somewhere else -- came out as `CauseTransitionUndispositioned`, whose rendered line reads "same stage, same verdict, different diagnostic". THAT SENTENCE IS FALSE ABOUT SUCH A RUN. The stage moved, which is the one thing the finding denies. Loud, located, and attributing the WRONG CAUSE -- this module's own repeatedly-repaired class, this time as prose-says-X-code-does-Y, with the annotation at the head of the function stating the intended semantics ("THE CAUSE COORDINATE OF A POSITION, COMPARED AT EQUAL RANK") that the code did not implement. An inert annotation is not a weaker wall than a check; it is a claim nothing holds (DESIGN section 4c). It also forced an author to file a `NativeCauseTransitionDisposition` for a pure stage advance, and all three of its arms are framed around a fixed rank -- so the vocabulary had no honest answer to offer, which is a second tell that the call site was wrong rather than the vocabulary incomplete. THE GATE IS RANK EQUALITY, and the reason it is the right boundary rather than a patch: a rank change ALREADY HAS ITS OWN ACCOUNTING -- an advance is admitted by the rank comparison, a fall is a regression or an attributed accept-to-refuse. The cause coordinate is the question asked of positions the rank cannot separate, which is exactly what "at equal rank" meant. TWO CLAIMS, because the gate can fail in both directions. A stage advance carrying a new cause now reports NOTHING; and a stage FALL carrying a new cause is still scored as a regression, which pins that the gate did not quietly absorb the falls it now skips the cause check on. The second is the one a careless version of this fix would break. 71 claims, forty-two authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review 70131: the one roster never checked from its own side was pre-authorising the next red THREE DISPOSITION ROSTERS, TWO CHECKED FROM THEIR OWN SIDE, ONE NOT. `cause_transitions` was only ever READ BY KEY LOOKUP, so a `CauseNowMoreTruthful` or `SameDefectRenamed` row for an identity whose cause did not move was never contradicted, persisted in the baseline, and SILENTLY PRE-AUTHORISED THE NEXT CAUSE CHANGE at that identity -- the guard returning no finding where it owed `CauseTransitionUndispositioned` or `CauseRegressedAtAFixedRank`. A PRE-DECLARED WAIVER OF A RED THIS MODULE EXISTS TO RAISE is DESIGN section 5's escape hatch -- "a toggle whose only effect is 'proceed as if the refusal had not fired'" -- and that section calls a diff landing one a hard reject. It is the worst-shaped defect this PR has carried, because it does not fail on the head that introduces the stale row; it fails on some later head, silently, at an identity someone already looked at once. EIGHTH INSTANCE OF THE CLASS, AND THE PUREST. The annotation on the accept-to-refuse checker states the rule VERBATIM -- "one claimed for a subject that did NOT go accept-to-refuse is contradicted by the run, and leaving it standing would pre-authorise a future fall nobody looked at" -- and the same sentence is true word for word of a cause-transition row. The rule was written down, in prose, immediately beside the code, and not applied to the roster added after it. That is the sharper form the manager named this morning: not a missing rule, a function narrower than a sentence someone already wrote. THE CHECK IS THE CONJUNCTION THE DISPOSITION CLAIMS -- the identity in the baseline, in the run, AT EQUAL RANK, carrying a DIFFERENT cause. Any one failing means the row describes something that did not happen. Three claims, because the own-side check fails in three directions: a row whose subject's cause did NOT move is contradicted; a row over a RANK CHANGE is contradicted, since the vocabulary's three arms all describe a fixed rank; and a genuine transition with its row is still ADMITTED, which is the control that stops the fix from being a blanket rejection. 74 claims, forty-five authored REDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Why
CI ground to a halt on 2026-09-19. Each PR push cost about 100 self-hosted runner-minutes:
heal: ~26 min, added todayThat was on a fleet of about 45 runners. Jobs queued for up to 49 minutes, and the merge queue stalled behind them.
On run 35462055101, the floor's 4,185 claims executed in 53 seconds. The other ~42 minutes went to:
Change
witnesses.ymlis now generated by a new module,gunbc.compiler_gate_workflow. It has one job,witnesses, which is the ruleset's required check:ubuntu-24.04-arm(GitHub-hosted, free for this public repo), so none of our fleet is used.cargo build --release -p v1-compiler --bin gunbc.cancel-in-progressis on forpull_requestonly. Hosted runners join no ctrl-jobserver, so a cancelled run leaks no permits (the reason the fold keeps cancelling off).merge_groupand heal revalidation keep their immutable groups.gunbc.witness_floor_workflowstays in the tree but no longer emits the workflow. The new module's header records the condition for switching back: the fold's preparation cost gets fixed.heal/heal-publishshould be disabled in the Actions UI (gh workflow disable heal.ymlandgh workflow disable heal-publish.yml). They add ~26 self-hosted minutes per push, andheal-publishhas failed on every run today withHostBudgetUnreadable.Verification
gunbcand rangenerated_artifact_gate main_wet.witnesses.ymlis the only generated artifact that changed (476 → ~75 lines).mainpasses.ubuntu-24.04-arminheal-publishruns.🤖 Generated with Claude Code