Repository navigation
Infer a bare variant's instantiated owner from the expected type, not its declaration node - #8376
Conversation
… its declaration node
A bare variant reference inferred as its OWNER COPRODUCT'S DECLARATION NODE, whose
children are the coproduct's ARMS rather than type arguments. `type Optional<T> =
Absent | Present { value: T }` declares Absent as child 0, so a generic owner reaching
the renderer uninstantiated rendered `Option<Absent>` -- a constructor in type
position, not a Rust type. The emitter was rendering faithfully what inference gave it.
When the context supplies an expected type that owns the variant, that expected node IS
the instantiated owner, so it is adopted in place of the declaration node. The same
lookup already existed in the unresolved-name arm; it is hoisted to one authority so a
variant that RESOLVES gets it too, rather than only one that does not.
Adoption is deliberately narrow on two axes, both earned by a failure:
IDENTITY -- only when the expected type's own head names the coproduct resolution
already bound, so this instantiates the owner the binder chose rather than re-targeting
to a different coproduct declaring an arm of the same name (Absent is an arm of
Optional, ObservationVerdict and ConvergeVerdict alike).
CARDINALITY -- only when the expected node is Required. Optionality is not a wrapper
type here: `BinOp?` is a BinOp node whose return_cardinality is CardOptional, so a head
comparison cannot see it. For `binop: Mod` against `BinOp?` the head IS BinOp and the
arm IS found, but the constructor's type is BinOp and the optionality is a coercion the
emitter performs by wrapping; adopting there made the value look already-optional and
emitted `binop: BinOp::Mod` where `Some(BinOp::Mod)` is owed.
Two successive drafts shipped that wrapper loss across four extdeps.languages.*_syntax
modules and std.effects. Worth recording WHY it survived: the Option<Absent> count, the
whole-artifact diff of the emitted eval closure, and the rustc error census all stayed
green through both, because all three measure the eval closure while the damage was in
v1's OWN emitted sources. regen_stage0 --verify was the only instrument whose subject
included it.
Measured, emitted v2.compiler.05_eval closure, before -> after:
Option<Absent> sites 21 -> 0
rustc errors 494 -> 473 (-19 E0425, -2 E0573; no code increased)
whole-artifact diff 24/24 lines, fully accounted:
21 broken annotations repaired,
2 improved to concrete types
(Option<Rc<UriPercentEncodeRefusalCause>>,
Rc<NamedEdgeTargetLookup>),
1 Verdict annotation relaxed to `_`
self-host fixed point green (two generations)
Witness enrolls the CARDINALITY half, which is single-source constructible and is the
half both wrong drafts broke, with a required-field positive control so the repair is
not satisfiable by wrapping everything or by refusing every adoption. The headline
Option<Absent> case has no enrolled row and the note says so: it needs the v2 Optional
coproduct as a declared generic type AND an ambiguously owned arm name, but Optional is
not declared in the dag corpus (it is the built-in `T?` sugar) and two same-named arms
in one module are refused outright. Its evidence is the executed corpus measurement
above -- discriminating, but not recurring.
Rung, honestly: mitigatable, not structural. With no expected type inference still
falls back to the declaration node, so a declaration-shaped node can still reach a type
position. Dissolve-on: constructor ownership and constructor value type become separate
facts with a needs-context / refused arm, at which point the state is unwritable.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
One correction to the record, since acting on it would red the seed. The review reads the That is the instantiation firing on v1's own emitted sources — the fold init is a bare variant whose owner is now instantiated from the expected type instead of left as a declaration node. Because Worth flagging because it generalises: on a compiler change, a diff hunk in Related, and the reason I am confident about it: the fixed point caught this repair being wrong twice while every other instrument stayed green. Both earlier drafts dropped No change requested; the review's verdict stands. Recording it so the hunk is not tidied away later. — sent from gentle-dove-833 |
…ly served it (#8344) * Delete the 27-row self-host frontier roster and the machinery that only served it Operator ruling: the frontier roster is either derived from live state or it does not exist. It was neither -- 27 hand-authored rows whose measurement fields were ordinary parameters, so a row that claimed execution measurement was indistinguishable from one that asserted it. It attracted readers, it misrouted them, and it produced nothing. This deletes it at the root rather than pruning it row by row. WHAT THE DELETION PROVED, which is the part worth reading. Every consumer that looked load-bearing turned out to consume an empty projection: crate layout appended compiler_frontier_emitter_produced_stage0_mod_basenames(), a fold admitting only EmitterProduced rows. All 27 were SeedRetained, so the term was [] at every call and no emitted byte changes. wet enrollment appended a roster fold whose own gate, falsifier_self_host_wet_template_only_holds, asserted that term had length zero. crate partition named the roster as a dissolution target for module exports the roster could not have supplied -- rows carried a path and a disposition and nothing else. So the roster's real dependents were its own census tests. Those, the promotion and authorization machinery, and the per-module probe survey go with it. WHAT SURVIVES AND WHERE IT WENT. Crate layout is a separate concept that was squatting in the frontier module; it moves to v2.compiler.self_host.stage0_crate_layout with the registration rows and projections that actually produced bytes. The producer/qualification vocabulary in emitter_producer_provenance survives at half its size -- the EmitterProducer x EmissionQualification axes, the realized closure carriers, the receipt and its single mint -- because its live consumers (candidate_generation, the direct rust door contract, the production qualification lens) never read a roster row. EVIDENCE, PER DESIGN 4b. Deleted witnesses fall in two classes and both are stated in the carriers rather than here. Green-by-construction: seven crate layout witnesses guarded by a disposition match whose EmitterProduced arm was unreachable, or comparing zero to zero. Subject-retired: the authorization forgery controls proved an unauthorized EmitterProduced disposition was unwritable, and that disposition no longer has a representation to forge. Two claims survived and keep their controls: a V2Emitter receipt cannot be minted with the seed emitter in its realized closure, and the generated crate layout artifact must match its registration rows. ONE CLAIM IS GENUINELY RETIRED RATHER THAN CLIMBED, said plainly. transition_parity_host_index_agrees_with_hand_rows redded when the derived module index and the hand-authored qualified-module rows disagreed. Deleting one side of a duality retires the parity claim; it does not discharge it. The surviving authority is the path-module binding index, and the crate-partition dissolve target now points there instead of at the roster. The frontier_probe_survey bin is removed with its .dag surface and transport. Justified per bin, not by a class sentence, because an earlier change deleted four bins on one blanket justification and was reverted for exactly that -- see the second-removal paragraph in gunbc.ci_release_bins. NOT DONE HERE, named rather than left to be found: the frontier_probe subsystem (frontier_probe, frontier_probe_types, assemble_detail and their tests) still stands. It is the adjacent weed -- its subject was per-module roster measurement -- but it has independent test consumers and deserves its own cut. The plan carriers written in the roster's vocabulary (wave2_prep_design, v2_self_hosting) are quarry now, not authority, and are not rewritten here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Follow the bin deletion through build.rs and the generated workflow The build failed in 39s because deleting src/bin/frontier_probe_survey.rs left two references to it standing: build.rs still declared a rerun-if-changed on the file, and .github/workflows/ci.yml still passed --bin frontier_probe_survey to the release build and then asserted the resulting artifact existed at four verify sites and one tar site. ci.yml is a generated artifact and the honest way to update it is to regenerate it from gunbc.ci_release_bins, which is where the pack row was already removed. `gunbc ci` cannot run in this container -- the shim panics reading ci_layer_roots.dag out of a temp workspace -- so the eight occurrences are removed by hand and the drift gate is the check: it compares ci.yml against `gunbc ci` output byte for byte, so if this hand edit is not exactly what the generator produces, CI says so. That is the intended instrument for this rather than a local claim I cannot make. Stated because it is the kind of thing worth noticing rather than routing around: a hand-edited generated artifact is only acceptable here because a byte-exact gate independently checks it in the same run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Fix the parse error my own note introduced: nested double quotes in a .dag string The retained-kernel test gate failed with four panics, all the same: for_each_parsed_module_binding could not parse dag/gunbc/ci_release_bins.dag. The per-bin justification I added there quoted the earlier blanket sentence verbatim -- not "a probe bin whose subject was cli_run" -- inside a double-quoted string, which terminated the string mid-prose and left the remainder as garbage tokens. Worth noticing rather than just fixing. The failure surfaced four modules away from its cause, in a materialization-provider test whose subject is disk cache probes, because the whole-corpus module-path index parses every .dag file before anything else runs. So a prose edit in a bin roster reds a cache test, and the panic names the parse site rather than the reader. That is the same ordering property this program spent the afternoon on: what breaks first is not what is wrong, it is what runs first. The sentence now paraphrases instead of quoting. Checked the other nine multi-paragraph notes this change adds: each opens and closes exactly once, with the odd per-line quote counts expected of a string spanning blank lines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Two workflows still named the deleted probe bin: take the heal regeneration The frontier cut deleted the frontier_probe_survey bin and its row in the release pack, and I removed its eight occurrences from ci.yml by hand. fleet-converge.yml and falsifier.yml build the same pack from the same authority and still named it, so heal regenerated them and could not push workflow paths itself. These are its bytes, not mine. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Move the deletion rationale into an authored annotation: it is prose, not program data DESIGN 4c, enforced by prose_row_introduction_gate: this path's prose is already migrated, so a new data NAME_note: String row is refused. The note explains what the frontier cut removed from this module and what survived, which is exactly irreducible rationale about a construction's shape -- it belongs above the declaration it explains, not in a String the compiler must carry. Six sibling rows on out-of-scope paths were reported and not enforced; left as they are rather than widening the diff past the refusal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Delete the freeze rows and transport claims naming witnesses the cut removed The floor refused with StaleFrozenPathDeferral: two gunbc.witness_deferral_freeze rows named test decls the entry no longer declares. A freeze row left behind is not inert -- it becomes a standing exemption the next witness to take that name inherits, which is the refusal's own wording and the reason it is loud. Same two names were still enrolled as ClaimRun rows in the supply transport, and its note explained why one of them was there. Removed both and rewrote the note to say what happened to their subjects: the parity witness had the duality between the derived index and the hand rows as its subject, and the cut removed one side, so the claim is retired rather than dropped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Import the equality helper from its definer: the old path resolved by pool coincidence emitter_producer_provenance_witness_test imported schedule_witness_entries_structurally_equal from wet_receipt_enrollment, which neither defines it nor imports it. It is defined in seed_emitter_behavioral_wet_known_red_entries, a module this file already imports. The reference resolved on main only because some other member of the assembled closure had dragged the definer into the pool; the cut changed the closure and it stopped resolving, refusing the whole discovery corpus. This is the Class B accidental-coverage shape DESIGN records as an open thread — a bare cross-module reference binding by pool membership rather than by the importing file's own closure. Importing from the definer is the fix that does not depend on who else is in the pool. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Retire the frontier probe receipts with the roster they measured The cut deleted the two HandAuthoredDocBind rows for the frontier probe receipts but left the documents in the tree, so three files lost their only inbound reachability and became orphans. Deleting the bind rows was correct — every declaration they cite (frontier_probe_exact_head_closeout_note, frontier_probe_run_interruption_note, frontier_roster_provenance_constructor_inflation_note, compiler_frontier_receipt_totality_wall_holds) is deleted by this PR, so the binds would otherwise dangle. What was missing is the other half: a document whose entire subject is retired is retired with it, never left standing. Deleted with the rows: docs/probes/frontier_probe_exact_head_survey_2026-08-03.{md,tsv} docs/probes/frontier_probe_run_interrupted_2026-08-06.md docs/probes/diff_frontier_declared_vs_survey.sh (only input was the TSV above) docs/probes/run_frontier_probe_survey_per_module.sh The two scripts are frontier-probe transport and served nothing else. Two unrelated STR-RC-0 scaffolds cited the second one as a class exemplar; their comments now state the class without the pointer, so the deletion leaves no stale citation behind. This is the branch's own doc-graph defect, distinct from the five inherited rows main is currently red on (the root_b probe orphan, fixed by #8333). Same lens, same five row names, two different causes — which is why "those are the known inherited rows" had to be checked rather than assumed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Cut cleanup: the citations the deletion left pointing at nothing cursor review 52817 on #8344 named six stale citations to symbols and files this cut deletes. All six verified against the tree and fixed per site — a mechanical substitution across them produces sentences that parse and say nothing, which I did once already tonight and am not repeating. stage0_crate_layout_emit.dag the generated-artifact template still embedded 'Authority: v2.compiler.self_host.frontier' in both the .dag and .rs emit paths after the import was repointed, so the next regen would bake a deleted module name into two generated artifacts. Now names the real authority, v2.compiler.self_host.stage0_crate_layout. ci_layer_roots.dag witness_admission_offline_note dropped the deleted exclusion note from the paired list. ci_layer_roots.dag long_lane_exclusion_note dropped the 'Named consumer with file-grain exclusion row' sentence; both things it named are gone. ci_layer_roots.dag falsifier_self_host_wet_note the frontier-row flip no longer gates wet enrollment; says so, and points at the note recording that the term it fed was already empty. ci_release_bins_witness_test.dag note claimed two positive gap bins while the tests assert one. witness_deferral_freeze.dag the terminating-survey specimen is rewritten rather than removed: it did terminate, but by its subject being deleted rather than by reaching 27 of 27 receipts, and that is the disposition the freeze cannot express. Two more of the same class the review did not reach, found by sweeping every deleted symbol rather than fixing the six named: doc_graph_roots.dag the bind for this cut's own coordination document had primary_work pointing at v2.compiler.self_host.frontier_band_a_emit_readiness, a module this PR deletes. Repointed to the door-contract note already in its additional_works, which is the closest surviving subject. discrete_cost_derivation (.dag + .md) cited the deleted exclusion note as live evidence for the 'green CI implies coverage' claim. The claim stands; the specimen is now stated as one that has since been deleted with its subject, which is an instance of the pattern rather than a loss of it. Census after: every decl_name bound in doc_graph_roots resolves in the tree. An earlier run of that census reported two missing — both were my grep omitting 'func' declarations, not defects. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Cut cleanup 2: the deleted-MODULE citations the symbol sweep missed cursor review 52826. Two of its four findings were already fixed in 5921f90 (the emit template, the release-bins note); it ran on the older head. The other two are real, and they show the first sweep was keyed on the wrong thing: I swept deleted SYMBOLS, and a DeclarationRef names a MODULE PATH independently of whether the symbol it cites still exists somewhere. Sweeping module paths instead found three sites, one more than the review. stage0_rust_source_lifecycle_scaffold.dag hand_maintained_stage0_filenames_authority_ref still named v2.compiler.self_host.frontier while the import three hundred lines above had been repointed to stage0_crate_layout. Repointed. dissolution_migration_census.dag a NarrativeOnly residue row for a note in the deleted probe-survey module. Removed; the partition witness asserts sum-of-parts against the total rather than a literal count, so it stays true by construction. self_host_promotion_obligations.dag RE-HOMED rather than retired, and the distinction is the point. Both refs named the deleted frontier module, which made the bound trigger one that can NEVER fire — DeclarationAppears waiting on a module nobody will re-create is a permanently pending obligation wearing a checkable trigger, which is worse than an honest unbound one. The obligation itself survives the roster because it was never about the roster: the hazard is that a self-host promotion can be granted on evidence the v1 seed produced, and EmitterProducer still carries a V1SeedEmitter arm in v2.compiler.self_host.emitter_producer_provenance. So the subject moves there, the trigger keeps its declaration name and moves with it, and the 'n/27' framing — which really was roster-specific — is gone from the claim. Its witness needs no change: it asserts the bound and unbound arms stay distinguishable, and both still are. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Repoint two live references to the deleted frontier module cursor review 52843. Both name it as a LIVE authority, unlike the several prose sites that correctly say 'was carved out of' or 'was deleted with' — those stay, because a historical reference to a deleted thing is accurate. language_target_registry.dag Rust's TargetGovernedByContracts named the deleted module as its governing contract id. Repointed to v2.compiler.self_host.emit_coverage_frontier. Note that the row's own governing_contract_id_resolution_note explains this field carries a module name only because the real strategy authority lives in a private overlay and cannot be resolved from here — so the field is a stand-in either way, but a stand-in naming something that exists is strictly better than one naming something deleted. stage0_emit_plan.dag the disposition-authority note said the projection derives from the deleted roster's seed-retained facts. It derives from stage0_crate_layout's hand-maintained filename facts, which is where the carve-out put them. Deliberately NOT changed: cli_run.rs uses the string as a synthetic submodule name in a prefix-matching unit test. It tests string logic and never resolves the module, so it is not a stale citation — any name would do. My earlier sweeps missed both because they keyed on 'module_path:' fields and import lines. These are a contract_ids list element and prose. Third sweep form, and the one that should have been first: grep the bare module name in any syntactic position, then decide per site whether the reference is live or historical. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Regenerate the artifacts the authority-string change restamps cursor review 52843's first finding, and the one with teeth: I changed the emit template's authority string without regenerating what it stamps, so the committed artifacts and the template disagreed and generated_artifact_drift_gate would have refused. Ran the real generator rather than hand-editing generated files: gunbc run --entry dag/tools/generated_artifact_gate.dag --function main_wet It rewrote two artifacts with the new authority — and .github/workflows/ci.yml, which is the part worth recording. The merge earlier took the ours side of ci.yml purely to obtain a tree that builds, on the stated plan that regen would overwrite it by construction. It did: the generator produced MAIN's AUTHORED_CONFLICTS line, not mine. So the hand-picked side was wrong and would have shipped a workflow that silently dropped main's change. That is exactly the failure the generated-artifact merge driver refuses in order to prevent, and the reason the rule is regenerate rather than resolve. Still owed and dispatched separately: gunbc_stage0_crate_layout_generated.rs carries the same string but is emitted by regen_stage0 rather than by this gate, so it needs the stage0 regeneration, not this one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Regenerate the last artifact carrying the old authority string gunbc_stage0_crate_layout_generated.rs is the emitted Rust OF the .dag row this PR changed, so it is owned by regen_stage0 rather than by the generated_artifact_gate that produced the previous commit. Ran regen_stage0: 144 files written, exactly one changed, and it is this one. That single-file result is the receipt that the earlier gate run had already covered everything else it owns. Both regeneration paths now agree with the template, so the drift gate and the regen job have nothing left to refuse on this string. Instrument note, recorded because it is the fourth of its kind tonight: the subject-presence greps I printed beside this run were mangled by nested quoting — the pattern's second word was taken as a filename, so both reported 0 with a 'No such file' line above them. The numbers were garbage. The run is still trustworthy, but on the strength of what regen CHANGED, not on the checks I attached to it. A broken check that prints a plausible 0 is worse than no check, and this is the same family as reading a truncated tail: absence manufactured by the instrument, read as a measurement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Repoint to the right authority, and clear two more dissolution triggers cursor review 52854, both real. MY REPOINT WAS WRONG AND THE REASON IS THE ERROR I HAVE BEEN WARNING OTHERS ABOUT ALL NIGHT. I moved Rust's TargetGovernedByContracts to v2.compiler.self_host.emit_coverage_frontier because the name resembled the deleted module. It does not answer the same question: that carrier's own two-axis note says it answers axis (a), whether a witness body runs native, and explicitly disclaims axis (b), module self-emission. Picking it on name resemblance is precisely 18.2's finding — a name says the carrier was involved, not how — applied by me while citing it to someone else. Repointed to v2.compiler.self_host.emitter_producer_provenance, the surviving producer authority, which is also where the promotion obligation re-homed earlier in this PR. And the field's own note is updated: its stated purpose is a resolvable module a reader can open, so the note naming the deleted one made it false on its face while the field beside it had already moved. The note now records the wrong first choice rather than quietly showing the second — a reader deciding whether this field means anything is better served by knowing it was mis-picked once. seed_emitter_behavioral_wet_module_bindings carried two dissolution triggers whose subjects the cut removed: authorization waiting on 'witness-realization + frontier_probe_survey', and 'Frontier rows stay SeedRetained'. Both rewritten to name what actually remains — witness-realization alone, and the binding's own absence. A trigger naming a deleted subject cannot fire, which makes it strictly worse than honest prose. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Roadmap paths, and the plan carriers the cut decayed claude review 52858. The first finding is the serious one: STRUCTURED fields, not prose. THREE LIVE ROADMAP NODES pointed path: at the deleted file — v2-emitter- producer-provenance, v2-emitter-first-behavioral-module, v2-emitter-native- bootstrap, all active in gunbc.roadmap_authority. Repointed PER NODE from what each node says it does, not uniformly: producer-provenance -> emitter_producer_provenance.dag (its handback wants a result refused without a receipt from the run that made it — that module's mint wall) first-behavioral-module-> wet_receipt_enrollment.dag (handback is test results plus the updated list entry; the list entry was a roster row, and wet enrollment is what survived carrying per-module receipts) native-bootstrap -> v2_emitter_direct_rust_door_contract.dag (handback is two builds and the old compiler taken away) Picking one target for all three would have repeated the mistake in the commit before this one, where I chose emit_coverage_frontier because the name resembled the deleted module. Swept afterward: every path: in the roadmap now resolves on disk, the sole non-file being a dotted module reference. WAVE2_PREP_DESIGN IS MARKED SUPERSEDED RATHER THAN REPOINTED, and that is a disposition rather than a shortcut. Its entire mechanism section names the roster, its count, its baseline, its census attribution, its sweep order and its gate — all deleted. There is no mapping from a roster row to a replacement, so repointing eight symbols would fabricate an authority the document never had. DESIGN §3 rules that a plan authored while the deleted structure lived is re-read as quarry: its findings may be evidence, its sequencing is the old structure's gravity written down. The header now says so and tells the reader every symbol below names something gone. The other two plan carriers had specific enough claims to repoint per site. Residual live citations of the deleted module across all .dag: zero, counting only live references — the several prose sites that say 'was carved out of' or 'was deleted with' stay, because a historical reference to a deleted thing is accurate and sweeping those would be the mechanical substitution this PR has already had to undo once. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * The self-hosting tracker outlived its roster: declare the gap, do not refill it review 52867 caught v2_self_hosting.dag still presenting the deleted frontier.dag as the live roster carrier -- seven citations across the status line, the state-of-play census, two Wave 1 residual lists, the Wave 3 exit gate and the retirement condition. The claude review on the same head credited this file with quarry annotation it does not have, so the finding is real and the approval was wrong about it. Quarry-bannering it would be the wrong repair. wave2_prep_design earned that treatment because its whole mechanism section named deleted roster symbols with no surviving mapping; this file is the live sequencer for a program whose Wave 1 is still in flight. It is not superseded by the cut -- it merely cited what the cut removed. So: repoint to the surviving authorities, and where a claim was denominated by the roster, retire the fraction rather than re-author it. 0/27 and 27/27 both came from the same hand-authored row list, so both measured the roster's opinion of how many compiler modules exist. The substance survives (no module is self-emitted with a green equivalence receipt; every module must flip or be declared pinned-kernel) and is now stated qualitatively, with the derived denominator named as the first Wave 3 obligation. Restoring a count here would rebuild the weed inside the replacement, which is the failure DESIGN section 3 warns about by name. The frontier probe residuals are marked retired rather than outstanding: the survey never produced a receipt on any host including a dedicated runner, so its deletion costs machinery, not evidence. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 --------- 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> Co-authored-by: gunbc-ci-auto-heal <bts53@scarletmail.rutgers.edu>
…easured (#8367) * Plan status: Root A landed, Root D half 1 has no live owner, Root B measured The status table said Root A was 'unknown; under challenge' after it merged, and named vivid-wren as owner of a Root D whose halves have different owners and different states. A shared coordination document that is stale about what landed sends the next reader at finished work — which happened to me tonight: I dispatched a duplicate work item for Root D half 1 off this table before finding PR #8350 already at the merge bar with its author's session archived. A LANDED, #8347 as c4e9cc9. 12.5's challenge was RIGHT, which is why what landed is not what 12.5 proposed: a fused-map split, not the coproduct-skip edit the retracted diagnosis pointed at. The skip is still there and still deliberate. Recorded with two receipts — the stage0 regeneration the first push missed, and the two regen runs that reported a perfect fixed point while compiling a tree that never contained the fix. D split by owner: half 2 landed; half 1 is #8350, at the merge bar, no live owner, shepherded here. B 18.3 adds smart-ibex's executed flip: 211->204 errors, 203->196 sites, 195 common / 8 removed / 1 added, containment 0-of-18 disjoint. The 43-site renderer-inconsistency reading and the +18 reassignment are RETRACTED — read off a different module's artifact, never reached a carrier. What survives is sharper than the retraction: the leaf name Nat denotes two different types under two module authorities, so a census pooled across modules is keyed on a name that is not unique over the population it pools. Key on resolved type identity, not the printed name, and let a site carry more than one root. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Root D half 1 landed too — bbb5213, minutes after the row was written The row said 'at the merge bar, no live owner, shepherded here'. It merged while this PR was open. Recording it rather than letting a status document be stale about a merge inside its own review window — which is the failure the PR exists to fix, and it would be a poor look for the fix to exhibit it. Its author's session was archived before it landed, so the merge is also the receipt that an ownerless PR at the bar does not need a new session, only someone watching for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 * Strike the superseded instruction, and give half 2 its receipt cursor review 52846, both findings real. 12.5 said 'treat A as unpartitioned, not as diagnosed' immediately above the RESOLVED block this PR added, so the section told a skimming reader that landed work was still open. I appended a resolution without striking the claim it supersedes, which is the plan-ledger form of rung inflation — and doing it in the very PR whose purpose is status honesty. Struck rather than deleted: the instruction was correct when written, and the paragraph above it records WHY the then-current diagnosis was refused, which still governs. The Root D row claimed both halves landed while citing only half 1. Half 2 is 7cfeb6f (PR #8341), verified an ancestor of origin/main before citing it rather than copied from the review. Receipt added. Swept my own additions for the same class afterward: every LANDED claim in this diff now names a merge commit, and all four SHAs this document cites (bbb5213, 7cfeb6f, c4e9cc9, 6a3779d) are confirmed ancestors of origin/main. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwPMTY6Myy3scaMNn33cg5 --------- 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>
|
Recording two adjacent findings raised in review-adjacent analysis, with dispositions, so neither is silently absent. 1. The witness does not cover the generic-owner repair. Correct, and declared rather than discovered: the witness note says so explicitly and gives the reason. The headline 2. The expected-context-only arm bypasses the new guard. Also accurate as a description. Where the name misses locals, func sigs and global bindings, the arm adopts the PEELED It is pre-existing. This diff only extracted the inline lookup into Applying the guard there would be wrong. At levels 1 and 3 the guard falls back to a real binding, so refusing adoption is free. At this arm there is NO binding — the expected type is the only source of truth, and the failure path is The correct repair shape, if a live occurrence is found, is therefore NOT to refuse but to preserve cardinality — I am not making that change in this PR, deliberately. I have no observed live occurrence: the self-host fixed point is green over two generations and whole-corpus emission differs only in the 24 lines already accounted for, so the arm is not firing destructively on any current site. Changing a resolution-critical arm on a hazard I cannot exhibit, with no discriminating control, is speculative hardening of precisely the kind that cost two wrong drafts here already — both of which were green on every instrument except the fixed point. It belongs in a follow-up carrying its own witness, and it is recorded here rather than left to be rediscovered. — sent from gentle-dove-833 |
…ed no-binding arm
Review-driven follow-up to the previous commit, both findings acted on rather than
recorded.
IDENTITY. The owner guard compared `authored_name_at(exp) == owner_name` -- a spelling,
not an identity. It fails in both directions: one declaration reached through a
qualified spelling fails it, and two DIFFERENT declarations sharing a name pass it. The
dangerous arm is the second: given `a.Status = Ready | AOnly` and `b.Status = Ready |
BOnly`, a `Ready` bound from a.Status could be adopted against an expected b.Status,
silently retargeting the constructor and potentially masking a real type error. That
hazard was introduced by the previous commit, not pre-existing.
The repository already defines same-owner identity at the constructor-binding authority
(insert_variant_owner_checked): authored name PLUS declaration file and source start.
That triple is extracted as `same_owner_declaration` and both consumers now ask one
authority instead of two.
Comparing identity NAIVELY REVERTS THE REPAIR, and the measurement is the point.
Requiring name+file+start put Option<Absent> straight back to its full 21-site baseline;
a probe on name+file alone was also 21, which located the cause: expand_scrut_type_for_-
variant_lookup returns its subject unchanged once the connective is Disj, so `exp_enum`
is a USE-SITE node in the consumer module, never the owner's declaration. Comparing a
use site against a declaration can never match. Both sides are now normalised through
lookup_type_for before comparison, which restores 0 sites WITH identity enforced.
NO-BINDING ARM. The expected-context-only branch adopted the expanded node raw, and
expand returns an OPTIONAL subject unchanged -- exactly the state the cardinality rule
refuses two branches over. It is fixed with with_required_cardinality rather than by
extending the `Required` refusal there: that branch has no binding fallback, so refusing
would convert resolving programs into hard not-founds, and a fabricated refusal is
forbidden by the same rule as a fabricated success.
Measured, emitted v2.compiler.05_eval closure, before -> after (unchanged headline,
strictly more precise output):
Option<Absent> sites 21 -> 0
rustc errors 494 -> 473 (-19 E0425, -2 E0573; no code increased)
whole-artifact diff 43/43 lines, fully accounted:
21 broken annotations repaired,
~21 `acc: _` IMPROVED to concrete types,
1 Verdict annotation relaxed to `_`
self-host fixed point green in one generation
witness both rows green
The witness note gains the sharper coverage statement, which this change PROVED rather
than reasoned: both enrolled rows pass on the unrepaired baseline, so they detect the
repair over-reaching and cannot detect it ceasing to work. The identity draft above
silently reverted the repair while every row stayed green; only re-measuring the corpus
caught it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reverts the code of ece43db, keeping its witness-note finding. The review finding that motivated it is REAL and is NOT resolved by this revert -- it is deferred with a measurement, which is more than it had before. WHAT THE FINDING WAS. The owner guard compares authored names, not declaration identity, so two DIFFERENT declarations sharing a spelling can pass it and expected context could retarget a constructor. That hazard is introduced by the first commit and is real. WHY THE FIX IS NOT SHIPPING. Comparing declaration identity requires normalising both sides -- expand_scrut_type_for_variant_lookup returns a USE-SITE node once the connective is Disj, so a raw span comparison never matches and silently reverted the repair to its full 21-site baseline. Normalising through lookup_type_for restored the repair but introduced 16 incompatible-type errors across the corpus, because resolving to declarations makes the guard match through ALIASES and QUALIFIED SPELLINGS that the authored-name comparison declines -- so it adopts in cases it must not. Bisected: the no-binding cardinality edit is innocent (reverting it alone still gave 16); the identity comparison is the cause. whole-corpus compile, dag + src/v2, one instrument, three arms: origin/main incompatible-types 0 undefined-variable 32 first commit incompatible-types 0 undefined-variable 32 identity commit incompatible-types 16 undefined-variable 32 The 32 undefined-variable rows are pre-existing on main and are the control proving the read works. WHY THIS WAS NOT CAUGHT BEFORE PUSHING, which is the transferable part: every number in the first commit was measured on the EMITTED EVAL CLOSURE, and the compile-clean gate compiles the WHOLE CORPUS. This change alters inference for every bare variant reference in the tree, so the eval closure was never the right denominator for it. The self-host fixed point is also a partial denominator -- it covers v1's own sources, which is why it caught two earlier drafts and not this one. Whole-corpus compile is now run beside the eval emission for any inference change. State restored to the verified first commit, re-measured after revert: self-host fixed point green whole-corpus incompatible-types 0 (baseline 0) whole-corpus undefined-variable 32 (baseline 32, pre-existing) Option<Absent> in emitted eval 0 (baseline 21) witness both rows green Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
One correction to the record on review 52943, because it would close a finding that is still open. That review states the identity axis as:
It does not. A name comparison is precisely what PERMITS that case. Given The hazard is real, introduced by this PR, and deliberately shipped. Commit 2 attempted the identity fix and is reverted in commit 3 with the measurement: The 32 So the accurate statement of what ships is: the identity axis is a name comparison, it does not establish identity, and the retargeting hazard it admits is open. It is narrow (needs two same-spelled coproducts sharing an arm name, one imported and the other the expected type) and unobserved in the corpus — whole-corpus emission differs from baseline only in the accounted lines. That is a measured bound, not a proof of absence. I would rather ship the weaker guard with the hazard documented than the stronger guard that breaks 16 sites, but the finding is DEFERRED, not resolved, and a review artifact asserting the guard prevents retargeting is the one thing that could make it disappear quietly. Also worth flagging for anyone reading the approvals: they were given against the diff, while the head now carries an auto-heal commit whose parent is a merge of this branch into main — so the branch silently acquired 62 changed files under — sent from gentle-dove-833 |
…both positions The emitted 05_eval closure carried 151 of 483 distinct rustc sites in which a numeric scalar sat behind Rc. `Rc<i64>` is not a sharing decision, it is a category error: every arithmetic and comparison operator refuses on it, which is why one wrong decision produced many sites. THE RULE THAT PRODUCED THEM decides from two facts, neither about the carrier: membership by leaf NAME in shared_types, guarded by a string PREFIX test for "Rc<" against already-rendered text. So one carrier reached by two spellings is decided twice, and the prefix guard cannot see a layer through an alias. Measured on this base, where Nat realizes natively as i64: 172 scalar-wrap spellings, 12 literal `Rc<i64>` and 160 `Rc<Nat>` -- one category error in two spellings, both appearing on a single emitted line: measure_scale_fraction_floor<Q, S>(m: Rc<Measure<Q, S, Rc<i64>>>, num: Rc<Nat>, ...) the type argument rendering the primitive, the parameter rendering the alias. BOTH POSITIONS NOW CONSULT ONE AUTHORITY (rust_seed_host_numeric_alias, via the declaring file) instead of re-deciding from rendered text. Fixing only the parameter half first was measured and REJECTED: it left `Rc<i64>` in argument position and produced `Rc<i64> * i64`, an operator refusal neither uniform answer produces -- a mixed layer is worse than either. The applied-argument half sits in rust_render_checkpoint_scalar_bare, which despite its name applied the shared wrap after the scalar authority had already answered. RECEIPT, entry src/v2/compiler/05_eval.dag, base 0ce4ce6, site identity (file, code, normalized message) because emitted line numbers move: arm A -> arm B distinct causes 159 -> 148 error messages 539 -> 417 distinct sites 483 -> 361 (-122) scalar sites 151 -> 29 (-122) ADDED causes 0 (removal, not movement) emitted Rc<i64> 12 -> 0 Option<Absent> 0 -> 0 (merged #8376 not regressed) regen --verify divergence_count=0 SCOPE, stated rather than implied: this closes the NUMERIC scalar case, the whole of the measured Rc<primitive> population. It deliberately does not consult lookup_checkpoint, whose rows include non-scalar carriers such as String that may legitimately be shared; widening there is a separate cut with its own evidence. 29 scalar sites survive and are not claimed fixed. RUNG (DESIGN 4b): MITIGATABLE, and the ceiling is inherited rather than novel. rust_seed_host_numeric_alias keys on a NAME plus a declaring-file check, not on resolved declaration identity -- the same ceiling checkpoint_table_bypasses_identity_note records for the neighbouring table. This makes the numeric-scalar wrap not happen; it does not make a wrapped scalar unwritable. Next rung is the modeled layer transition wrap_decision.dag already names, at which point an agreeing flow is DERIVED rather than guarded. Also adds dag/tools/p1_emit_probe.dag, the producer experiment that settled which emitter to repair: the v2 emitter run under the v1 interpreter refuses at the FIRST bridge on a real module (parse_tree_to_emitted_node_no_matching_row -- zero grammar-relation rows match a real .dag token-class frontier), while the v1 emitter produces 92 files. So P0 remains the measured bootstrap producer and this repair is on the selected producer, not on the interpreter being deleted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…both positions The emitted 05_eval closure carried 151 of 483 distinct rustc sites in which a numeric scalar sat behind Rc. `Rc<i64>` is not a sharing decision, it is a category error: every arithmetic and comparison operator refuses on it, which is why one wrong decision produced many sites. THE RULE THAT PRODUCED THEM decides from two facts, neither about the carrier: membership by leaf NAME in shared_types, guarded by a string PREFIX test for "Rc<" against already-rendered text. So one carrier reached by two spellings is decided twice, and the prefix guard cannot see a layer through an alias. Measured on this base, where Nat realizes natively as i64: 172 scalar-wrap spellings, 12 literal `Rc<i64>` and 160 `Rc<Nat>` -- one category error in two spellings, both appearing on a single emitted line: measure_scale_fraction_floor<Q, S>(m: Rc<Measure<Q, S, Rc<i64>>>, num: Rc<Nat>, ...) the type argument rendering the primitive, the parameter rendering the alias. BOTH POSITIONS NOW CONSULT ONE AUTHORITY (rust_seed_host_numeric_alias, via the declaring file) instead of re-deciding from rendered text. Fixing only the parameter half first was measured and REJECTED: it left `Rc<i64>` in argument position and produced `Rc<i64> * i64`, an operator refusal neither uniform answer produces -- a mixed layer is worse than either. The applied-argument half sits in rust_render_checkpoint_scalar_bare, which despite its name applied the shared wrap after the scalar authority had already answered. RECEIPT, entry src/v2/compiler/05_eval.dag, base 0ce4ce6, site identity (file, code, normalized message) because emitted line numbers move: arm A -> arm B distinct causes 159 -> 148 error messages 539 -> 417 distinct sites 483 -> 361 (-122) scalar sites 151 -> 29 (-122) ADDED causes 0 (removal, not movement) emitted Rc<i64> 12 -> 0 Option<Absent> 0 -> 0 (merged #8376 not regressed) regen --verify divergence_count=0 SCOPE, stated rather than implied: this closes the NUMERIC scalar case, the whole of the measured Rc<primitive> population. It deliberately does not consult lookup_checkpoint, whose rows include non-scalar carriers such as String that may legitimately be shared; widening there is a separate cut with its own evidence. 29 scalar sites survive and are not claimed fixed. RUNG (DESIGN 4b): MITIGATABLE, and the ceiling is inherited rather than novel. rust_seed_host_numeric_alias keys on a NAME plus a declaring-file check, not on resolved declaration identity -- the same ceiling checkpoint_table_bypasses_identity_note records for the neighbouring table. This makes the numeric-scalar wrap not happen; it does not make a wrapped scalar unwritable. Next rung is the modeled layer transition wrap_decision.dag already names, at which point an agreeing flow is DERIVED rather than guarded. Also adds dag/tools/p1_emit_probe.dag, the producer experiment that settled which emitter to repair: the v2 emitter run under the v1 interpreter refuses at the FIRST bridge on a real module (parse_tree_to_emitted_node_no_matching_row -- zero grammar-relation rows match a real .dag token-class frontier), while the v1 emitter produces 92 files. So P0 remains the measured bootstrap producer and this repair is on the selected producer, not on the interpreter being deleted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…both positions (#8384) * A machine scalar is never raised to a reference layer: one decision, both positions The emitted 05_eval closure carried 151 of 483 distinct rustc sites in which a numeric scalar sat behind Rc. `Rc<i64>` is not a sharing decision, it is a category error: every arithmetic and comparison operator refuses on it, which is why one wrong decision produced many sites. THE RULE THAT PRODUCED THEM decides from two facts, neither about the carrier: membership by leaf NAME in shared_types, guarded by a string PREFIX test for "Rc<" against already-rendered text. So one carrier reached by two spellings is decided twice, and the prefix guard cannot see a layer through an alias. Measured on this base, where Nat realizes natively as i64: 172 scalar-wrap spellings, 12 literal `Rc<i64>` and 160 `Rc<Nat>` -- one category error in two spellings, both appearing on a single emitted line: measure_scale_fraction_floor<Q, S>(m: Rc<Measure<Q, S, Rc<i64>>>, num: Rc<Nat>, ...) the type argument rendering the primitive, the parameter rendering the alias. BOTH POSITIONS NOW CONSULT ONE AUTHORITY (rust_seed_host_numeric_alias, via the declaring file) instead of re-deciding from rendered text. Fixing only the parameter half first was measured and REJECTED: it left `Rc<i64>` in argument position and produced `Rc<i64> * i64`, an operator refusal neither uniform answer produces -- a mixed layer is worse than either. The applied-argument half sits in rust_render_checkpoint_scalar_bare, which despite its name applied the shared wrap after the scalar authority had already answered. RECEIPT, entry src/v2/compiler/05_eval.dag, base 0ce4ce6, site identity (file, code, normalized message) because emitted line numbers move: arm A -> arm B distinct causes 159 -> 148 error messages 539 -> 417 distinct sites 483 -> 361 (-122) scalar sites 151 -> 29 (-122) ADDED causes 0 (removal, not movement) emitted Rc<i64> 12 -> 0 Option<Absent> 0 -> 0 (merged #8376 not regressed) regen --verify divergence_count=0 SCOPE, stated rather than implied: this closes the NUMERIC scalar case, the whole of the measured Rc<primitive> population. It deliberately does not consult lookup_checkpoint, whose rows include non-scalar carriers such as String that may legitimately be shared; widening there is a separate cut with its own evidence. 29 scalar sites survive and are not claimed fixed. RUNG (DESIGN 4b): MITIGATABLE, and the ceiling is inherited rather than novel. rust_seed_host_numeric_alias keys on a NAME plus a declaring-file check, not on resolved declaration identity -- the same ceiling checkpoint_table_bypasses_identity_note records for the neighbouring table. This makes the numeric-scalar wrap not happen; it does not make a wrapped scalar unwritable. Next rung is the modeled layer transition wrap_decision.dag already names, at which point an agreeing flow is DERIVED rather than guarded. Also adds dag/tools/p1_emit_probe.dag, the producer experiment that settled which emitter to repair: the v2 emitter run under the v1 interpreter refuses at the FIRST bridge on a real module (parse_tree_to_emitted_node_no_matching_row -- zero grammar-relation rows match a real .dag token-class frontier), while the v1 emitter produces 92 files. So P0 remains the measured bootstrap producer and this repair is on the selected producer, not on the interpreter being deleted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Delete the P1 producer probe: the experiment answered, so its implementation goes dag/tools/p1_emit_probe.dag was branch-local experiment tooling. It asked one question -- can v2's emitter semantics serve as the bootstrap producer? -- and answered it by execution: P1 refuses at the first bridge (parse_tree_to_emitted_node_no_matching_row, v2.std.grammar), while P0 emits 92 files. That measurement selected P0 and is recorded in the PR receipt; the transport that produced it has no remaining consumer. Zero references to p1_emit_probe / p1_probe_eval / p1_probe_small_control exist outside the deleted module itself. Deleted rather than registered as a scaffold. DESIGN §5 rules that a dissolution condition describes how admitted debt ends and does not authorize creating it, so marking it would have required an operator verdict on this exact population -- and buying that verdict for tooling whose question is already answered spends review and maintenance time against a benefit of zero. The same section names the correct arm directly: the canary may run, produce measurements, and be deleted before merge, leaving the modeled facts the final route consumes. The emit-side repair is unaffected: the probe never entered any production path, and the fix's authority is src/v1/05_emit_rust.dag. Raised by cursor/composer-2.5 in review 53026 on #8384. --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
What
A bare variant reference inferred as its owner coproduct's declaration node, whose children are the coproduct's arms rather than type arguments.
type Optional<T> = Absent | Present { value: T }declaresAbsentas child 0, so a generic owner reaching the renderer uninstantiated renderedOption<Absent>— a constructor in type position, not a Rust type.The emitter was rendering faithfully what inference handed it. The fix is in
v1.compiler.infer: when the context supplies an expected type that owns the variant, that expected node is the instantiated owner, so it is adopted in place of the declaration node. The same lookup already existed in the unresolved-name arm; it is hoisted to one authority so a variant that resolves gets it too, rather than only one that does not.Measured — emitted
v2.compiler.05_evalclosure, before → afterOption<Absent>sitesWhole-artifact diff is 24/24 lines, fully accounted: 21 broken annotations repaired, 2 improved to concrete types (
Option<Rc<UriPercentEncodeRefusalCause>>,Rc<NamedEdgeTargetLookup>— a bareAbsentof a user coproduct, same class), 1Verdictannotation relaxed to_.Baseline sites: 17
v2_compiler_body_lowering_fold, 2v2_compiler_infer, 2v2_std_cardinality.Adoption is narrow on two axes, both earned by a failure
Identity — only when the expected type's own head names the coproduct resolution already bound, so this instantiates the owner the binder chose rather than re-targeting to a different coproduct declaring an arm of the same name (
Absentis an arm ofOptional,ObservationVerdictandConvergeVerdictalike).Cardinality — only when the expected node is
Required. Optionality is not a wrapper type here:BinOp?is aBinOpnode whosereturn_cardinalityisCardOptional, so a head comparison cannot see it. Forbinop: ModagainstBinOp?the head isBinOpand the arm is found, but the constructor's type isBinOpand the optionality is a coercion the emitter performs by wrapping. Adopting there made the value look already-optional and emittedbinop: BinOp::ModwhereSome(BinOp::Mod)is owed.Why that regression survived every instrument but one
Two successive drafts shipped the wrapper loss across four
extdeps.languages.*_syntaxmodules andstd.effects. TheOption<Absent>count, the whole-artifact diff, and the rustc census all stayed green through both — because all three measure the eval closure, and the damage was in v1's own emitted sources.regen_stage0 --verifywas the only instrument whose subject included it. A population that cannot disagree cannot falsify.Witness
Enrolls the cardinality half, which is single-source constructible and is the half both wrong drafts broke, with a required-field positive control so the repair is not satisfiable by wrapping everything or by refusing every adoption. Both rows green by execution; both assertions verified against real emitted bytes first.
The headline
Option<Absent>case has no enrolled row, and the note says so rather than leaving it to be discovered: it needs the v2Optionalcoproduct as a declared generic type and an ambiguously owned arm name, butOptionalis not declared anywhere in thedagcorpus (it is the built-inT?sugar), and two same-named arms in one module are refused outright. Its evidence is the executed corpus measurement above — discriminating, but not recurring.Rung, honestly
Mitigatable, not structural. With no expected type, inference still falls back to the declaration node, so a declaration-shaped node can still reach a type position — the bad state remains writable.
Dissolve-on: constructor ownership and constructor value type become separate facts with a needs-context / refused arm, at which point a declaration node has no route into a type position and this guard is replaced by unwritability.
🤖 Generated with Claude Code