Repository navigation
Model expected_red_roster_join in .dag; fix two required_regen_host bugs blocking regen verification - #8527
Conversation
…ust normalize and candidate-dir ordering bugs expected_red_roster_join.rs (378 lines, #8428) was hand-authored with no .dag authority and hand-edited generated lib.rs, so a clean regen deleted its pub-mod line and the build failed E0433 (DESIGN §5 "manual application committed as source"). Model the module in src/v1/expected_red_roster_join.dag so v1_compiler_expected_red_roster_join.rs is compiler-emitted, and delete the hand-authored file; the legitimate hand-authored bin/expected_red_roster_join.rs Door is untouched. While re-running claim_executor --required-regen to verify, found and fixed two independent bugs in required_regen_host.rs blocking any regen check on a clean tree: write_emitted_tree unconditionally rustfmt-normalized every entry in the emitted map, including the non-Rust Cargo.toml artifact from crate-layout emission, crashing on `[package]`; and verify_hand_maintained wrote scratch normalize files into candidate_dir before that directory was ever created. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts: # dag/gunbc/stage0_crate_layout_generated.dag # src/v1/stage0/src/bootstrap_stage0_crate_layout_generated.rs
…on; scope disjoint-holds to the one genuine dual classification The #8428 regen-survivability backfill registered v2_compiler_compile.rs, v2_compiler_program_assembly.rs and v2_compiler_source_authority.rs as SeedRetainedIntrinsicRegistration rows, firing residue_frontier_module_gap's own dissolution trigger for all three — delete the fired rows rather than leave them stale. cssl_seed_linked_closure_assembly.rs remains a genuine dual classification (residue-pending-emission AND hand-maintained/emit-excluded) whose dissolution condition has not fired, so classified_residue_disjoint_holds is scoped to exclude exactly that one named path instead of silently widening. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts: # src/v1/stage0/src/required_regen_host.rs
# Conflicts: # src/v1/stage0/src/cli_run.rs
…rce_authority disposition — measured, not analogized
Parent's independent measurement (msg_6f205102) found these three basenames
carry ZERO pub-mod lines in src/v1/stage0/src/lib.rs on origin/main (control:
v1_interpreter and the four true v2_compiler_resolve/program_partition/
tokenize/infer siblings each carry exactly 1), with no #[path] wiring
anywhere. The prior gate_a_flip_lane_seed_retained_note claimed they were
"exactly like their already-registered ... siblings" and registered them as
SeedRetainedScaffoldRegistration, which implicitly emits a pub-mod line —
reclassifying them into the generated-with-pub-mod population so the
population-mismatch refusal stopped firing for these three rows, without the
underlying reality (zero wiring, genuinely committed_not_emitted) changing.
That is DESIGN.md S5's absorbing-fallback pattern applied at the disposition
layer, not a completed landing.
Reclassified to SeedRetainedIntrinsicRegistration { has_pub_mod: false },
matching the measured lib.rs state and matching the already-correct sibling
disposition of cssl_seed_linked_closure_assembly / required_regen_host (also
verified this session: 0 pub-mod lines each on origin/main, same profile).
Note rewritten to record the correction rather than silently overwrite the
false claim.
expected_red_roster_join is untouched by this commit and was never touched by
any prior commit on this branch — grep confirms it is unchanged context in
every hunk of this PR's diff; it already carried has_pub_mod: true on
unmodified origin/main. PR #8527 owns that row's terminal shape per parent's
ruling; there is nothing here to drop.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Thanks for the review. Both findings are real; I'm not fixing either right now, and want to say why rather than let that read as ignoring them.
— sent from quick-bee-733 |
Two findings from review 53871, recorded here because this lane has closed
Both are non-blocking. This PR is CLEAN and approved; the only thing holding it is the two-distinct-provider bar, which is currently unsatisfiable for every PR here since only one review provider exists. 1.
|
…m classifier, and lib.rs had three drops Twenty-eight conflicts, and this time three of them were in src/v1 files this branch has heavily edited, so the take-main's-file-whole rule I have been using does not apply on its own -- it is only safe where the discarded side is mechanically re-derivable, and my hand repairs in those files are not. Resolved by reading each conflict. The load-bearing one is #8592's follow-up: main DELETED `scalar_shaped_builtin_method_arg_type` (0 occurrences now in both 04_infer and 04_lookup) and replaced it with a `DeclaredArgContract` authority in 04_lookup. The sixth integration had taken that interim function from main; main has since superseded it. Keeping mine would have left two authorities answering one question, so main's deletion wins -- checked by counting occurrences on main rather than by reading the conflict's shape. One conflict resolved the other way: `a2_qualified` in 04_infer, where this branch's side already contains main's change plus a comment and the qualified callee. Taking main's side there would have discarded work while looking like a resolution. My hand repairs in those files were verified to survive rather than assumed to: the `lookup_variant_parent_enum` single-authority form, the 51 genuine `resolved_type` call sites, and the interpreter's sole-child alias descent are all still present. They were in non-conflicting regions, which is exactly why they needed checking. 2,183 names re-qualified across the 22 files that arrived carrying imports. The local-shadowing class recurred -- seven sites, `resolved_type`, `method_receiver` and `lookup_type` qualified where they are function parameters -- so the repair is now a pipeline step (`postcut.py`) rather than something I notice each time. The cut's driver reads the import block and cannot see that a name it qualifies is also a local; that is structural, so the repair belongs beside it. THREE MODULE DECLARATIONS IN lib.rs WERE WRONG, all of them silent: expected_red_roster_join declared here, DELETED on main by #8527 (modeled in .dag). Removed -- the build was failing on it. v1_compiler_trait_bound_witness declared on main, not here v1_tests_claim_checkpoint_identity_keying_witness declared on main, not here I re-added the last two and they do not compile, which surfaced something worth recording plainly: THIS BRANCH'S GENERATED SEED IS BEHIND ITS OWN .dag AUTHORITY. `rust_scalar_checkpoint_render_base` is declared `(String, String)` in both this branch's 05_emit_rust.dag and main's, but this branch's generated `v1_compiler_emit_rust.rs` still carries the pre-#8357 `(String, RustCorpusRepr)` signature. Measured drift against main: emit_rust 1,485 lines, infer 1,636, parse 295. The cause is the same hazard I hit in cli_run.rs -- an earlier integration took the branch's seed whole, and git has recorded it settled ever since. The two declarations stay out for now, stated rather than dropped silently, and the trigger is regenerating this branch's seed. That is not a change I will make inside a merge commit: the generated set has to move together or the mirrors disagree with each other, which is how this started.
…tion — and a check that finds this class The floor refused with `no such function: v2.workflow.required_floor.required_floor_expected_red_roster`. Neither this branch nor main declares it, and yet this branch's `cli_run.rs` calls it -- which is the shape I have now hit three times tonight, so I stopped fixing it and looked for the rest. It was MINE. Commit 5fb26a1 ("Restore the floor's edge to the expected-red roster as a qualified reference") added it, and the eighth integration deleted it by taking main's side on `required_floor.dag`. Main never had the function, so there was nothing on main's side to preserve it; taking main's file whole discarded it, and git has recorded that file settled ever since. The delegating edge is not decoration. `cli_run.rs` evaluates the roster inside the policy module's own frame, and the frame's scope IS that module's closure -- a name `required_floor` does not reference is not in the world the frame was built from. Main reaches `v2.workflow.floor_expected_red.floor_expected_red_roster` directly because main's frame differs; on this branch the edge is what makes the name reachable. SO I WROTE THE CHECK RATHER THAN PROMISING TO BE CAREFUL. `dropcheck.py` compares declaration names between a pre-integration commit and HEAD, keeps those that main also lacks, and reports them -- BY CONTENT, never by git's merge state, which is precisely the record a wholesale take corrupts. Over the eighth integration it found eight candidates. Four are main's own deletions (#8598, #8596, #8527 -- confirmed by finding each name in main's history rather than by assuming), one is main superseding my interim `scalar_shaped_builtin_method_arg_type`, and one is this. Over the ninth integration it reports zero. That is the difference between a rule and a mechanism: I wrote "verify the discarded side by content, not by git status" into my own notes two integrations ago, and then dropped this function anyway.
…generations Found by executing `claim_executor --required-regen` on main and then compiling the regenerated mirror, rather than by reading either artifact. Each is a fix at the .dag authority; the two projections in this diff were written by the declared actuator, not by hand. 1. `v2.compiler.self_host.stage0_crate_layout` -- ONE ROW DELETED. #8527 modelled `v1_compiler_expected_red_roster_join` in .dag, making it compiler-emitted, but RENAMED its `SeedRetainedIntrinsicRegistration` row instead of deleting it. A module cannot be both emitted and seed-retained: the emitted `lib.rs` then declares the basename twice, once from the file-derived set and once from the spliced `generated_pub_mod_block`. MEASURED: generation 2 fails `E0428 the name v1_compiler_expected_red_roster_join is defined multiple times`, lib.rs:160 against a previous definition at lib.rs:106. Generation 1 BUILDS CLEAN -- the duplicate only becomes a compile error once the candidate replaces the committed mirror. NOT MEASURED, stated as the inference it is: before the projection was regenerated, the generation-1 candidate carried the PRE-rename bare name `pub mod expected_red_roster_join;` at lib.rs:152 while the only file in the candidate directory is `v1_compiler_expected_red_roster_join.rs`, so an E0583 would follow. I did not build that candidate. Another session reported an E0583 here; I did not reproduce it, and an earlier revision of this message asserted it as my own measurement. That was wrong and is retracted. Two sessions, including this one, predicted this row self-heals. The E0428 refutes it. The discriminator was visible one generation earlier and was recorded before this fix: the stale literal ADDS rather than REPLACES, which is what two producers do. 2. `std.occurrence_binding_candidates` -- refusal propagation on BOTH destructurings of `AssembledClosureDependencyProjectionReady`. One arm dropped a refusal on the floor, so a failed projection continued as a successful one carrying an empty candidate set: the empty-observation narrow, DESIGN section 5. The other arm propagates correctly, which is what makes this a defect rather than a design. 3. `v1/04_types.dag` `instantiate_algebra_type` -- the `CallableOf` arm built a callable type from raw parameter types without the `make_callable_type` param-node wrap every other construction site uses, so instantiated algebra callables were shaped unlike their hand-written peers. 4. `v1/04_infer.dag` ExprLambda -- `body_expected` was derived from `callable_inferred`, which REBUILDS the callable rather than reading the one already resolved. Now it reads `resolved_type` behind an `is_fully_resolved` guard, so an unresolved lambda does not get a fabricated expectation. Measured on the fixed tree, guards armed (log byte count, candidate file count, candidate mtime after start -- an earlier run of this measurement was void because `claim_executor` is a separate binary and `gunbc claim_executor` exits 2 from clap, which aliases the drift exit code): `first_generation_equal=false planned=129 executed=129`, 235s, 16 files drifting -- four attributable to these fixes, twelve in files untouched here. Those twelve are the standing mirror drift, not a regression from this change, and they are why regen is not enrolable as a required gate today. Against the 15-name population on #8631, measured at 102bd15 without these fixes, the delta is exactly one name: v1_compiler_infer_types.rs, which fix 3 puts into drift. The other three fixed modules were already drifting there for unrelated reasons. Not asserted here: that regen is green. It is not. This closes four causes found on the way to that measurement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DY4WxMYnZKvxCpWTTwjaDy
…generations Found by executing `claim_executor --required-regen` on main and then compiling the regenerated mirror, rather than by reading either artifact. Each is a fix at the .dag authority; the two projections in this diff were written by the declared actuator, not by hand. 1. `v2.compiler.self_host.stage0_crate_layout` -- ONE ROW DELETED. #8527 modelled `v1_compiler_expected_red_roster_join` in .dag, making it compiler-emitted, but RENAMED its `SeedRetainedIntrinsicRegistration` row instead of deleting it. A module cannot be both emitted and seed-retained: the emitted `lib.rs` then declares the basename twice, once from the file-derived set and once from the spliced `generated_pub_mod_block`. MEASURED: generation 2 fails `E0428 the name v1_compiler_expected_red_roster_join is defined multiple times`, lib.rs:160 against a previous definition at lib.rs:106. Generation 1 BUILDS CLEAN -- the duplicate only becomes a compile error once the candidate replaces the committed mirror. NOT MEASURED, stated as the inference it is: before the projection was regenerated, the generation-1 candidate carried the PRE-rename bare name `pub mod expected_red_roster_join;` at lib.rs:152 while the only file in the candidate directory is `v1_compiler_expected_red_roster_join.rs`, so an E0583 would follow. I did not build that candidate and did not attempt to. An earlier revision of this message asserted the E0583 as my own measurement; that was wrong and is retracted. THE RETRACTION IS ABOUT MY EVIDENCE, NOT ABOUT THE E0583. swift-moth-294 reported an E0583 as their own generation-1 build result on their own tree, read from an error histogram over the whole population, and that report is not withdrawn. What is established here is only that I did not measure it. Treating this retraction as a refutation would re-open a live class by making a real defect look imaginary, which is the mirror of the error being corrected. Two sessions, including this one, predicted this row self-heals. The E0428 refutes it. The discriminator was visible one generation earlier and was recorded before this fix: the stale literal ADDS rather than REPLACES, which is what two producers do. 2. `std.occurrence_binding_candidates` -- refusal propagation on BOTH destructurings of `AssembledClosureDependencyProjectionReady`. One arm dropped a refusal on the floor, so a failed projection continued as a successful one carrying an empty candidate set: the empty-observation narrow, DESIGN section 5. The other arm propagates correctly, which is what makes this a defect rather than a design. 3. `v1/04_types.dag` `instantiate_algebra_type` -- the `CallableOf` arm built a callable type from raw parameter types without the `make_callable_type` param-node wrap every other construction site uses, so instantiated algebra callables were shaped unlike their hand-written peers. 4. `v1/04_infer.dag` ExprLambda -- `body_expected` was derived from `callable_inferred`, which REBUILDS the callable rather than reading the one already resolved. Now it reads `resolved_type` behind an `is_fully_resolved` guard, so an unresolved lambda does not get a fabricated expectation. Measured on the fixed tree, guards armed (log byte count, candidate file count, candidate mtime after start -- an earlier run of this measurement was void because `claim_executor` is a separate binary and `gunbc claim_executor` exits 2 from clap, which aliases the drift exit code): `first_generation_equal=false planned=129 executed=129`, 235s, 16 files drifting -- four attributable to these fixes, twelve in files untouched here. Those twelve are the standing mirror drift, not a regression from this change, and they are why regen is not enrolable as a required gate today. Against the 15-name population on #8631, measured at 102bd15 without these fixes, the delta is exactly one name: v1_compiler_infer_types.rs, which fix 3 puts into drift. The other three fixed modules were already drifting there for unrelated reasons. Not asserted here: that regen is green. It is not. This closes four causes found on the way to that measurement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DY4WxMYnZKvxCpWTTwjaDy
…generations Found by executing `claim_executor --required-regen` on main and then compiling the regenerated mirror, rather than by reading either artifact. Each is a fix at the .dag authority; the two projections in this diff were written by the declared actuator, not by hand. 1. `v2.compiler.self_host.stage0_crate_layout` -- ONE ROW DELETED. #8527 modelled `v1_compiler_expected_red_roster_join` in .dag, making it compiler-emitted, but RENAMED its `SeedRetainedIntrinsicRegistration` row instead of deleting it. A module cannot be both emitted and seed-retained: the emitted `lib.rs` then declares the basename twice, once from the file-derived set and once from the spliced `generated_pub_mod_block`. ONE DEFECT, TWO SPELLINGS, decided by whether the projection has been regenerated -- not by which base you are on: BEFORE regeneration, the emitted lib.rs carries the stale block's bare `pub mod expected_red_roster_join;` (lib.rs:152) beside the file-derived prefixed line, and only the prefixed FILE exists -> E0583 file not found. Measured by swift-moth-294 on their tree, with the four discriminating counts beside it (bare 1, prefixed 1, bare file 0, prefixed file 1). AFTER regeneration, both producers contribute the prefixed spelling -> E0428 the name is defined multiple times, lib.rs:160 against lib.rs:106. Measured here, receipt in this session's g2-build.log. TWO RETRACTIONS AGAINST MYSELF, BOTH LOAD-BEARING. Earlier revisions of this message reported the E0583 as my own measurement -- it is not mine, it reached me through a relay -- and then reported that generation 1 BUILDS CLEAN. It does not. My loop script ran `sed -i '/^pub mod expected_red_roster_join;$/d' src/v1/stage0/src/lib.rs` between installing the candidate and building it, so every clean generation-1 build I have is a build of the tree with the defect removed by hand. That is an unmarked workaround executed by the author, DESIGN section 5: it routed around a correct refusal, and it zeroed the defect's frequency in my own runs so it never ranked. Noticing it should have been the line-stop signal -- the line I deleted as noise IS the second producer. Two sessions, including this one, predicted this row self-heals. The E0428 refutes it. The discriminator was visible one generation earlier and was recorded before this fix: the stale literal ADDS rather than REPLACES, which is what two producers do. 2. `std.occurrence_binding_candidates` -- refusal propagation on BOTH destructurings of `AssembledClosureDependencyProjectionReady`. One arm dropped a refusal on the floor, so a failed projection continued as a successful one carrying an empty candidate set: the empty-observation narrow, DESIGN section 5. The other arm propagates correctly, which is what makes this a defect rather than a design. 3. `v1/04_types.dag` `instantiate_algebra_type` -- the `CallableOf` arm built a callable type from raw parameter types without the `make_callable_type` param-node wrap every other construction site uses, so instantiated algebra callables were shaped unlike their hand-written peers. 4. `v1/04_infer.dag` ExprLambda -- `body_expected` was derived from `callable_inferred`, which REBUILDS the callable rather than reading the one already resolved. Now it reads `resolved_type` behind an `is_fully_resolved` guard, so an unresolved lambda does not get a fabricated expectation. Measured on the fixed tree, guards armed (log byte count, candidate file count, candidate mtime after start -- an earlier run of this measurement was void because `claim_executor` is a separate binary and `gunbc claim_executor` exits 2 from clap, which aliases the drift exit code): `first_generation_equal=false planned=129 executed=129`, 235s, 16 files drifting -- four attributable to these fixes, twelve in files untouched here. Those twelve are the standing mirror drift, not a regression from this change, and they are why regen is not enrolable as a required gate today. Against the 15-name population on #8631, measured at 102bd15 without these fixes, the delta is exactly one name: v1_compiler_infer_types.rs, which fix 3 puts into drift. The other three fixed modules were already drifting there for unrelated reasons. Not asserted here: that regen is green. It is not. This closes four causes found on the way to that measurement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DY4WxMYnZKvxCpWTTwjaDy
…generations (#8637) Found by executing `claim_executor --required-regen` on main and then compiling the regenerated mirror, rather than by reading either artifact. Each is a fix at the .dag authority; the two projections in this diff were written by the declared actuator, not by hand. 1. `v2.compiler.self_host.stage0_crate_layout` -- ONE ROW DELETED. #8527 modelled `v1_compiler_expected_red_roster_join` in .dag, making it compiler-emitted, but RENAMED its `SeedRetainedIntrinsicRegistration` row instead of deleting it. A module cannot be both emitted and seed-retained: the emitted `lib.rs` then declares the basename twice, once from the file-derived set and once from the spliced `generated_pub_mod_block`. ONE DEFECT, TWO SPELLINGS, decided by whether the projection has been regenerated -- not by which base you are on: BEFORE regeneration, the emitted lib.rs carries the stale block's bare `pub mod expected_red_roster_join;` (lib.rs:152) beside the file-derived prefixed line, and only the prefixed FILE exists -> E0583 file not found. Measured by swift-moth-294 on their tree, with the four discriminating counts beside it (bare 1, prefixed 1, bare file 0, prefixed file 1). AFTER regeneration, both producers contribute the prefixed spelling -> E0428 the name is defined multiple times, lib.rs:160 against lib.rs:106. Measured here, receipt in this session's g2-build.log. TWO RETRACTIONS AGAINST MYSELF, BOTH LOAD-BEARING. Earlier revisions of this message reported the E0583 as my own measurement -- it is not mine, it reached me through a relay -- and then reported that generation 1 BUILDS CLEAN. It does not. My loop script ran `sed -i '/^pub mod expected_red_roster_join;$/d' src/v1/stage0/src/lib.rs` between installing the candidate and building it, so every clean generation-1 build I have is a build of the tree with the defect removed by hand. That is an unmarked workaround executed by the author, DESIGN section 5: it routed around a correct refusal, and it zeroed the defect's frequency in my own runs so it never ranked. Noticing it should have been the line-stop signal -- the line I deleted as noise IS the second producer. Two sessions, including this one, predicted this row self-heals. The E0428 refutes it. The discriminator was visible one generation earlier and was recorded before this fix: the stale literal ADDS rather than REPLACES, which is what two producers do. 2. `std.occurrence_binding_candidates` -- refusal propagation on BOTH destructurings of `AssembledClosureDependencyProjectionReady`. One arm dropped a refusal on the floor, so a failed projection continued as a successful one carrying an empty candidate set: the empty-observation narrow, DESIGN section 5. The other arm propagates correctly, which is what makes this a defect rather than a design. 3. `v1/04_types.dag` `instantiate_algebra_type` -- the `CallableOf` arm built a callable type from raw parameter types without the `make_callable_type` param-node wrap every other construction site uses, so instantiated algebra callables were shaped unlike their hand-written peers. 4. `v1/04_infer.dag` ExprLambda -- `body_expected` was derived from `callable_inferred`, which REBUILDS the callable rather than reading the one already resolved. Now it reads `resolved_type` behind an `is_fully_resolved` guard, so an unresolved lambda does not get a fabricated expectation. Measured on the fixed tree, guards armed (log byte count, candidate file count, candidate mtime after start -- an earlier run of this measurement was void because `claim_executor` is a separate binary and `gunbc claim_executor` exits 2 from clap, which aliases the drift exit code): `first_generation_equal=false planned=129 executed=129`, 235s, 16 files drifting -- four attributable to these fixes, twelve in files untouched here. Those twelve are the standing mirror drift, not a regression from this change, and they are why regen is not enrolable as a required gate today. Against the 15-name population on #8631, measured at 102bd15 without these fixes, the delta is exactly one name: v1_compiler_infer_types.rs, which fix 3 puts into drift. The other three fixed modules were already drifting there for unrelated reasons. Not asserted here: that regen is green. It is not. This closes four causes found on the way to that measurement. Claude-Session: https://claude.ai/code/session_01DY4WxMYnZKvxCpWTTwjaDy 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 that position The deleted line stays deleted -- it was dead residue and removing it is correct on its own merit. What does not stand is ae2fb03's commit message, which asserted as measured that the empty import caused nine dropped `pub mod v2_compiler_*` declarations and one phantom `expected_red_roster_join`. IT DID NOT. Re-run with one frozen binary and one variable: arm A HEAD as-is, line deleted 131 files, 13 v2_compiler decls, 0 roster arm B same tree, line restored 131 files, 13 v2_compiler decls, 0 roster diff -rq over the whole emitted tree: NO DIFFERENCES The original four-arm result was confounded. Its branch arm ran on an older `gunbc` than its other three arms: the binary was rebuilt mid-sequence at 13:48 as a side effect of `cargo build --release --bins`, run for an unrelated probe. The one arm showing the anomaly is the only one that predated that rebuild, and that binary predated #8527 (8ca2e2a), which is why its lib.rs carried `expected_red_roster_join` -- a name current sources cannot emit. The claimed control ("same binary throughout") never existed; the variable I attributed the effect to covaried exactly with one I did not know had moved. What survives, and neither part depends on the retracted numbers: - an empty import list CAN change emitted bytes -- established independently by another session, whose specimen is a module's SOLE import manufacturing a phantom module. That is a different condition from this one, where the emptied import was one of many, and these arms say nothing about it either way. - the seed builds clean (lib and all bins) with nine declarations absent. That was measured on an installed tree rather than on an emit, so the binary confound does not reach it. Recorded as its own commit rather than a body edit, because the false claim is in a pushed commit message and a squash flattens both into one history entry. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq
…st rows in extdeps, closed alphabet re-homed to keep spelling total (#8605) * B1 (b): capability-keyed sharing contract replaces RequiredTraitWitness at the root RULED (operator, 2026-08-19, relayed by smart-ram-730): B1 resolves as option (b), a capability-keyed contract subsuming RequiredTraitWitness — not the coproduct. WHY, and it does not rest on any diagnostic count. RequiredTraitWitness's three variants (TargetCollectionWitnessOrd/Hash/Eq) were RUST TRAIT NAMES sitting in a std interface. DESIGN §4: a new target language is rows in extdeps/languages, never an edit to the fold — so a target whose sharing requirements differ from Rust could only express them by editing that coproduct, which is the N×M adapter trap §4 exists to prevent. §3 puts realization-selecting dispatch peripheral, never in the interface. WHAT LANDS type TargetCapabilityKey = Symbol where brand("TargetCapabilityKey") type TargetCapabilityRequirement { representation_parameter, capability_key } type TargetCapabilityElementEligibility { kernel_atoms: List<Symbol> } type TargetCapabilityEligibilityTable = Map<TargetCapabilityKey, ...> RequiredTraitWitness is DELETED at the root, not hollowed or adapted — zero references remain in v2 std, extdeps, compiler, or tests. Per-target eligibility rows are authored in extdeps/languages/rust.dag and ride the target's own bundle, so std decodes them generically and never names a Rust trait. The wire form was ALREADY keyed on a Symbol atom; only the in-memory type was a coproduct. So the migration DELETES the translation boilerplate rather than adding to it: rust_collection_witness_bundle_node 48 -> 16 lines, and the 43-line if-chain in target_collection_witness_from_node collapses to a direct read. A §5 REPAIR THAT RODE ALONG, named so reviewers see it rather than find it. repr_grounding_derive_traits_for_collection_witness had a two-arm if/else in which an UNRECOGNISED capability silently received the equality trait list — an absorbing fallback (a failure arm that defaults instead of refusing). It now returns Optional and refuses, with tdc_unknown_capability_refuses_rather_than_defaulting as the discriminating input: it asserts an undeclared capability is Absent AND that a declared one is not, so it goes red if the refusal is removed. Unknown capability at satisfaction time is likewise a typed, located refusal (target_capability_eligibility_row_absent) rather than a silent true/false. WHAT THIS DOES NOT DO, measured rather than assumed. The work item claimed this carrier was "the measured root of 97 diagnostics across 20 module boards". That is false and the operator has accepted the refutation. RequiredTraitWitness was MONOMORPHIC (type_param was a Symbol FIELD, not a type parameter) and target_model declares zero generic types and zero generic functions, so it cannot originate a trait-bound class. A clean-worktree measurement at e0c5e25 confirms it: of 68 primary diagnostics in the emitted v2_std_compilers_target_model.rs there are ZERO "no method clone for type parameter" and ZERO "trait bound T: Clone". The board is function-valued carriers that cannot derive serde/Debug (19), missing-field initializers (16), map-accessor emission gaps (5), and E0308/E0004 residue. Same file, different defect. This PR will not move those counts. EVIDENCE 0 blocking errors on all six changed entries (gunbc compile, 2 source roots, primary-precedence). trait_derive_completeness_predicate_test: 6/6 green BY EXECUTION, including the new discriminating test. Two DeclarationRef citations in derive_contracts.dag named the deleted declaration; repointed, so no citation names a symbol that does not resolve. LANGUAGE-LAYER DEFECT WORTH KNOWING: `capability` is a reserved keyword. Using it as a field name produces "expected RParen, found keyword 'capability'" reported at a character offset ~300k away from the real line. Field is spelled capability_key. Census defect recorded per operator instruction: the phase-B0 probe document reports TWO DIFFERENT 139s in two partitions of one 369-occurrence population with different site counts (39 vs 20), and NoEmitterArm's authority lines are a proper subset of DerefCloneWholeValue's — which cannot hold at an equal occurrence count. Marked unreliable and unreproducible (its instrument was a deleted shell scaffold) rather than resolved or quietly dropped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Name the two residues review 53861 found, with their triggers Both findings are correct and both are recorded in the module header rather than answered in the PR thread, because a trigger that lives only in a review comment is not a trigger. (1) RESIDUAL PER-TARGET AUTHORITY. repr_grounding_derive_traits_for_capability keys on the three Rust capability symbols and answers with Rust derive-trait lists — the same per-target policy this PR evicted from std/target_model, now one layer up in v2/compiler instead of in extdeps/languages/rust beside the eligibility rows. It is not a second carrier, but it is a second per-target ROW SET, so a non-Rust target would still edit this file. Sequencing stated rather than deferred by omission: these rows are typed in ReprGroundingDeriveTrait, so migrating them to extdeps BEFORE that 16-variant coproduct is keyed would only relocate the coproduct unchanged. They move together in the ReprGroundingDeriveTrait cutover (PR 2). (2) OBLIGATION ON Absent, PINNED BEFORE A CONSUMER EXISTS. Absent means "unknown capability key", never a satisfied or unsatisfied gate. No production consumer exists today, so this is not live fail-open — but when one is wired, Absent must route to a typed located refusal. Folding it into Satisfied or Incomplete, or treating it as skip-the-gate, would reintroduce precisely the absorbing fallback this PR removed. tdc_unknown_capability_refuses_rather_than_defaulting is the control that goes red if that behaviour returns. 0 blocking errors on the changed entry. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Census note: state the sizing correction without restating counts Self-inflicted, and the file said so before I edited it. The note I amended already carries "COUNTS ARE DELIBERATELY NOT RESTATED HERE (review 44386ate)": this module previously restated site and occurrence counts, they went stale the moment #7324 moved the corpus, and they then contradicted the receipt — a §3 dual representation of a fact whose home is the measurement, not the module. I added counts back into that exact note. Removed: the carrier-population figure, the measured-board figures, and the base SHA of the measurement run. Kept: the ruling, the reason the sizing figures do not size carrier work (they count emitted-Rust occurrences under a lowering-operation partition — a different population, which is a statement about denominators, not a number), and a pointer to the probe document that is the measurement's actual home. The attribution refutation is kept but re-stated STRUCTURALLY rather than numerically: RequiredTraitWitness was monomorphic, so it could not originate a trait-bound class at all. That argument does not decay when the corpus moves; a diagnostic count does. Flagged by deep-ant-102, whose general point — never justify this contract by a diagnostic count in a durable artifact — is correct and lands on this note specifically, notwithstanding that the counts here were recording a REFUTATION of that attribution rather than a justification for the work. 0 blocking errors on the changed entry. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * B1 PR 2 (Option A): collapse TargetDeriveTraitKey into TargetCapabilityKey Two brands stood over one overlapping key space in target_model — and PR 1 created the second one, so this retires a fork of my own making. TargetDeriveTraitKey was never an independent authority. Measured: every value of it in the corpus came from a single producer, target_grounding_derive_trait_key(t) = target_grounding_derive_trait_discriminant(t) = discriminant(t) so the brand was a projection OF ReprGroundingDeriveTrait. It and TargetCapabilityKey are both `Symbol where brand(...)` and their key spaces overlap on Ord, Hash, Eq and Clone — the §3 nickname pair. Collapsed into TargetCapabilityKey. The producer is renamed target_capability_key_for_derive_trait, since a function returning a capability key should not be named for the type it no longer returns. NO v1 EXPOSURE, WHICH IS WHY THIS IS LANDABLE NOW. The producer still ACCEPTS a ReprGroundingDeriveTrait and returns its discriminant, so no shared std or extdeps signature changes and frozen v1 is untouched. All 19 sites are v2-only (target_model 10, v2 extdeps rust 3, one v2 test file 6). THE FORK IS NOT CLOSED, AND THE CARRIER SAYS SO. After PR 1 plus this, main still carries ReprGroundingDeriveTrait AND TargetCapabilityKey as two representations with the Ord/Hash/Eq/Clone overlap LIVE. Three representations to two — not closed. That is recorded in target_capability_key_fork_state_note rather than left for the word "collapse" to overstate; a diff that reads as closing a fork while leaving one is the rung inflation §4b names, applied to a changeset. WHY IT COULD NOT BE CLOSED HERE — measured, and it reverses what three sessions had agreed. src/v1/trait_derive_emit.dag imports twenty symbols from std.trait_derive_shape; five of them (record_derive_traits_heap, _copy, nullary_coproduct_derive_traits, symbol_wrapped_ord_carrier_derive_traits, repr_grounding_derive_completeness_predicate) are the SAME declarations v2 and dag/extdeps/languages/rust/emit consume — not parallel copies — and their signatures are typed in the coproduct. extdeps.languages.rust.emit rust_trait_derive_attr_from_traits additionally takes List<ReprGroundingDeriveTrait> and is imported by v1 directly. So the coproduct crosses the frozen boundary through BOTH std and extdeps, and every route to migrating a consumer either changes a signature v1 shares (breaking frozen v1) or adds a keyed surface beside the coproduct in std (a dual authority — worse than today). Both arms refuse, which is what makes this a block rather than a preference. The prior conclusion that the freeze ruling governed only a final re-home step, and was therefore off the critical path, is refuted by that import measurement. 0 blocking errors on all three changed entries. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Split the capability model: agnostic half stays in std, Rust rows move to extdeps The freeze relaxation ("anything in support of v2 self host is safe") unblocks the half of B1 that was measured as blocked. This is the structural move; consumer rewiring follows. ReprGroundingDeriveTrait was sixteen Rust and serde trait names sitting in a std interface, so a non-Rust target could only express its capabilities by editing that coproduct — the §4 N×M adapter trap. Replaced by TargetCapabilityKey. WHAT SPLITS WHERE, and the line is target-agnostic vs target-specific: std.trait_derive_shape TargetCapabilityKey brand; ReprGroundingDeriveElemShape (SOURCE shapes — kernel string/int/bool/unit, nullary enum, payload coproduct — substrate concepts, legitimately std); generic table lookup and completeness predicate that take a TargetCapabilityShapeTable AS A PARAMETER. 547 -> 272 lines. extdeps.languages.rust.capabilities (new) the sixteen capability keys, the shape-by-capability rows, the derive-trait list builders, the emission order. So dispatch is peripheral (§3) and a new target is a sibling module of rows, never an edit to the fold (§4). TargetCapabilityKey MOVES DOWN from target_model into std.trait_derive_shape. Primary reason is §3 placement — the capability key belongs with the capability authority, not in the target model that consumes it. It also removes an import cycle: target_model already imports std.trait_derive_shape, so keying that module on a type declared in target_model reverses the direction, and acyclicity is the one structural law DESIGN does not bend. PR 1 placed it in target_model only because that was the sole file in scope then. THIS FIRES THE MODULE'S OWN DECLARED TRIGGER RATHER THAN OVERRIDING IT. trait_derive_shape_dissolve_on already said these Rust-specific members "migrate beside each target's spelling table WHEN A SECOND CONSUMER EXISTS." The C-linkage realization is that second consumer. The ruling fires a trigger the authority had already written, which is a stronger position than overriding one. ROW FIDELITY — the part that could have silently emptied. The shape×capability rows were extracted mechanically from the predecessor's nested match, not hand-retyped: 71 admitted pairs extracted against 71 `=> true` cells in the source, 8 shape rows. My first extraction pass silently produced ONE row and a table that still compiled — the fixture-emptied-of-its-subject failure, in my own tooling. The counts are asserted against the source rather than eyeballed. Serialize and Deserialize are serde names, not Rust language names, and their spellings were ALREADY cited in extdeps rust_trait_derive_spelling — so the std coproduct was a redundant KEY SET forked from a key extdeps already spelled. This finishes a migration someone had started rather than opening a new one. DECLARED RESIDUE: std.trait_derive_shape's NAME now says "derive shape" for what is a capability authority — a §3 nickname for what it has become. Not renamed here: a mechanical rename across every importer, bundled into a migration already reshaping contents, makes both unreviewable. Named in the module note with its trigger. 0 blocking errors on both authorities. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Complete the capability-key migration: consumers rewired, and two defects compile-clean could not see Finishes the ReprGroundingDeriveTrait -> TargetCapabilityKey migration the previous two commits started, and repairs two defects that a clean `gunbc compile` reported nothing about. WHAT LANDED - Every consumer of the derive-trait lists and the completeness predicate now reads the Rust rows from extdeps.languages.rust.capabilities and passes the shape table explicitly: v1 trait_derive_emit and 05_emit_rust, v2 trait_derive_completeness, and four witness modules. - kernel_int_arithmetic_traits migrated with the other builders (it was left behind by the split). - RustCapability: the coproduct is RE-HOMED into extdeps rather than deleted. TargetCapabilityKey is an open Symbol brand so unrelated modules can share one key space; an open brand cannot be matched exhaustively, and rust_trait_derive_spelling was TOTAL by exhaustive match before this migration. Deleting the coproduct outright would have traded a structural guarantee for a runtime refusal -- a rung DROP dressed as a migration (DESIGN 4b). Interface speaks keys; realization speaks the closed alphabet; rust_capability_key is the single total lift between them. - The pair-completion spelling rows now carry the capability key they answer for, so the join to std.trait_derive_shape is an identity match. That REPLACES a sixteen-arm key-to-method-name function -- a second naming scheme for what the key already names (DESIGN 3). One thing got weaker and the note beside it says so: the refusal arm can no longer name the unmatched key, because no Symbol-to-String projection exists; it prints the keys that ARE spelled instead. - TargetCapabilityKey is declared ONCE (std.trait_derive_shape) and imported everywhere. target_model had a local declaration AND the identical import. TWO DEFECTS THAT COMPILED CLEAN 1. target_grounding_derive_trait_discriminant called `discriminant(v: key)` on what is now a branded Symbol, and was ALSO passed as a function VALUE to coproduct_nullary_inhabitant_by_discriminant, so it resolved eagerly. Effect: any module whose closure reached target_model could no longer resolve the `discriminant` builtin at all, surfacing as NoSuchFunction attributed to whatever entry function happened to be running. All fifteen entries reported 0 blocking errors throughout. The wrapper, its second name, and the coproduct-inhabitant decode all collapse to the identity for a branded Symbol and are gone. 2. The witness files passed List<RustCapability> where List<TargetCapabilityKey> was required. It compiled; at runtime the comparison was variant-against-symbol and silently answered false. rust_capability_keys lifts at the boundary. EVIDENCE, BY EXECUTION - Minimal pair for defect 1: a probe module declaring its own coproduct and calling `discriminant` passes on clean main, fails NoSuchFunction on this branch, discriminated solely by importing v2.extdeps.languages.rust. Green after the fix. - 18 witnesses across trait_derive_completeness_predicate_test and trait_derive_seed_emit_binding_test run green, including the pair-completion tests that exercise the rewritten key join. Defect 2 was found by one of them going red, not by review. - All changed entries compile with 0 blocking errors. The two diagnostics on coproduct_reflection_conformance_test (LiveTreeDisposition, SubstrateInputsOnly) are byte-identical on clean main and are not from this change. `gunbc compile` reporting zero blocking errors is not evidence that a module evaluates. Both defects above were invisible to it and both were found by running a witness (DESIGN 5). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Stop laundering the closed alphabet through the open key brand (review 53978), and delete this PR's own unreferenced rows REVIEW FINDING, CONFIRMED AND FIXED review 53978 found v1_with_map_key_requirement declared as List<TargetCapabilityKey> -> List<TargetCapabilityKey> while every caller passes a list builder's List<RustCapability> and every consumer of its result takes List<RustCapability>. The signature typed on the OPEN brand what the function threads as the CLOSED alphabet -- silently laundering away the exact invariant the alphabet exists to hold (DESIGN 4b), and the compiler said nothing. The chain went one link further than the report: v1_with_map_key_requirement calls derive_traits_union, which with derive_traits_contain was declared in std.trait_derive_shape on the key brand -- and those two had exactly ONE consumer, this function. So the repair is not a cast at the boundary; the helpers were in the wrong module on the wrong type. Both are relocated to extdeps.languages.rust.capabilities, typed on RustCapability, and v1's signature follows. Recorded beside them, so it is not retried: keeping them in std and lifting to keys at the call site would have forced the union result back through a key-to-spelling step that no longer exists, because spelling is total only over the alphabet. That repair looks smaller and breaks the guarantee. A SECOND DEFECT FOUND SWEEPING FOR THE FIRST Rather than trust a single report, I enumerated every remaining key-typed surface. The sixteen `rust_capability_<name>: TargetCapabilityKey` data rows and `rust_capability_emission_order` -- all authored by me earlier in this PR -- have ZERO references corpus-wide. A new artifact with no final consumer is experimental residue (DESIGN 6), and sixteen rows that read as the key authority while nothing consumes them are worse than absent. Deleted. Emission order is carried by the list builders, where it was before this migration. The module note claimed both as contents; it is rewritten rather than left asserting deleted rows. DECLARED RESIDUE, NEW derive_traits_contain / derive_traits_union are a membership test and a set union over a list, specialized to one element type because this corpus has no generic list union to instance. Naming it rather than minting one: authoring a new std primitive is wider than the finding that produced the move. Dissolves when a second element type asks for the same union. EVIDENCE All affected entries compile with 0 blocking errors, and -- because compile-clean is precisely what missed this class -- nine witnesses re-run green by execution across both affected test files, including the record heap/copy and payload-coproduct paths that flow through the retyped function. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Floor run found a third discriminant-on-a-Symbol site: a fixture my own rewiring script rewrote The manual floor dispatch on 15b2750 came back with exactly one unheld failure out of 9687 executed (passed=9380, known_red_held=306, failed=1): required-floor: FAIL v2.test.claim.emit.trait_derive_supplemental_generic_bound_contract. malformed_contract_row_refuses_on_bundle_decode errored: no such function: discriminant ROOT CAUSE sgb_atom_node(identity: discriminant(v: ^target_capability_debug)) discriminant of a SYMBOL LITERAL. The fixture originally read discriminant(v: ReprDeriveDebug) -- a coproduct variant, where the call was meaningful. My scripted rewiring replaced the variant with the symbol literal and left the call wrapped around it, producing an expression that is well-formed, compiles clean, and cannot evaluate. Same class as the two already fixed in this PR, third instance, and the one place I had not looked: I swept production code for the pattern and not the FIXTURES. Now `sgb_atom_node(identity: ^target_capability_debug)`. The fixture's malformation is unchanged -- a positional edge where the decoder requires named ones -- so the witness still refuses for the reason it was written to refuse, and the round-trip witnesses confirm the decoder still ACCEPTS well-formed rows rather than refusing everything. ALSO: TargetCapabilityKey was imported from BOTH std.trait_derive_shape and v2.std.compilers.target_model in two files. target_model no longer declares it, so the second import named a symbol that module does not own. Removed. Stated at the strength of the evidence: this is a section 3 duplicate-binding defect on its own terms, and removing it did NOT fix the failure above -- I checked before moving on. EVIDENCE malformed_contract_row_refuses_on_bundle_decode true (the floor's one red) missing_contract_authority_refuses_on_bundle_decode true nested_generic_contract_round_trip_preserves_keyed_authority true rust_vec_target_bundle_round_trip_preserves_im_vector_policy true rust_set_target_bundle_round_trip_preserves_both_production_policies true rust_vec_unmodeled_ord_contract_refuses_as_missing true The round-trips are there deliberately: a refusal witness going green after a fixture edit proves nothing unless the accept path still accepts. A stacked PR schedules no pull_request runs, so this push fires nothing. Re-dispatching the floor manually against the new head. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Recut the bootstrap seam: std names no capability carrier, one key + one alphabet + one bridge required-regen refused this branch BEFORE comparing any bytes. The move-down put `TargetCapabilityKey = Symbol where brand(...)` in dag/std/trait_derive_shape.dag, which forced `import v2.std.node { Symbol }` into a module that src/v1 imports. regen_input_sources seeds its walk from HARDCODED roots (cli_run.rs regen_source_roots: src/v1, dag) and ignores --source-root entirely, so src/v2 is not in the index at all. THE INVARIANT, which is closure membership and NOT seed-projection: a dag/ module reachable by import from src/v1 may not import v2.*. 591 dag/ modules import v2.* legally because src/v1 does not reach them. This is not a gate defect to route around -- stage0 IS the v1 seed, and a seed closure reaching into src/v2 would make the seed depend on the successor it bootstraps toward. THE SHAPE, three declarations with one home each rather than one declaration shared across bootstrap generations: open interface key TargetCapabilityKey v2.std.compilers.target_model (back where it was) closed alphabet RustCapability extdeps.languages.rust.capabilities total bridge alphabet -> key v2.extdeps.languages.rust, exhaustive, no wildcard std now names NO carrier: TargetCapabilityShapeRow<K>, TargetCapabilityShapeTable<K> and both predicates take the carrier as a type parameter. A seed-visible carrier would have satisfied the gate by putting the target-model concept back INSIDE the seed closure -- the coupling that made the predecessor work by accident. A type parameter removes the dependency instead of relocating it, so std cannot violate the boundary by construction. There is also no retype target: zero `type Symbol` declarations exist under src/v1 or dag. The seed path then speaks the alphabet end to end at K = RustCapability, which DELETED the rust_capability_keys lift added last round -- a correct decomposition deletes something. PAIR-COMPLETION IS REKEYED ONTO ITS OWN OPERATION, not the capability key. add/sub/mul/div/neg are semantic; a target may realize canonical addition through a trait, an operator token, or a function. Keying the algebra on a target-realization identity let that identity leak back into target-independent algebra, and it would have survived the placement repair looking fixed. The predecessor note declined to mint this enum, correctly, while one key set was visible to both sides; that premise is gone and the reversal is recorded rather than left as drift. THE BRIDGE WAS BRIEFLY DELETED AND RESTORED. After parameterizing std, nothing called it, so I removed it as dead. That was wrong: with no bridge, RustClone and ^target_capability_clone corresponded only by MATCHING SPELLING, with no authority and nothing that would refuse if they diverged. It is now the sole authority for that correspondence and every Rust capability key in v2 routes through it. EVIDENCE, TWO MEASUREMENTS BECAUSE ONE CANNOT COVER BOTH HALVES closure half : required-regen (reported separately; it never compiles src/v2) v2 half : the three src/v2 consumers required-regen structurally cannot see -- v2.compiler.trait_derive_completeness and the two v2 test claims All changed entries compile with 0 blocking errors under three roots. 18 witnesses green by execution across both claim files, including every pair-completion witness -- which exercise the rekeyed join -- and tdc_unknown_capability_refuses_rather_than_defaulting, the discriminating control for the absorbing fallback this cutover removed. One witness went RED mid-recut and is why the v2 half is measured separately: tdc_int_kernel_satisfies_arith_and_ord passed capability KEYS into a predicate now keyed by the ALPHABET. It compiled clean and answered false. v2.compiler.trait_derive_completeness is Rust-specific policy -- that is its own declared residue -- so it now speaks the alphabet openly instead of hiding its target-specificity behind key literals. Entry scope is not gate scope, a green floor is not a green regen, and a green regen is not a green corpus. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Delete the rank projection: a second identity on ReprGroundingDeriveElemShape I introduced (review 54050) review 54050 flagged repr_grounding_derive_shape_has_trait comparing shapes through an Int `rank` projection instead of `==`, reading as a workaround for generic-coproduct equality and, either way, a second identity on the coproduct. CHECKED RATHER THAN ASSUMED, in both directions: repr_grounding_elem_shape_rank does NOT exist on main -- `git show origin/main:...| grep -c` is 0. I introduced it in this PR, and its only consumer was my own predicate. It is not a substrate constraint anyone was living with; it is a workaround I authored for a limitation I never tested. Coproduct equality WORKS. Probe with both arms: ReprDeriveElemKernelInt == ReprDeriveElemKernelInt -> true (ReprDeriveElemKernelInt == ReprDeriveElemKernelBool) == false -> true A same-only probe would have passed against an `==` that returns true unconditionally, so the discriminating arm is the one that establishes it. So the reviewer's "likely a real constraint of the substrate today" is generous and wrong, and I am recording that rather than accepting the softer reading: the substrate was fine and I did not check. The comparison is now `row.shape == shape` and repr_grounding_elem_shape_rank is deleted. Nothing else referenced it, so no ordering semantics are lost -- the projection was only ever standing in for equality. EVIDENCE: all three affected entries compile with 0 blocking errors, and the four SHAPE- DISCRIMINATING witnesses pass -- two positive (int-kernel arithmetic, symbol-kernel string shape) and two negative (string kernel does NOT satisfy add, unknown atom REFUSES ord completeness). The negatives are the ones that matter here: an equality that matched everything would still green the positives. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * An empty import list silently corrupts the emitted crate layout: delete the dead statement My own scripted import cleanup left `import std.trait_derive_shape { }` in 05_emit_rust.dag after its last imported symbol moved to extdeps.languages.rust.capabilities. The statement is dead, compiles with 0 blocking errors, and emits no diagnostic -- and it silently changes what the emitter writes: emitted lib.rs, my branch: 4 `pub mod v2_compiler_*` declarations, plus a spurious `pub mod expected_red_roster_join;` whose only .rs is a BIN (E0583 if installed) emitted lib.rs, main: 13 `pub mod v2_compiler_*` declarations, no roster declaration Deleting the one line restores the emitted declaration set to exactly main's, plus my own new module -- nothing else changes. Single-variable, measured, not inferred: main -> 13 v2_compiler decls, 0 roster main + an unrelated new module (probe) -> 13 v2_compiler decls, 0 roster (so it is not module addition) this branch, line present -> 4 v2_compiler decls, 1 roster this branch, line deleted -> 13 v2_compiler decls, 0 roster Same binary, same command, same on-disk crate layout on both sides; only the .dag sources differ. The nine dropped declarations were previously reported as a possible repository-wide population-authority question and escalated as such. They are not: they were this branch's defect, and the escalation should be closed on this evidence rather than on the zero-drift argument that closed it first. The substrate half stays open and is reported separately: a syntactically valid empty import list changes emitted bytes with no refusal anywhere on the path. That is a silent wrong answer (DESIGN section 5), not a lint -- the emitted crate simply loses module declarations. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Retract the causal claim on ae2fb03: the empty import changed nothing at that position The deleted line stays deleted -- it was dead residue and removing it is correct on its own merit. What does not stand is ae2fb03's commit message, which asserted as measured that the empty import caused nine dropped `pub mod v2_compiler_*` declarations and one phantom `expected_red_roster_join`. IT DID NOT. Re-run with one frozen binary and one variable: arm A HEAD as-is, line deleted 131 files, 13 v2_compiler decls, 0 roster arm B same tree, line restored 131 files, 13 v2_compiler decls, 0 roster diff -rq over the whole emitted tree: NO DIFFERENCES The original four-arm result was confounded. Its branch arm ran on an older `gunbc` than its other three arms: the binary was rebuilt mid-sequence at 13:48 as a side effect of `cargo build --release --bins`, run for an unrelated probe. The one arm showing the anomaly is the only one that predated that rebuild, and that binary predated #8527 (8ca2e2a), which is why its lib.rs carried `expected_red_roster_join` -- a name current sources cannot emit. The claimed control ("same binary throughout") never existed; the variable I attributed the effect to covaried exactly with one I did not know had moved. What survives, and neither part depends on the retracted numbers: - an empty import list CAN change emitted bytes -- established independently by another session, whose specimen is a module's SOLE import manufacturing a phantom module. That is a different condition from this one, where the emptied import was one of many, and these arms say nothing about it either way. - the seed builds clean (lib and all bins) with nine declarations absent. That was measured on an installed tree rather than on an emit, so the binary confound does not reach it. Recorded as its own commit rather than a body edit, because the false claim is in a pushed commit message and a squash flattens both into one history entry. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Stop storing the capability-eligibility index in the realization record TargetCollectionRealization carried `capability_eligibility` as a Map<TargetCapabilityKey, TargetCapabilityElementEligibility>. The authored data is a List<TargetCapabilityEligibilityRow> in extdeps.languages.rust and the Map was folded from it, so the record stored a DERIVED INDEX beside its own authority -- redundancy under DESIGN section 2 independently of what it costs to emit. What it costs to emit, measured: the Map realizes as PartialFunction, the emitter derives Debug, Clone, PartialEq, Serialize and Deserialize on the containing record, and PartialFunction satisfies none of them. That is 14 rustc errors on the emitted crate, all in v2_std_compilers_target_model.rs, all attributable to this one field (main 1ebac31: 189 errors in the closure; this branch before this commit: 203). The field becomes the row list. The Map survives as a lookup structure built at the point of consumption (`target_capability_eligibility_table_from_rows`) and as the decoder's duplicate check, so no refusal is lost: `target_capability_eligibility_from_node` still folds rows through a map and still rejects a duplicate capability key with `target_capability_eligibility_duplicate_diagnostic`; it now returns the rows it validated rather than the index it built from them. The emitter's inability to derive over a carrier holding a structurally underivable value is NOT fixed here and is not this PR's to fix -- main carries the same class at two other sites in this file, and the wider family (function-valued fields on the interpreter carriers) has no escape at all, because there the function value IS the model's intent rather than an index. This instance is the one with a clean way out, which is why it is taken here and the others are left named. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Drop the eligibility Map entirely: the rows are the lookup The previous commit moved the stored index out of the record but kept a Map rebuilt at each point of consumption. That still cost errors, because `Map<TargetCapabilityKey, V>` realizes inconsistently: as `PartialFunction` in TYPE position (the alias in a signature) and as `im::HashMap` in EXPRESSION position (`empty_map`/`map_insert`), so every declared-vs-constructed pairing is an E0308. So the Map goes. Eligibility lookup is a fold over the authored rows (`target_capability_eligibility_lookup`), and the three consumers take `List<TargetCapabilityEligibilityRow>` directly. Nothing is rebuilt at consumption because there is nothing to rebuild. The decoder keeps its Map, unexported and local, purely as the duplicate-key check, so `target_capability_eligibility_duplicate_diagnostic` still fires on a repeated capability key. No refusal is lost. The PartialFunction-vs-im::HashMap representation fork is an emitter defect and is NOT fixed here; this change stops one module depending on the inconsistent surface. Two other sites in this file and the function-valued interpreter carriers still sit on it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Remove the last Map from the eligibility path: duplicate detection scans the rows too The decoder still built a local Map for its duplicate-key check, and its declared return type reached the `Map<TargetCapabilityKey, _>` alias -- so the PartialFunction-in-type-position versus im::HashMap-in-expression-position fork was still producing E0308s from the one place the Map survived. The check now folds the rows, carrying the rows already accepted and refusing when a later row repeats an earlier capability key. Same refusal, same diagnostic, no Map. `TargetCapabilityEligibilityTable` and `target_capability_eligibility_empty` are deleted -- nothing refers to them. Measured on the target_model board (same entry, same probe, PROBE_EXPECT_BASE_SHA armed on every arm): main 1ebac31 189 rustc errors contract added 9395926 203 (+14) index unstored 69ff5f4 199 Map dropped <this> 196 before this commit The remaining delta over main is E0308 only; every derive-class error (E0277 Debug, E0369 ==) is back to main's count. Final figure for this commit reported separately with its ref. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Duplicate detection was quadratic twice over: one keyed accumulator replaces the scan and the copied append Self-raised against this PR rather than shipped quietly. §6 is explicit that a quadratic fold is always fixed regardless of the realized n, and "there are only a handful of capability rows" is precisely the defence it rejects. Removing Map from every DECLARED type position is what this PR is for -- it took the rustc-error regression from +14 to +3 -- and the duplicate refusal was re-implemented over the row list to preserve it. That preserved the refusal and introduced two cost defects, both named in §6's own sentence: target_capability_eligibility_lookup(rows: seen, ...) O(n) scan per row list_append(left: seen, right: [row]) copied accumulator so the accumulator was O(n^2) on both axes where the predecessor's map_insert was neither. The fix keeps the ban intact, because the ban was on Map in DECLARED positions, not on Map: the seen-set is a fold accumulator whose type is inferred from empty_map() and never crosses a signature. The enclosing fn still returns List<TargetCapabilityEligibilityRow>, and the file already uses map_insert / map_lookup this way in six places. No refusal changes -- a duplicate capability_key still rejects with the same typed diagnostic at the same node. target_capability_eligibility_no_rows is deleted; the change was its only caller. target_capability_eligibility_lookup stays: its other caller does a single lookup over the row list, which is O(n) once, not a quadratic fold. Measured: 0 blocking errors, advisories 137 -> 136 (the deleted helper). NOT VERIFIED AT THE RUSTC LEVEL, and this is a gap rather than an omission: the emitted seed does not compile until the PartialEq well-formedness propagation lands, so the end-to-end rustc count cannot be measured on this branch today. Queued behind that blocker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pdScziA7qwW3dqMP1B4Zq * Install the emitted stage0 mirror for the re-homed capability alphabet: first mirror for extdeps_languages_rust_capabilities, regen fixed point restored * Re-home main's two new Ord-propagation call sites onto RustCapability, drop duplicated imports, restore the regen fixed point --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
#8428 hand-authored
expected_red_roster_join.rs(378 lines) with no.dagauthority and hand-edited the generatedlib.rspub-mod list to register it — DESIGN §5's "manual application committed as source" scaffold tell. A clean regen (main_wet/regen_stage0) recomputeslib.rsfrom the crate-layout authority, which didn't know about the file, so the pub-mod line was silently dropped and the build failed E0433 on any clean-regen tree.This models the module in
src/v1/expected_red_roster_join.dagsov1_compiler_expected_red_roster_join.rsis compiler-emitted (final construction, not a patched crate-layout row), deletes the hand-authored.rs, and registers it instage0_crate_layout.dag'sseed_retained_intrinsic_registrationswithhas_pub_mod: true. The legitimate hand-authoredbin/expected_red_roster_join.rsDoor (CLI entry point, a separate file) is untouched.While re-verifying with
claim_executor --required-regen, found and fixed two independent bugs inrequired_regen_host.rsthat blocked running the regen check at all on a clean tree:write_emitted_treeunconditionally rustfmt-normalized every emitted entry, including the non-RustCargo.tomlartifact from crate-layout emission, crashing on[package].verify_hand_maintainedwrote scratch normalize files intocandidate_dirbefore that directory was ever created.Note: the immediate E0433 symptom this PR targets was independently patched on main in the meantime via #8476 (crate-layout
has_pub_mod: truerow, without converting the file to a.dagauthority). This PR is still worth landing on its own merits — it replaces the hand-authored scaffold with the final construction DESIGN §5 calls for, rather than leaving a patched-but-still-hand-maintained file in place. It does not block or conflict with any other in-flight regen work.Test plan
claim_executor --required-regen --source-root dag --source-root src/v2run remotely (ctrl-build) against this branch merged with current main: the tool now runs to completion (previously crashed on the two host bugs above) and reports no drift or missing-registration issue forexpected_red_roster_join/v1_compiler_expected_red_roster_join.v1_compiler_expected_red_roster_join.rsis present, compiler-emitted, and registered withhas_pub_mod: trueinstage0_crate_layout.dag; the old hand-authoredexpected_red_roster_join.rsis deleted.cargo build --release -p v1-compiler --bin gunbc/--bin claim_executorboth succeed on this branch (remote release build, ctrl-build).