Skip to content

The stage0 exclusion list was not the suppressor: required-regen measured main.rs's divergence and threw it away - #8704

Merged
briansrls merged 3 commits into
mainfrom
session/quiet-owl-897
Aug 21, 2026
Merged

briansrls merged 3 commits into
mainfrom
session/quiet-owl-897

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

The finding under the finding

HAND_MAINTAINED_STAGE0_FILES was not the thing suppressing the drift. verify_hand_maintained in required_regen_host.rs already computed committed-vs-emitted for every entry, and the divergent branch was an empty block:

if committed_norm != candidate_norm {
    // drift expected on clean tree for some hand files; not a sync refusal.
}

The measurement existed and was discarded. That is the absorbing fallback (DESIGN §5) in its authoring form: a real divergence between the authority and the committed artifact produced no typed, located, countable output, so its frequency was zero by construction and it could never rank for repair. The list was doing its legitimate job — keeping the flat committed walk and the candidate-tree copy working — while membership silently doubled as permission to diverge.

What was measured, by execution

Instrument is spelling-independent — it does not grep for a banner, it asks compile_stage0()'s own emitted map. Local release claim_executor --required-regen --source-root dag --source-root src/v2, all 36 entries printed:

disposition count members
emitted and divergent 1 main.rs
emitted and identical 0 —
not emitted at all 35 everything else

Three grep-based routes had answered 1, 2 and 4. Only one file is in the emitter's population; the other bannered files carry banners from other actuators, which is a different question. The 36 − 35 = 1 arithmetic route (smart-otter-309, from the #8696 emitted-population manifest) was right, and direct execution agrees with it.

What main.rs's divergence actually is

1318 committed lines vs 552 emitted. emit_main_rs (src/v1/05_emit_rust.dag) produces a generic workflow-function dispatcher; the emitted form omits the Ci, Converge and Serve subcommands entirely, along with compile's --entry. Installing the emitter's output would delete the CLI. This is not formatting drift and no number of regenerations closes it.

The change

Not two lists. The .dag authority already types why each row is excluded (intrinsic / scaffold / wet-actuator); the defect was that the taxonomy had no member for the one real case, so main sat in SeedRetainedIntrinsicRegistration — a type that asserts hand-authored source with no .dag authority, which is false of a file the emitter emits. The false family is what made the divergence unobservable.

  1. New family EmitterProducedDivergentRegistration { basename, reason, restoration_trigger } in v2.compiler.self_host.stage0_crate_layout. main moves into it. A declared §4b rung drop: rung mitigatable, ceiling structural impossibility (the file is decidable and fully modelled — the end state is that the emitter produces the committed bytes and this family is empty, not that a check reports the gap), bounded population = 1, per-row reason and trigger.

  2. hand_maintained_stage0_filenames() stays the union. Splitting it would drop main.rs out of copy_hand_maintained_support, so the candidate tree would carry the 552-line main.rs and no longer build — a destructive remedy offered to whoever hits the refusal. The split that matters is the second projection, EMITTER_PRODUCED_DIVERGENT_STAGE0_FILES, which names the divergent population so it can be counted and enforced.

  3. The empty if becomes fail-closed in three directions, which is what makes the population shrinkable rather than a quieter snapshot. Membership is not permission:

    • divergent and declared → counted and named on every run (declared_divergent=1 [main.rs])
    • divergent and not declared → FAIL (a new suppression cannot be added by editing the exclusion list)
    • identical and declared → FAIL (the rung drop has dissolved; the row must be deleted)
    • not produced and declared → FAIL (a row cannot outlive the producer whose output it excuses)

    The third arm is what makes each row's restoration trigger executable rather than prose.

  4. v1_interpreter_dispatch_generated.rs moved from the scaffold family to the wet-actuator family, where its actual producer lives (dag/gunbc/v1_interpreter_dispatch_emit.dag, named by its own banner). Byte-neutral for the pub-mod block. The scaffold note's stale count ("six" against eight rows) corrected to the live seven.

Evidence

Green by execution, shipped tree, exit=0:

required-regen: elapsed_ms=412060 first_generation_equal=true planned=128 executed=128 declared_divergent=1 [main.rs]

Discriminating RED — the wall was mutated, not just the witness. One run with all three new arms provoked simultaneously (undeclare main.rs; declare v1_compiler_artifact.rs, which is emitted and identical; declare cli_run.rs, which is not emitted). exit=1, each arm firing on the right file with the right cause:

declared_divergent=0 []
FAIL refusal: main.rs is excluded from the generated-surface comparison but the emitter produces it
     and its output DIVERGES ... and it is not declared in EMITTER_PRODUCED_DIVERGENT_STAGE0_FILES ...
FAIL refusal: v1_compiler_artifact.rs is declared ... but the emitter's output now MATCHES the
     committed file. The rung drop has dissolved: delete its row ...
FAIL refusal: cli_run.rs is declared ... but is absent from the emitted population, so there is
     nothing for the declaration to excuse ...

Mutation reverted, binary rebuilt, green re-measured on the exact shipped tree (above).

The generated artifacts were regenerated, not hand-written. main_wet derived EMITTER_PRODUCED_DIVERGENT_STAGE0_FILES byte-identically to the const written by hand to break the build's chicken-and-egg, and the two-generation gunbc_stage0_crate_layout_generated.rs drift was installed from the candidate tree and re-verified.

On the self-exclusion objection (deep-ant-102), checked rather than absorbed

bootstrap_stage0_crate_layout_generated.rs declares the exclusion list and appears on it, which reads as the exclusion mechanism closed over its own output. It is not a blind spot, and I verified the mechanism rather than its enrolment. It is a wet-actuator artifact, measured NOT-EMITTED — compile_stage0() structurally never produces it, so the regen comparator is not a mechanism that could ever check it. Its convergence is the generated-artifact drift gate's question, and that gate does cover it: Stage0CrateLayoutGeneratedRsArtifact is a row in gunbc.generated_artifact, and planting drift in the file makes the gate name it by path, while the clean tree is silent.

Recorded, deliberately not folded in

  • std_lens_verdict.rs — disposition UNDETERMINED, and I first reported this wrongly. I wrote it up as an orphan whose producer is gone. That claim was made over the wrong search space and is withdrawn: dag/std/lens_verdict.dag does not exist, but src/v2/std/lens_verdict.dag does, declaring module v2.std.lens_verdict (caught by wise-boar-649). The absence was real; the conclusion did not follow, and the two readings have opposite remedies — deleting an artifact whose producer merely moved would destroy a live mirror.

    What is established: the banner names std.lens_verdict; no dag/std/lens_verdict.dag exists; src/v2/std/lens_verdict.dag exists; compile_stage0() does not emit the mirror (it appears in the candidate tree only because copy_hand_maintained_support copies it in after the emit). One further fact narrows it and points away from a clean delete: the live module's lens_verdict_home_note says the LensVerdictDiagnostic/LensVerdictLocus fork "is dissolved (W1.2)", while the committed mirror still declares pub struct LensVerdictDiagnostic. So the mirror predates the W1.2 regrounding onto v2.std.diagnostic regardless of which module is the naming authority. Which authority owns it, and whether the mirror should be re-derived or deleted, is a decision I do not hold; routed, not absorbed.

  • The literal first_generation_equal: false written by regen_refusal_outcome for a value nothing measured (smart-ram-730 / deep-ant-102) — same file, different subject, separate PR to follow.

  • The 8 nested hand-maintained files. Datapoint from this work: --required-regen on a clean tree at this commit ran to exit 0 twice; that refusal did not reproduce here.

Credit

The finding is smart-otter-309's, from two directions — the emitter banner on main.rs, and the 36 − 35 = 1 arithmetic off the emitted-population manifest in #8696. Reframing from "the list suppresses" to "the measurement is discarded", and the constraint that the split must not make the comparison destructively red, came from wise-boar-649.

CI status — one failure fixed, one blocked on a pre-existing defect this PR did not cause

Fixed here. scaffold_generated_artifact_layout_overlap_repo_paths_is_exactly_v1_interpreter_dispatch is a list equality, so it asserts derived order as well as membership; the wet-actuator family move puts v1_interpreter_dispatch_generated after bootstrap instead of before it. Order updated rather than relaxed to a set comparison — the ordering is derived and deterministic, so the equality catches strictly more. Verified locally with claim_batch, together with the two neighbours reading the same overlap list.

Blocked, and not worked around. The receipt phase refuses both authorities this PR touches:

behavioral-receipt: v2.compiler.self_host.stage0_crate_layout REFUSED — the emit produced no
bootstrap_stage0_crate_layout_generated.rs, so there is no candidate to compare

The phase selects an authority when an emitted mirror's header names it, then takes the candidate from emitted_generated_sources() — compile_stage0()'s population. For a wet-actuator artifact those two rules disagree by construction: the header names the authority, and compile_stage0() structurally never emits the file. So the phase reds for any change to such an authority.

Pre-existing, established two independent ways that agree. From the code: MirrorIndex on origin/main documents that it learned the second header key (// Authority:) specifically so these two mirrors would stop being invisible to selection — correct for its own purpose, and it is what made them selectable while leaving them unsatisfiable (wise-boar-649). Empirically: on a detached worktree at clean origin/main, adding one comment line to stage0_crate_layout.dag and running claim_executor --behavioral-receipt-plan reproduces the identical refusal at exit=1.

The fix — a typed INAPPLICABLE disposition separating "this mirror is outside compile_stage0's population" from "compile_stage0 should have produced it and did not" — is deliberately not in this PR. It edits a required CI gate, it weakens a refusal arm, and writing it to turn my own PR green is the author-side absorbing fallback §5 names. It is routed to the lane already holding a sibling defect in the same phase (a module with zero declared functions, selected, deriving nothing, refusing — the same shape from the derivation side), because those are very likely one vocabulary and two authors adding two members to it separately is the fork that gets consolidated later at cost.

Main cannot be the baseline for this phase — it never runs there

Recorded because two readers have now proposed "compare against main's last green run", and that test cannot return an answer. On main the merge base resolves to HEAD, so the phase has no diff to observe and reports its own SKIPPED state (measured on main run 32475483128 at 7d3fec269a4):

behavioral-receipt: merge_base=7d3fec269a4 head=7d3fec269a4
required-ci: phase receipt SKIPPED — the merge base resolves to HEAD ... so this run has no diff
to observe. Not a pass over an empty selection: the subject is absent, not agreed

Main is green on this phase because the phase does not execute there. The receipt phase only ever runs on PRs — which is precisely how a defect that reds every PR touching one class of authority can persist without main ever noticing. Use the local repro below instead.

Also: bootstrap_stage0_crate_layout_generated.rs did not change sides in this PR

It is in HAND_MAINTAINED_STAGE0_FILES at the base (1ebac31a099, line 41) and at the head (fa82dacf9c8, line 39). Only its position moved, because v1_interpreter_dispatch_generated was reordered ahead of it. It was already a wet-actuator artifact that compile_stage0() structurally never emits — that is what the family means — so nothing here changed whether it is emitted.

This PR trips both arms of the receipt-phase defect

Worth noting for whoever fixes it, because the two are usually discussed as separate lanes and one PR reaches both:

v2.compiler.self_host.stage0_crate_layout  -> missing candidate (wet-actuator mirror)
gunbc.stage0_crate_layout_generated        -> fn_lines=0, nothing derived (zero-function class)

The receipt phase is testable without a CI round

Worth more than the finding above, and recorded so the next person does not rediscover it. The phase runs locally in minutes against any tree:

git worktree add --detach /tmp/probe origin/main
cd /tmp/probe && <edit one authority> && git commit -am probe
<path-to>/target/release/claim_executor --behavioral-receipt-plan --source-root dag --source-root src/v2

It diffs the worktree HEAD against its merge base, so a one-line commit is enough to select an authority. That is how pre-existence was established here at 1ebac31a099 without spending a CI round.

…measured and thrown away

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title Split HAND_MAINTAINED_STAGE0_FILES: main.rs is claimed hand-maintained AND emitted, and the list is suppressing that drift with no counter The stage0 exclusion list was not the suppressor: required-regen measured main.rs's divergence and threw it away Aug 21, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 21, 2026 01:17
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

CI at fa82dac (run 32438980975): failed=2 → failed=1.

The floor failure was mine and is closed — required-floor: planned=9849 executed=9849 terminal=9849 passed=9542 known_red_held=206 **failed=0**. The witness that asserted the overlap list's derived order now matches the wet-actuator family move.

The one remaining failure is FAILED PHASE receipt, which is not this PR's and is routed elsewhere by ruling. It reds for any change to a wet-actuator-mirrored authority, because the phase selects on the mirror's // Authority: header while taking the candidate from compile_stage0()'s population — two producers, one question. Reproduced on clean origin/main at 1ebac31a099 by adding a single comment line to stage0_crate_layout.dag and running claim_executor --behavioral-receipt-plan: identical refusal, exit=1. Details and the local repro recipe are in the PR body.

I am deliberately not fixing it here: it edits a required CI gate and weakens a refusal arm, and writing it to turn my own PR green is the author-side absorbing fallback §5 names. It is routed to the lane already holding a sibling defect in the same phase (a module with zero declared functions, selected, deriving nothing, refusing — the same shape from the derivation side), because those are very likely one vocabulary.

— sent from quiet-owl-897

@briansrls
briansrls merged commit 645be6a into main Aug 21, 2026
1 check passed
@briansrls
briansrls deleted the session/quiet-owl-897 branch August 21, 2026 18:09
gunbai-bot Bot pushed a commit that referenced this pull request Aug 21, 2026
Third consecutive strip-only integration. 4 conflicted files, 16 hunks to
main's semantics, 29 import lines removed from the 5-file delta, no name
rewriting. v2 self-compile: 0 hard diagnostics.

One correction to the previous integration: I had taken the BRANCH side of
src/v1/stage0/src/bootstrap_stage0_crate_layout_generated.rs, which dropped
main's EMITTER_PRODUCED_DIVERGENT_STAGE0_FILES (#8704) while
required_regen_host.rs imports it -- E0432, seed would not build. That file
is GENERATED, so the rule applies: regenerate or take the side matching the
.dag authority, never hand-merge. Main's .dag authority is what this merge
brought in, so main's mirror is the matching one. Seed builds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant