Skip to content

Preserve phantom marker identity across Rust emission - #9915

Merged
gunbai-bot[bot] merged 11 commits into
mainfrom
session/neat-otter-332-phantom-marker
Sep 1, 2026
Merged

gunbai-bot[bot] merged 11 commits into
mainfrom
session/neat-otter-332-phantom-marker

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

Outcome

Rust emission now preserves a unit-variant phantom marker's declared identity whenever that identity occurs as the immediate argument of an applied type. Measure<Time, S, Nat> therefore projects as Measure<Time, S, i64>, consistently across all five outer renderer positions, instead of collapsing the marker to () in some positions while rendering its parent Quantity elsewhere.

The same canonical TypeSurfaceOccurrence walk carries the immediate-edge AppliedTypeArgument fact into import emission. Marker occurrences and non-markers form one disjoint, exhaustive partition before generic variant classification; a marker cannot also reach is_known_variant or import_variant_parent_for_name.

This is admitted maintenance of frozen v1 because it directly serves the v2 self-host program: the Measure transition cannot reach a Rust-consistent projection while one declared identity is rendered two ways by position.

Exact semantic corrections

  • CostAccount.time: before, Measure<Time, S, Nat> erased Time to (); after, the declared Time marker identity survives.
  • cost_account_measured: the same before/after identity correction.
  • Remote use lines: before, an applied marker could be reclassified as its parent value variant and receive no marker binding; after, applied-argument identity produces the direct marker import.
  • Record-field traversal now reaches applied arguments inside declared child fields and variant payloads without widening to function/body children or to every type-position name.

An earlier marker-before-kernel ordering edit was removed after executed carrier measurement falsified its premise: Time already survived that step and was lost later. The final repair is a partition, not precedence.

Evidence and measured radius

Frozen base: baeabbbf807fb54361ca52c4a5a3fbeffb76473e (one non-seam extdeps hardware-documentation commit behind main at adjudication). Accepted authored composition head: eb51107a601c475d1c5c1782b5e6c17b7c30a928. Atomic finalized head: 9f17d19ce525084c6f8586880a18808935916dd3.

  • Final reviewed radius: 11 files, 128 hunks, +690/-161. The accepted emitter composition was 12 files/129 hunks before review; review 58131 removed the fixture-local Quantity authority and moved that fixture onto canonical std.measure, reducing the path/hunk count by one while the emitter/projection partition remained unchanged.
  • Textual census: 123 Measure quantity-marker references. Executed semantic projection changed two generated consumers; the other two generated changes are the projections of the two emitter authorities.
  • Projection roster join: 151/151 identities, equal both directions (150 GeneratedSurface, including the non-Rust manifest, plus main.rs). An earlier 223 count conflated directory files with admitted surfaces and was superseded by the independently derived roster.
  • Occurrence-grain partition in std.realization_schedule: 58 identities, 13 Time marker occurrences and 45 non-markers; disjoint, exhaustive, no duplicates. All 13 decisions deduplicate to one remote import identity.
  • Exactly one live marker partition exists across the generated corpus. The fixtures are therefore the substantive coverage; this is not presented as broad corpus coverage.
  • Producer bootstrap lineage: landed-base D0 -> C1 (two emitter projections) -> D1 -> C2 (exactly std_measure.rs and std_realization_schedule.rs) -> D2 -> C3. C3 is equal over all 149 compared Rust surfaces with zero drift.
  • The four final generated paths were installed from exact C2 under a bounded identity-and-digest bridge: installed set equals admitted set both directions and all four destinations are byte-equal. Cargo.toml was neither offered nor applied.
  • Complete emitted candidate crate passed cargo check.

Mutation evidence terminates at emitted-target compilation, with a single canonical positive build reused rather than duplicate positive executions:

  • Withheld import partition: emitted target refuses for missing remote marker bindings; restored partition imports Time/One distinctly and compiles.
  • Erasure mutation: Time and Memory both become (), so the semantic assertion fails even though Rust compiles; corrected projection preserves both identities and compiles.
  • Scope mutation: the assertion concerns the occurrence-to-import relation. The broad classifier wrongly imports a non-applied marker; the positional classifier excludes it while a genuine applied-argument control remains included. Compiler outcomes are observations, not pass conditions.
  • Parent-boundary control proves the broad arm's shallow compilation was fabricated plausibility: using the field as its declared Quantity parent refuses with E0308 (expected Quantity, found Time). The positional arm exposes the separately filed E0573 projection gap.

Claim boundaries and supersessions

The final scope position supersedes two earlier claims: first, that no target-valid broad-only specimen existed; then, that the broad specimen's compilation preserved meaning. Executing the parent relation established that the broad arm merely compiled by substituting a marker struct for the written variant.

Three claims remain deliberately separate:

  • This PR's scope witness owns whether a marker import is justified by occurrence position.
  • node://adhoc-8fc6d673-7f1 owns accepted source producing a non-compiling target at a non-applied unit-variant position.
  • The Measure target-validity pair owns applied-argument marker identity producing a compiling target.

The meaning-level two-arm discriminator was executed but is not enrolled on an acceptance path. The next-rung trigger is a fixture-callable emitted-crate compilation route running unconditionally on an acceptance path, executing these two emitter arms to rustc termination over a synthetic closure and comparing their diagnostics. Owner: node://adhoc-da8c65c0-b3b. #9911's evolving test-facing route is ignored and outside the required aggregate, so availability alone does not fire this trigger. The enrolled rung remains the honesty witness plus corpus regeneration. The general emitted_bytes_witness_required_lane drop does not dissolve.

Fixed-point denominator and separate hazard

The fixed point is established over the true compared-Rust population of 149. Cargo.toml is declared as a GeneratedSurface but is excluded from comparison, changed_paths, planning, and fixed-point digests by is_compared_generated_basename, with no typed disposition. This fixed point makes no claim about it, and this change alters neither its authority nor destination bytes.

That pre-existing instrument/install hazard is routed separately as node://adhoc-09827eb8-29f: the low-level copier has no extension guard, so the upstream .rs comparison filter is currently the accidental protection against installing the bare Cargo.toml identity as foreign src/v1/stage0/src/Cargo.toml debris. An earlier packet statement incorrectly joined that bare identity to the package-root src/v1/stage0/Cargo.toml and overstated the harm as overwriting the hand-maintained manifest; the installer actually joins basenames under src/v1/stage0/src. The denominator loss and missing disposition remain, but widening that population alone does not overwrite the package-root manifest.

Alias-root review follow-up

Native review 5078318459 found the same position-dependent identity class at a second rendering path: the alias-RHS root and its applied children shared a context-free marker decision. The reviewed repair makes the position structural. render_rust_alias_rhs_type is the non-applied root entry and cannot reach rust_type_arg_identity_spelling; only render_rust_alias_rhs_applied_arg, entered by an immediate applied child, can consult it. The paired one-module witness keeps AppliedAlias = Box<Time> beside BareAlias = Time, so the applied child must retain Time while the bare root must not borrow that marker identity.

The successor currently emits AppliedAlias = Rc<Box<Time>> and BareAlias = (). The latter is not asserted to be semantically correct: it is only evidence that the non-applied root no longer selects the marker. It reaches the ordinary value-variant collapse and the target still refuses at that position. That accepted-source/non-compiling-target behavior belongs to node://adhoc-8fc6d673-7f1 / #9909 and is deliberately outside this PR. The witness requires the applied child to retain Time, requires the bare alias declaration to exist, and forbids the bare root from borrowing either fixture marker (Time or Memory). It deliberately does not constrain the bare RHS to today’s known-wrong () fallback; rustc diagnostics are recorded outcomes, not invariants.

Final follow-up head: 061d4c3a558c600d5fad3e0e449bbd1288476516. The one admitted projection v1_compiler_emit_rust.rs was installed under a one-path identity-and-digest bridge; candidate and destination SHA-256 are both 2b8c5726cfffd6b7c15b3928f03a6970a686833d233b6591ca16be99baeb2534. Cargo.toml was neither offered nor applied. Exact-head regeneration reports first_generation_equal=true, changed_paths=[], and 149/149/149 over the bounded compared-Rust population.

@gunbai-bot

gunbai-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Addressed both findings from review 58131 at bae7e013af5b:\n\n- Deleted the fixture-local Quantity = Time | Memory authority. The non-applied consumer now imports canonical Quantity and Time from std.measure; the focused seven-source witness closure compiles with zero blocking diagnostics.\n- Replaced the prose-valued ceiling datum with a typed carrier that separately records enrollment standing, enrolled boundary, a DissolutionCondition capability/execution trigger, and a branded route owner. The trigger explicitly does not fire for a merely callable or ignored test.\n\nThe review changed the exact radius to 11 files/128 hunks/+690/-161, now stated in the PR body; emitter and generated projection bytes are unchanged. — sent from neat-otter-332

@gunbai-bot

gunbai-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Review 58141’s duplicate-call observation is correct: render_rust_applied_type_arg evaluates the same pure identity lookup twice. I am leaving it unchanged in this transaction because removing that redundancy would alter the emitter authority and generated projection after the semantic composition and digest-bound evidence were accepted; it is an efficiency cleanup with no bearing on the identity correction, and would create a fresh cause/radius solely for polish. It should be a small follow-up against the landed emitter. — sent from neat-otter-332

@gunbai-bot

gunbai-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Correction to the separately routed Cargo hazard: the manifest identity is bare Cargo.toml, and the convergence installer joins it under src/v1/stage0/src. Population widening would therefore create foreign src/v1/stage0/src/Cargo.toml debris; it would not, by itself, overwrite the package-root hand-maintained manifest. My earlier statement fused a valid byte-semantic comparison with the wrong destination join. The .rs denominator loss and missing typed disposition remain unchanged. PR body corrected; Measure behavior/evidence is unaffected. — sent from neat-otter-332

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES at exact head bae7e013af5cc1c267417bc8075d56a6a5597de1.

Blocker — applied-argument marker semantics leak into a plain alias RHS

The ruled invariant is positional: a unit-variant identity becomes its Rust phantom marker only when the occurrence's immediate parent edge is AppliedTypeArgument. The import path now carries that fact, but the renderer still does not.

In render_rust_alias_rhs_type, the zero-child leaf arm calls rust_type_arg_identity_spelling(...) unconditionally. That function admits a visible unit variant (and the existing width phantom forms) without receiving any position. render_rust_alias_rhs_type is used both as the top-level renderer for an alias declaration's RHS and recursively for children of an applied RHS. Therefore a root leaf such as type BareAlias = Time reaches the same marker arm as the Time child in type AppliedAlias = Box<Time> even though only the latter has an applied-parent edge.

This is the exact positional conflation this PR says it removes, one renderer later. The existing non-applied control covers a record field and its use-line population; it does not exercise the plain alias-RHS leaf arm.

A discriminating fixture should put both forms in one emitted module, for example:

type Quantity = Time | Memory
type Box<Q> { value: Int }
type AppliedAlias = Box<Time>
type BareAlias = Time
fn bare_alias_as_parent(value: BareAlias) -> Quantity { value }

AppliedAlias must select the marker. BareAlias must not. Keeping both in one module is load-bearing: the valid applied use makes the Time marker ZST available, so an incorrectly marker-rendered bare alias can look plausibly compilable until the parent-boundary control exposes the substitution.

Re-review bar

  1. Make root-versus-applied-child position structural at the alias renderer seam: either thread a closed/Boolean position through render_rust_alias_rhs_type, or introduce one applied-child wrapper. Top-level alias calls enter non-applied; recursive applied children enter applied. rust_type_arg_identity_spelling must be unreachable from a non-applied root leaf.
  2. Add the paired alias-RHS discriminator above, with the occurrence/render assertion and real target-compilation outcomes reported honestly. Do not freeze the separately filed non-applied projection diagnostic as the invariant.
  3. Audit every production call of rust_type_arg_identity_spelling; each must be justified by an actual applied-argument edge, not merely by being somewhere inside a type renderer.
  4. Regenerate from the corrected authority and repeat the exact-candidate evidence: occurrence partition, projection-roster identity join, target-validity and Time/Memory pairs, fixed point, producer-rooted install bridge, and exact-head CI. The present digest-bound receipts do not carry across a change to 05_emit_rust.dag and its generated projection.

The current CI, fixed point, 151/151 surface join, and external provider approval do not answer this arm because no current corpus member occupies it and none of the submitted fixtures authors it.

@gunbai-bot

gunbai-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Addressed native review 5078318459 at 061d4c3 after reproducing the defect on the exact prior emitter bytes. The alias-RHS renderer now has separate structural entries: the non-applied root cannot reach rust_type_arg_identity_spelling, while immediate applied children enter the only wrapper that may consult it. Added the requested same-module AppliedAlias/BareAlias discriminator. The successor preserves Time for the applied child and prevents the bare root from borrowing it. The bare root currently falls through to the ordinary () collapse; the PR does not claim that spelling is correct, and records the remaining accepted-source/non-compiling behavior under node://adhoc-8fc6d673-7f1 / #9909. Exact-head regeneration is equal with no drift (149/149/149). Please re-review the new head. — sent from neat-otter-332

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES at exact head 061d4c3a558c600d5fad3e0e449bbd1288476516.

The original alias-RHS blocker is technically fixed. The root/applied-child split is structural: render_rust_alias_rhs_type no longer reaches rust_type_arg_identity_spelling, refinement recursion remains root-to-root, and the new render_rust_alias_rhs_applied_arg is entered only while rendering an immediate applied child. The five-call production census now has five applied-child justifications. The duplicate helper evaluations noted by review 58223 are a nonblocking cleanup.

One blocker remains in the enrolled discriminator. alias_root_does_not_borrow_applied_child_marker_identity requires the exact positive substring pub type BareAlias = (). The PR body correctly states that this is still wrong output—the ordinary value-variant erasure—and that the emitted target still refuses. But the machine-level witness nevertheless makes that known-wrong projection required green. Not asserting E0308 is insufficient: pinning the exact () bytes freezes the mechanism of the separately filed accepted-source defect and will turn its eventual repair into a regression against this witness.

The alias class does not need to be repaired in this PR. Narrow only the witness oracle to the fact this PR owns. For example, require the applied alias exactly (AppliedAlias = Rc<Box<Time>>), require that a BareAlias declaration is present, and exclude marker borrowing (BareAlias = Time, and any other fixture marker identity) plus applied erasure (AppliedAlias = Rc<Box<()>>). A small dedicated predicate extracting the bare alias RHS and proving it is not one of the fixture's phantom marker identities is also acceptable. Do not require the current () fallback.

That preserves the two-sided discriminator: erasing both positions still fails because the applied alias must retain Time; borrowing the applied marker at the root still fails because the root may not be a phantom marker. It also permits the independently filed type-position wall to replace () with a refusal or correct realization later without first weakening a green test.

Because this correction can be confined to the witness file, the emitter authorities and generated projections may retain their existing digest-bound receipts if they remain byte-identical. A fresh exact-head CI receipt and review state are still required.

@briansrls
briansrls dismissed their stale review September 1, 2026 15:30

The original alias-RHS positional blocker is closed at exact head 061d4c3. This review is superseded by exact-head review 5079648914, whose narrower witness-oracle blocker remains controlling.

@gunbai-bot

gunbai-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Addressed native review 5079648914 at fb9b8c3. The witness no longer requires the known-wrong BareAlias = () bytes. Its positive arm requires AppliedAlias = Rc<Box<Time>>, the BareAlias declaration prefix, and the parent return; its negative arm rejects applied erasure plus either BareAlias = Time or BareAlias = Memory. Thus it remains two-sided without freezing the fallback or a rustc diagnostic. This commit changes only the witness file. All emitter-authority and generated-projection blobs remain byte-identical to 061d4c3, so the digest-bound candidate, fixed-point, and install-bridge evidence carries unchanged. Please re-review the new head. — sent from neat-otter-332

@briansrls
briansrls dismissed their stale review September 1, 2026 15:45

Superseded by exact-head re-review at fb9b8c3. The witness-only successor removes the positive BareAlias = () obligation and applies the required prefix-plus-exclusions oracle exactly; no remaining technical blocker.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE at exact head fb9b8c3c643919d693f7e7853f6cb68b6d105f0c.

The successor from 061d4c3a558c600d5fad3e0e449bbd1288476516 is exactly one witness-file change, +2/-2. It removes the positive pub type BareAlias = () obligation and applies the required positional oracle: the applied alias must retain Time, the bare alias declaration must exist without a prescribed RHS, applied erasure is excluded, and the bare root may borrow neither fixture marker identity (Time nor Memory). This remains two-sided without freezing the separately filed non-applied projection defect.

The original production blocker remains closed: root alias rendering cannot reach the marker helper, while immediate applied children enter the dedicated applied-argument path. No sharper RHS extractor is required. The duplicate helper evaluations remain nonblocking.

Because this head changes only the enrolled witness and the emitter authorities/generated projections are byte-identical to the previously reviewed head, the accepted digest-bound fixed-point, candidate, and install-bridge receipts may carry under the ruled byte-identity condition.

This is technical approval of the exact subject. Merge readiness remains conditional on successful completion of the fresh exact-head CI run.

@gunbai-bot
gunbai-bot Bot merged commit 4859710 into main Sep 1, 2026
6 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/neat-otter-332-phantom-marker branch September 1, 2026 20:02
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