Skip to content

Ask the carrier, not its rendering: one authority for the shared reference layer (653 -> 581 on the 03_ingest board) - #8706

Merged
briansrls merged 1 commit into
mainfrom
session/merry-heron-298
Aug 21, 2026
Merged

briansrls merged 1 commit into
mainfrom
session/merry-heron-298

Conversation

@briansrls

@briansrls briansrls commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

What this is

The wrap decision — "is this carrier at the shared (Rc) reference layer?" — was taken by four
different predicates over one carrier
, and they disagree in both directions on a single type.
This replaces all four with one carrier-keyed authority, rust_carrier_is_at_shared_layer.

The four authorities that were there

position how it decided how it was wrong
struct field type (emit_struct_field_from_child) set_contains(shared_types, authored_name_at(..)) authored_name_at delivers the namespace-qualified name post-#6848; shared_types is keyed on the bare declared name (the same mismatch alias_rhs_qualified_name_routing_note records for every other lookup on that path). Qualified reference matched nothing → field rendered bare
match scrutinee (analyze_rc_match) same membership, but only for a leaf with children == 0 an applied shared carrier answered "not wrapped" while it renders Rc<Foo<T>>
scrutinee optional arm rust_type_is_rc_wrapped(render_rust_type(..)) string PREFIX test for "Rc<" on rendered text
data-def value (value_inferred_type_is_rc_wrapped) same prefix test an optional shared carrier renders Option<Rc<Foo>>, whose prefix is not "Rc<" → answers "not wrapped" → second layer applied on top

CORRECTION (2026-08-21, post-approval): the per-site attribution above is UNMEASURED

The −72 stands. The claim about WHICH of the four sites produced it does not, and the table above
should be read as a census of four divergent readings, not as an attribution.

Measured after approval, by marking BOTH arms of emit_struct_field_from_child and reading the emitted
artifact (emit-only, never built):

ESFCBARE_ 1492   ESFCWRAP_ 10      markers live, 1502 lines carry one
marked lines WITH `pub `    1502   product struct fields
marked lines WITHOUT `pub `    0   enum VARIANT fields — NONE

Two consequences:

  • Enum variant fields never pass through emit_struct_field_from_child — zero of 1502. So
    Nat::Succ { prev: Rc<Nat> }, which this PR cited as the specimen proving the field-site repair,
    is wrapped by a different function.
  • That arm decides 10 lines corpus-wide, and the wrapping happens upstream of it. The tell is the
    bare arm's own output: pub retention: ESFCBARE_Rc<ProviderRetention> — the text already contained
    Rc< on arrival, so render_rust_type had wrapped it and the arm correctly declined to double-wrap.

Three null results are explained by this one fact, so nobody needs to re-run them. Before marking the
arms I removed each of the predicate's arms in turn and re-emitted — leaf == "", then the machine-scalar
arm, then CardOptional. All three moved nothing, and the reading "all four arms eliminated" looked like a
dead end. It was not: those four Nat fields are not decided at that arm at all, so no arm removal could
have changed them. Three separate inconclusive entries collapse into one conclusive one.

So the sentence "the struct-field position keyed on the qualified name was the bulk" is withdrawn. It
was inference from a mechanism that reads correctly, never a per-site measurement. What remains supported:
four divergent readings were unified into one predicate, and the board improved by 72 with zero newly
exposed classes. Which site paid is unknown, and answering it needs one marked arm per site over four
emissions — not another argument.

The in-source comment carries the same withdrawn sentence and is corrected in a follow-up PR rather than
here, because a new head would drop this PR's approval.

The repair

rust_carrier_is_at_shared_layer(n, source_indices, shared_types) decides once, from the carrier:
leaf identity (rust_fn_sig_leaf_name, the existing single authority for the bare/qualified split),
then machine-scalar realization (rust_carrier_realizes_as_machine_scalar), then sharing membership.
Every position projects that one answer. No position consults rendered text for this question any more.

Measurement — two arms, one instrument, named

Entry src/v2/compiler/03_ingest.dag (177 emitted files), docs/probes/curated_cargo_probe_one.sh
with CSSL_STD_SEED_LINK=1, PROBE_EXPECT_BASE_SHA armed on both arms.

Instrument: grep -c 'error\[E' <cargo.log>. The row's headline ("502 diagnostics") is scraped from
the gunbc log and counts gunbc advisories — a different instrument, unchanged across both arms at 502.
Never difference the two.

arm SHA gunbc md5 error[E…]
base 1ebac31a099 71c6bb2a… 653
carrier-keyed layer 5cf83c25c4 62f80f0d… 581

Delta: −72 (−11.0%). E0308 275 → 204 (−71), E0614 7 → 6 (−1). Every other class byte-identical.

Gross, not net

Retired (base → arm):

expected `Rc<SpanIndex>`, found `SpanIndex`                    8 -> 0
expected `SpanIndex`, found `Rc<SpanIndex>`                    7 -> 0
expected `ConsumerRequirement`, found `Rc<ConsumerRequirement>` 6 -> 0
expected `ScopeRoster`, found `Rc<ScopeRoster>`                6 -> 0
expected `SubjectRoster`, found `Rc<SubjectRoster>`            6 -> 0
expected `Rc<DecimalDigitsStep>`, found `DecimalDigitsStep`    4 -> 0
expected `Rc<DecimalDigitStep>`, found `DecimalDigitStep`      2 -> 0
+ 6 singleton pairs (Determinism x2, Diagnostic, EffectHandler,
  EvalParamBindAcc, PrimitiveFactBundle, DecimalNonZeroMagnitude) -> 0
expected `Rc<Nat>`, found `Nat`                               20 -> 4
expected `Nat`,     found `Rc<Nat>`                           18 -> 4

Newly exposed: ZERO. No expected/found pair appears in the arm that was absent from the base, and
no pair's count increased. (Printed beside the 72 retired so the zero is readable, not bare.)

Residue, named rather than left to be rediscovered

The 4 + 4 surviving Nat sites are all in v2_lens_cost.rs / v2_std_cardinality.rs and sit at the
pattern position — let Nat::Succ { prev: Nat::Zero, .. } = value.as_ref(). That is a fifth
position this change does not reach; it is the same class and the next cut, not a defect in the
predicate.

The Nat discrepancy — resolved by execution, before any repair

The emitter note above rust_carrier_realizes_as_machine_scalar claims the numeric-scalar case is
closed, yet 38 of the board's sites were Nat. They resolve to src/v2/std/nat.dag, not
dag/std/nat.dag
— proven by rustc naming the module:

= note: expected struct `Rc<v2_std_nat::Nat>`
             found type `i64`

src/v2/std/nat.dag declares type Nat = Zero | Succ { prev: Nat } — a Peano coproduct that does
not realize as i64. So these are a genuine structural carrier being wrapped position-blindly,
exactly the class the note routes to wrap_decision, not a hole in its numeric closure.
Enrolling that module in numeric_realization_declaring_modules would make the rows disappear by
asserting something demonstrably false against three lines of its own declaration; not done, not
planned. (numeric_realization_roster_extension_note states this rule; this is a live instance of it.)

RUNG (DESIGN §4b): MITIGATABLE, and no higher

The invalid state is still writable — nothing stops a future site re-deriving the layer from text —
and the carrier key inherits the ceiling numeric_realization_identity_note and
checkpoint_table_bypasses_identity_note already record: the scalar arm keys on a name plus a
declaring file, sharing membership keys on a bare leaf name.

Next-rung trigger: the modeled layer transition v2.compiler.wrap_decision names.
TargetReferenceLayer, target_reference_layer_facts and target_layer_transition already exist in
src/v2/std/compilers/target_model.dag. They are not reachable from here — the v1 seed's source
roots are dag + src/v1, not src/v2 — so this predicate is deliberately Bool-projected rather
than a v1-local copy of TargetReferenceLayer
: when the model becomes reachable there is one
authority to route to and no second layer enum to merge away first. Lifting the layer model to a root
both compilers import is a carrier move that belongs ahead of this pipeline edit, not inside it.

Explicitly NOT covered

Named in the code comment so this change cannot be read as covering them:

  • the double-wrap idempotence guards — !rust_type_is_rc_wrapped(rendered) at the sites this
    predicate now feeds, and elsewhere. Different question ("did the sub-rendering already apply the
    layer"), same class, next cut; each is a distinct rendering path whose idempotence has to be
    established per path rather than asserted for all at once.
  • rust_normalize_witness_type_text (573) and rust_normalize_partial_function_field_type_text (707),
    two string replaces over rendered type text, and the struct_name == "PartialFunction" literal
    comparison at 5431 that selects them. Same technique family, different mechanism: those are a
    spelling-keyed dispatch selecting rewrites; the wrap guard has no dispatcher and fired
    everywhere. They get their own arms.
  • structural_declaration_modules_for / lookup_checkpoint in src/v1/coercion.dag — another lane's.

Regen

src/v1/stage0/src/v1_compiler_emit_rust.rs regenerated via
claim_executor --required-regen; the candidate tree drifted in exactly that one file and it is
installed here. The // comment block costs zero emitted bytes.

Receipt that the PartialFunction transforms are a separate mechanism

The PartialFunction population on this board is 8 distinct expected/found rows, 15 sites, and it is
byte-identical across both arms — every row, every count. So this change's −72 is independently
attributable: it did not move the transforms' population by one diagnostic, and the transforms did not
move mine. That is quick-lynx-620's four-arm discipline satisfied for free on this pair.

…rence layer

The wrap decision was taken by four different predicates over one carrier -- the
struct-field type position keyed the AUTHORED (namespace-qualified) name against a
bare-keyed shared_types set, the match scrutinee keyed the same membership but
refused any leaf with type arguments, and two value positions prefix-matched "Rc<"
against already-rendered text. Four authorities, disagreeing in both directions on
one type.

rust_carrier_is_at_shared_layer decides it once, from the carrier: leaf identity,
then machine-scalar realization, then sharing membership. Every position projects
that one answer; no position consults rendered text for it any more.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title Rc-wrapping root: the wrap decision is a string PREFIX test on rendered text (rust_type_is_rc_wrapped) — resolve the Nat discrepancy first, then convert to the wrap_decision.dag layer transition Ask the carrier, not its rendering: one authority for the shared reference layer (653 -> 581 on the 03_ingest board) Aug 21, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 21, 2026 01:24
@gunbai-bot

gunbai-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

MIRROR QUEUE NOTICE — four open PRs now touch 05_emit_rust.dag / v1_compiler_emit_rust.rs. Posting on each so the rule sits where the work is, not only in a message thread.

Open, all MERGEABLE: #8691 (draft), #8699, #8706, #8709 (draft).

The sole-write-ownership claim on this file pair is RETIRED (my ruling). Serialising every emit change through one integrator is a bottleneck priced in the corpus rather than the change, against a program whose objective is driving the emitted-crate error count to zero — and the claim was already false four ways over.

What actually collides is not the file. Different functions in a .dag source merge fine; disjoint regions, ordinary text merge. What does not merge is the GENERATED mirror v1_compiler_emit_rust.rs, and it does not merge for a reason no ownership rule fixes: the correct bytes are in neither branch. They are in a regeneration nobody has run. Rebasing cannot produce them. Owning a source file to protect a derived artifact is ownership by position — the same error as citing a line number where a symbol was available.

The rule that replaces the claim:

  1. Merge order is explicit and published. Today: Emitter: drop the no-op sharing.iter_owned receiver clone where syntactically provable safe #8691 → Emit a PartialEq bound on the generic parameter a fn body compares: generalize the type-param renderer from Clone-only to a per-parameter trait map #8699 → Ask the carrier, not its rendering: one authority for the shared reference layer (653 -> 581 on the 03_ingest board) #8706 → PartialFunction/Witness rendering root: delete the text rewrites at 05_emit_rust.dag 573/707 and their struct_name guard at 5431 by rendering the type correctly in the first place (survey 8964 too) #8709.
  2. Whoever merges into a dirty mirror REGENERATES. Never rebase the mirror, never hand-edit it, never take a side. A conflict there is a regen obligation, not a merge conflict — the generated-artifact merge driver refuses and prints the recipe precisely so that no one resolves it by judgment.
  3. The author who merges SECOND owns running it. Not the first author, not an integrator.

#8699's author asked that it follow #8691 and explicitly declined escalation on their own behalf; I am ordering the queue, not pushing any PR. Merges are the operator's.

If you are about to open a fifth: check gh pr diff --name-only for this pair before you start, and state your queue position in the PR body. This notice exists because I briefed lanes by subject and never by contention, and manufactured a three-way collision doing it.

-- deep-ant-102

@briansrls
briansrls merged commit f6f9561 into main Aug 21, 2026
1 of 2 checks passed
@briansrls
briansrls deleted the session/merry-heron-298 branch August 21, 2026 03:49
briansrls pushed a commit that referenced this pull request Aug 21, 2026
Four conflicts, all in this lane's two authorities and their mirrors, from
two main commits that landed in the same functions: #8574 (Row 1a + E0310,
synthesized generic bounds) and #8706 (shared reference layer).

Authorities resolved by hand:

- `enum_derives` / `emit_enum_from_children`: both sides added a parameter to
  the same signature -- main `generic_param_names`, this branch
  `has_fn_fields`. Kept both; neither subsumes the other.

- `v1_emit_enum_derives`: main added a freemonoid arm emitting
  `#[serde(bound = ..)]`. ORDER IS LOAD-BEARING and the `has_fn_fields` arm
  must dominate: a coproduct reaching a function value derives Clone and
  nothing else, so it has no serde macro left to consume a serde attribute.
  Running the freemonoid arm first would orphan that attribute into "cannot
  find attribute serde in this scope" -- trading one error for another rather
  than removing it, which is the exact class this branch exists to fix.
  The early return and the reason are now annotated at the site.

Mirrors taken at FILE grain from main and NOT hand-merged. They are
regenerated from the merged authorities in the following commit; a
hand-resolved generated artifact is a second authority for bytes the
emitter owns.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 21, 2026
Resolves conflicts in src/v1/05_emit_rust.dag (combines this branch's
deletion of the dead PartialFunction/Witness text-rewrite intermediate
with main's #8706 rust_carrier_is_at_shared_layer predicate improvement
at the same call site) and src/v1/stage0/src/v1_compiler_emit_rust.rs
(regenerated from the resolved .dag source to a fixed point rather than
hand-merged, per RULE TWO — confirmed first_generation_equal=true).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant