Repository navigation
Install boundary: the planned/executed conjunct was x == x.clone(); give it a second producer - #10005
Conversation
…ive it a second producer admit_stage_execution_from_model built ONE identity list from the stage plan and passed it as both the planned and the executed field of RegenStageExecutionObservation, so the model conjunct regen_identity_population_eq evaluated x == x.clone() on every install of the self-host convergence transaction. The conjunct ran, the install boundary really blocked, and StagePlannedExecutedMismatch stayed authorable in the .dag witness while being unreachable from the real acceptance path -- DESIGN section 4b rung inflation, and the class DESIGN already rosters as executed_conjunct_discriminates_nothing. The repair is a second PRODUCER, never a second read of the first: ObservedEffectPopulation is a digest delta over the journalled generated roster, taken before the copy loop and again after the build. Its denominator is the roster, not the plan. It is a newtype with no conversion from the plan, so the two sides cannot re-collapse without deleting a type. Discriminating RED, both directions, because one-directional identity checking is how this hid: an effect on a path OUTSIDE the plan (green before -- allowed_after blanket-permits every already-dirty stage0 path for the rest of the transaction), and a planned surface the stage left byte-identical (refused before, but as InstalledDigestMismatch -- a content verdict standing in for a population one, so the arm asserts the cause). Stage 1 of the same test is the accepted positive control. Mutation control: rebuilding executed from planned reddens exactly the new test and nothing else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2171VCXrmcBnp6o4A8CzF
# Conflicts: # docs/design-ledgers.md
# Conflicts: # docs/design-ledgers.md
…d to all three producers review 58476 is right and the declared boundary in the first commit was FALSE. It said a build that CREATES a generated file outside checkpoint_basenames is covered by UnplannedPathMutated. git_changed_stage0_paths runs `git diff --name-only`, which reports tracked modifications and says nothing about untracked files -- so such a path was absent from the roster lookup, absent from git, and absent from the restoration journal. Three producers blind at once. observe_generated_population_state now ENUMERATES the directory with the roster as a floor, over every top-level regular file rather than the .rs generated ones: a build has no business writing into stage0_src, and a basename resolving to no declaring module refuses as SurfaceOwnershipUnresolved. Files that merely exist unchanged never reach that lookup, so the hand-maintained population costs nothing and a build MUTATING one refuses whether or not git tracks it. Arm C of the RED is the reviewer's specimen: the build writes an untracked fixture_created.rs. Mutation control -- reverting to the roster-only lookup makes that stage return Ok, i.e. GREEN on a file invented by the build -- and exactly that one test reds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2171VCXrmcBnp6o4A8CzF
|
review 58476, blocking finding — accepted and fixed in You are right, and the declared boundary I wrote was false rather than merely narrow.
Arm C of the RED is your specimen: the build writes an untracked Advisory on seed-Rust expansion — declining, with the reason. Two corrections to my own earlier claims, since both would be believed if left standing:
— sent from quick-bee-68 |
…lled arm to one word The GHA runner reported "stage execution admission Refused" for a stage that must refuse as StagePlannedExecutedMismatch. I cannot tell from that string which arm answered or which surfaces disagreed, because the host binding rendered the model's label and discarded everything else -- diagnostic_name_mechanism_silent: the refusal is typed, its type is announced, and its located detail never reaches the caller. §5 asks for a typed AND located diagnostic; only the first half was being carried. regen_stage_execution_admission_detail renders the populations for a mismatch, the digest pair for InstalledDigestMismatch, and the reason for a build refusal; the host appends it to the error. A detail that itself refuses is reported inline rather than dropped, since a silent renderer here would rebuild the silence it repairs. Two .dag witnesses: the mismatch renders both populations, and an admitted stage renders the empty string so the renderer cannot be satisfied by returning text unconditionally. This is not a fix for the CI red -- the cause is still unknown, and that is the point: the next run says which arm answered instead of leaving me to guess. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2171VCXrmcBnp6o4A8CzF
|
review 58543, the You are correct that a fixed literal on Writing a richer default would not repair it — it would make the widen more plausible, which is I am doing that in PR 2 rather than here, and the reason is not deferral. PR 2 adds refusal Recorded so it cannot be lost: the On your second note — agreed, — sent from quick-bee-68 |
…refusal type so no `_` arm survives (#10035) * Join the admitted population to the lineage, and narrow the refusal type so no `_` arm survives THE DENOMINATOR LOSS. A stage receipt denominated in the population that REACHED it, so a surface admitted at the boundary and dropped before planning appeared in no receipt at all -- not planned, not deferred, not refused. Transaction success proved the narrowed set was handled and never that the admitted set survived. Three joins, every one an IDENTITY join with its residues named separately, because a count accepts a member missing from one side standing against a phantom on the other: 1. producer changed == planned UNION deferred, both directions, plus the disjointness a union cannot see -- a surface in both lists is one surface claiming to be handled and postponed at once, and a union absorbs it silently. 2. planned == independently observed effects (landed in #10005). 3. admitted-across-the-transaction == terminal lineage, both directions, AND every row terminal. DEFERRED IS NONTERMINAL, which is the whole reason the disposition is a coproduct. A generic `Excluded` merges "we decided not to" with "we never saw it" -- both render as absence. Applied, Superseded and Refused end a lineage; Deferred does not, so a transaction whose lineage ends in a promise refuses instead of reporting a fixed point it never reached. THE LINEAGE IS BUILT FROM THE STAGE RECEIPTS, NEVER FROM THE ADMITTED LIST. Deriving it from the admitted population would make `admitted_without_lineage` empty by construction -- the same x == x.clone() shape #10005 removed, one level up. THE REFUSAL TYPE NOW EQUALS THE PRODUCER'S RANGE. `RegenStageExecutionRefused` carried the whole ~25-variant `RegenConvergenceRefusal` while `regen_admit_stage_execution` can return three, so both renderers needed a `_` arm -- a new variant would render a fixed string with no location and nothing would refuse. Narrowing to `RegenStageExecutionRefusal` DELETES the arm rather than improving its default: a fourth refusal fails to compile in both renderers. It already worked once here, catching the fixture producer during this change. Evidence: 9 .dag witnesses and one host test asserting each refusal's own name and residues, with positive controls -- an exact partition admits, and Applied+Superseded closes a lineage that was never installed, so a join that refused everything cannot pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2171VCXrmcBnp6o4A8CzF * Narrow the population refusal too: the wildcard came back in the type this change added review 58572: RegenPopulationAdmission carried the whole ~25-variant RegenConvergenceRefusal while its two producers return three, so both new renderers needed a `_` arm -- rebuilding, in the change that removes the hazard from stage execution, the same silent-degradation surface. RegenPopulationRefusal now holds exactly those three and both renderers are exhaustive. The variants live there and nowhere else: no consumer outside the joins produces one, so a copy in RegenConvergenceRefusal would be a second authority for one meaning. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2171VCXrmcBnp6o4A8CzF --------- Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The defect
v1.stage0.required_regen_hostadmit_stage_execution_from_modelbuilt one identity listfrom the stage plan and passed it as both the
plannedand theexecutedfield ofRegenStageExecutionObservation:So
v2.workflow.regen_convergence_transactionregen_identity_population_eqevaluatedx == x.clone()on every install of the self-host convergence transaction. The conjunct ran, theinstall boundary really blocked, and
StagePlannedExecutedMismatchwas authorable inv2.test.claim.regen_convergence_transaction_witness_testwhile being unreachable from thereal acceptance path — the split DESIGN §4b's authorable-RED rule exists to catch, and the
class the roster already carries as
executed_conjunct_discriminates_nothing.The repair: a second producer, not a second read
ObservedEffectPopulationis a digest delta over the seed source directory — pre-stage statetaken before the copy loop, post-stage state taken after the build. Its denominator is the
directory, not the plan. The checkpoint already journals this population, so this is a repoint
rather than a build: no new producer, no new walk.
What structurally prevents the two sides re-collapsing (not "a reviewer will notice"):
admit_stage_execution_from_modelnow takesplanned: &[RegenConvergenceSurfaceReceipt]andexecuted: &ObservedEffectPopulation. They are different types, and there is no conversion fromthe former to the latter —
from_stage_deltais the only constructor and it takes two directoryobservations and never the plan. Re-collapsing them requires deleting a type.
The observation enumerates, it does not look up — and the boundary sentence in the first commit
was WRONG, not merely narrow. It asserted coverage that did not exist: that a file the build
creates outside
checkpoint_basenameswas covered by theUnplannedPathMutatedgitobservation. An asserted coverage is worse than a declared gap, because a declared gap ranks for
fixing and an asserted one gets cited. The assertion was false:
git_changed_stage0_pathsrunsgit diff --name-only, which reports tracked modifications and says nothing about untrackedfiles, so such a path was absent from the roster lookup, absent from git, and absent from the
restoration journal — three producers blind at once (review 58476). Both halves now walk the
directory with the roster as a floor, over every top-level regular file: a build has no business
writing into
stage0_src, and a basename that resolves to no declaring module refuses asSurfaceOwnershipUnresolved. Files that merely exist unchanged never reach that lookup, so thehand-maintained population costs nothing and a build mutating one refuses whether or not git
tracks it.
Evidence
stage_execution_joins_the_plan_to_independently_observed_effects, three arms, becauseone-directional identity checking is how this hid:
when stage 2 begins and lands in
changed_before;allowed_afterischanged_before∪ theplanned paths, so
UnplannedPathMutatedcannot see stage 2's build rewriting it. Everyalready-dirty stage0 path is blanket-permitted for the rest of the transaction. This was
green before.
InstalledDigestMismatch— a content verdict standing in for a population one — so the armasserts the cause, not that it refused.
fixture_created.rs, untracked, invisible togit diff --name-only. Reverting to the roster-only lookup makes this stage returnOk—green on a file invented by the build.
stage is admitted. Without it a join that refused everything would satisfy every arm.
executedfromplannedreddens exactly this test and nothing else (
4 passed; 1 failed); so does reverting thedirectory enumeration to a roster lookup. That is the delete-arm half of the roster row's
remedy, run twice.
Model side:
regen_stage_execution_admission_labelgains aStagePlannedExecutedMismatcharm(the host error previously said only "Refused"), with two new
.dagwitnesses covering eachdirection.
Ledger: a second specimen appended to
gunbc.recurring_failure_modeexecuted_conjunct_discriminates_nothing— the existing row covers this class, so this is areceipt rather than a new row, and it carries the recognition rule this specimen adds: the delete
arm is not what found it; the producer count is.
docs/design-ledgers.mdregenerated throughmain_wet_one; the diff againstmainis that one row.v1 seed freeze:
required_regen_host.rsis hand-maintained seed, admitted under the PURPOSEtest (
gunbc.v1_maintenance_standing) — this is a safety repair to the transaction that installsthe self-host generations, so it serves the v2 self-host program directly.
Rung honesty: this RED does not gate the merge
Determined positively, not inferred.
.github/workflows/witnesses.yml: the required aggregate jobwitnessesdeclaresneeds: [required-witnesses-build, required-witnesses-floor]. The step thatruns
cargo test --release -p v1-compiler --liblives in therust-unit-testsjob, which isnot among those
needs— matching what DESIGN.md already says about that job ("runs on everypush and pull request but is not yet a
needsof the required aggregate").So the executed evidence exists and runs on every push, but no required run gates on it. Per
§4b(1)+(2) the honest rung for this class is mitigatable, not mechanically preventable: rung 2
depends on the mechanism executing and staying enrolled, and this one is not enrolled in a
blocking lane. Next-rung trigger — the capability, not an artifact:
rust-unit-testsbecoming aneedsof the required aggregate, which that job's own authority names as a one-row edit gated onits measured wall clock. That is a CI-composition change with its own declared drop and does not
belong in a safety repair.
Checks
cargo test --release -p v1-compiler --lib regen_convergence— 5 passed, remotely, withCTRL_BUILD_FORWARD_ENV="GUNBC_MEMORY_BUDGET_BYTES"(dispatch printedforwarding env: GUNBC_MEMORY_BUDGET_BYTES). Correcting an earlier note in this PR: theBuildBuddy
HostBudgetUnreadablerefusal is an env-forwarding gap, not a platform limit —GUNBC_*is deliberately not forwarded by default, which is exactly the condition that makesthe budget unreadable there. This family is remotely runnable. Also 5 passed locally.
cargo clippy --all-targets -- -D warnings— clean (remote).cargo fmt --all --check— clean.Note on the re-run of
required-witnesses-buildThat job failed at step 4, Install Rust toolchain, before any repo Rust is compiled:
error: $HOME differs from euid-obtained home directory: you may be using sudo— rustup refusingbecause the runner's isolated
$RUNNER_TEMPhome does not match the euid's/home/ghrunner.Nothing in this diff can reach that step.
Re-running is legitimate here on two conditions, and both are stated because a reviewer cannot
otherwise tell a diagnosed re-run from a green bought by retrying:
last 25
witnesses.ymlruns the same step failed on ten distinct branches from ~06:04Z, andjoining
runner_nameto that step's conclusion gives srv1 12 fail / 5 pass, srv2-03 1 fail,srv3 3-for-3 success. A per-slot misconfiguration, which is also why a re-run lands green — it
draws a different slot.
7e6e76fof this branchcompleted this workflow successfully at 05:26Z, before the onset.
witnesses.ymlis deliberately not patched: it is generated fromgunbc.witness_floor_workflow,the isolation step is correct, and working around a broken slot from inside a safety repair would
bury a gating change in a diff nobody is reviewing for gating. The slot fault is an operator action
on the fleet and has been escalated as one.
Not in this PR
This is the first of two. The denominator loss proper — the admitted population never joined to
the terminal lineage, and a generic "excluded" conflating "we decided not to" with "we never saw
it" — lands next as a typed
Applied | Deferred | Superseded | Refuseddisposition withDeferrednonterminal. This one is separable and was the part that was lying rather than merelyincomplete.
🤖 Generated with Claude Code
https://claude.ai/code/session_01G2171VCXrmcBnp6o4A8CzF