Files
ARCADIA-Studio/harness/analysis-mixed-acceptance-design-20260925/OWNERSHIP-SOURCE-MAP.md
T

5.7 KiB

Pending output ownership source map — proposal only

Source inspected: a629ae01d49bb3cb482a047eb41832ad4246a5c6; no compilation, source modification or acceptance claim. This refines only the lifetime seam in ACCEPTANCE-PROPOSAL.md, not equality/scratch policy. Paths below are relative to .local/as3batch at that commit.

Existing authority

crates/oa-core/src/language/analysis_source/mixed/project/ordinary_index/rename/emission.rs:6 owns PendingRename's bundle, exact Limits/ProjectLimits, retained Slots, original expression count and immutable desired Project reference. Its constructor at the end of emit_changed_unverified follows output reservation and explicit old-owner drop; no public bundle/slots constructor exists. Those private fields currently prevent sibling carried code from reading authority.

.../mixed/carried.rs:40 consumes CarriedInput into a bundle reference, one policy value and a slim guard. :63 derives C from that guard; :116 selects both producer modes. .../mixed.rs:39 stores the guard alongside the borrowed bundle and Budget; :308 is the shared parser. Consumed resolution at .../mixed/project.rs:453 retains that syntax. None of these owners currently needs desired's lifetime.

Recommend Candidate A with a complete pending reference

The smallest variant avoids projecting authority down to a bare &Slots at all:

// Private variants in the existing enums; no new allocating wrapper.
SnapshotBacking::Pending(&'s PendingRename<'s>)
GuardBacking::Pending(&'s PendingRename<'s>)

impl<'s> CarriedInput<'s> {
    pub(super) fn from_pending<'t: 's>(p: &'s PendingRename<'t>) -> Self {
        Self { backing: SnapshotBacking::Pending(p) }
    }
}

This is a proposed Rust shape, not a compiler-tested patch. PendingRename is covariant in its sole lifetime: the only use is desired: &'t Project, and all other fields own data without that lifetime. Consequently the longer desired borrow can be shortened to the pending borrow 's when storing p. The original pending value retains its original type/lifetime; no data moves or self-reference is created. Parser, resolved and indexed owner types keep their single existing 's. Immutable &PendingRename itself prevents mutation, consumption or dropping its bundle while syntax/guard remain usable. No trait object or PhantomData proof is needed, and future invariant lifetime-bearing fields would require revisiting this coercion rather than silently bypassing it.

Add narrowly visible immutable Pending methods bundle() -> &SourceBundle, policy() -> (Limits, ProjectLimits) and retained() -> Slots, restricted to pub(in crate::language::analysis_source::mixed). CarriedInput accepts only the complete pending reference, never those components as independent arguments. into_parts derives bundle/policy from its stored pending and transfers the same reference into GuardBacking::Pending; slots() calls that pending's retained method. Policy is copied once into the existing preparse transfer value and then Budget/syntax limits; the guard contains only one pointer, not another policy. Pending necessarily retains its original immutable policy as owner provenance. No recomputation of C, tuple authentication or runtime identity comparison helps.

Candidate B and visibility

Embedding an owned RetainedSnapshot in Pending would remove the cross-reference between carried and emission modules and also avoid desired lifetime covariance. It adds no necessary heap allocation, but replaces existing pending fields, changes emission construction and existing direct inspection tests, and requires a controlled production snapshot constructor or wider sibling field authority. That larger migration has no present ownership benefit over the complete pointer. Prefer B only if later genuinely shared owning snapshot behavior justifies it.

The module paths are already visible: ordinary_index.rs:433 exposes rename to analysis_source, and rename.rs:2 exposes emission likewise. Pending type itself has that visibility. Keep carried private to mixed; descendants can name its module. The needed changes are just its from_pending entry point and a named strong parse entry with visibility up to mixed, plus the three immutable pending views. Keep SnapshotBacking/GuardBacking variants and fields private to carried; do not export SnapshotPolicy or add arbitrary production RetainedSnapshot inputs.

Consuming verification and finite type checks

Implement verify in emission, where it can consume self and eventually move its private bundle. A local block calls the strong parser with from_pending(&self), consumes syntax into resolve, performs separately specified bounded equality, then drops resolved owner/guard before leaving that block. Only afterward move self.bundle into an owning accepted result. No parsed witness or desired borrow escapes, so accepted output has no lifetime parameter or self-reference. Failure returns diagnostics and drops self; successful no-op remains the separate old owner branch. This note does not select accepted-result extraction/installation.

Compiler acceptance must demonstrate: long-lived desired + local pending can produce a short scoped syntax; resolved owner cannot outlive pending; moving or mutating pending while the guard is subsequently used is rejected; dropping all verification borrows permits moving the bundle into the accepted owner. Positive runtime tests should drop original input and desired after acceptance and still inspect returned output. Preserve exact inherited policies and C once throughout; no new carrying-mode bypass or policy mutation. Any compile-fail examples should be narrow external snippets/appropriate harness, not runtime unsafe tricks.