Files
ARCADIA-Studio/harness/analysis-mixed-rename-execution-20260924/RENAME-EXECUTION-SOURCE-MAP.md
T

13 KiB
Raw Blame History

Mixed rename execution: minimal source seams and hazards

2026-09-24. Investigation only, against private base ee500908e3d77182ddd54e12524f9b6c6eb43b60 and the reviewed working rename planner. No implementation, Cargo, commits or Gitea actions. Current planning acceptance remains primary. Paths below begin at crates/oa-core/src/.

Recommended direction: consume the verified plan; validate the complete current snapshot; emit one owned complete bundle under the existing aggregate ledger; explicitly drop the old auxiliary owner; verify the output with the exact inherited per-snapshot policy and the surviving output reservation; return an owning bundle/model result after temporary verification syntax drops. Reuse parsing, resolution, validation and model equality. Do not reuse the public updater or add a second general edit framework.

There is no carried-baseline parser/resolver API today. Adding a baseline only to resolve would not satisfy the successor contract: output already coexists with parser allocations before resolution begins. This is the principal unresolved implementation seam.

Reusable pieces and necessary narrow changes

Actual seam Reuse / required change
ordinary_index/rename.rs:6–13,163–174,259–315 Plan owns the complete old witness, external desired borrow and two authenticated maps. Reuse its exact current-bundle check and combined sizing. Execution must consume this authority, not take independently supplied edits or a Budget. Line refs identify the reviewed draft; future formatting may move them.
analysis_source/update.rs:195–219 Useful copying algorithm: walk original sorted ranges, append untouched slices and replacement names, append tail. Do not directly adopt its numeric-file result, extra length map or independent Budget argument.
source_project.rs:19–23,52–59 Output owns entry: String and BTreeMap<String,String>; ProjectLimits includes file, include-depth, include-edge and model limits. All must survive; source-byte limit alone is insufficient policy.
analysis_source/budget.rs:6–14,36–64 Limits is Copy but private inside Budget. Add only a private read-only exact-profile extraction seam. A deliberate new snapshot gets a new Budget with those Limits; never zero or replace counters inside a still-live old witness.
analysis_source/mixed.rs:38–47,244–268 ParsedMixedSyntax retains ProjectLimits, Budget, canonical files and metadata. parse_with_profile preserves an explicit profile but currently constructs a fresh independent Budget; parse reconstructs defaults and must not be used for tightened-policy continuation.
mixed/project.rs:438–443 Resolver currently starts Ledger::default() then accounts syntax. A new private entry point must receive the parser's authenticated surviving reservation/baseline rather than fabricate another independent ledger. Keep the old wrapper behavior for existing callers.
mixed/project/accounting.rs:234–369 Reuse syntax traversal/lowering-count logic, but specify one owner for syntax entry/text reservations. If the new parser already reserved them, this routine must not charge the same retained storage again; its live walk slots and later lowering scratch still count.
mixed/project.rs:595–644 Actual validation transfers owned warnings after reservation and records actual static admission limits/usage. A narrow consuming extraction may move Project/warnings/metadata out and drop syntax/raw sites. Do not clone the desired Project or return old warnings as if output were re-admitted.

Output storage and original-coordinate emission

Let L be the planner's current live ledger (already old B plus R+M). Let F be complete file count, C the checked sum of final source-content bytes, and P = entry.len + sum(path.len) for copied output path strings. The new owned output requires at least:

O = Slots { entries: F, occurrences: 0, text: C + P }.

The owning SourceBundle struct itself is inline; entry text still counts even though the same path spelling also exists as a map key. Unchanged files are copied and counted. Reserve the whole checked O before constructing any output String/path/map entry, keeping L live. A per-file reservation can also be sound but adds more interleavings to verify. A currently built String can belong to its already reserved destination slot; document this rather than charging it inconsistently twice.

Repeat the streaming per-file sizing walk if necessary; no F-entry length table is required. Use the validated sorted original physical keys. Copy original slices and borrowed replacement names directly, without formatting, rescanning references or applying one name swap after another. Full Word spans preserve @/$, comments, whitespace, historical content and all non-name bytes. Allocation capacity is not the logical text metric, and with_capacity is not itself a budget check.

Keep separate checks for final content C under the inherited complete source-byte policy and live auxiliary text L.text+C+P under the ledger. Passing the former does not imply the latter. Conversely, parsed Usage.bytes is a work/input measure: do not add it as another owned source-buffer copy when O already accounts that buffer. Existing caller-owned old source and desired Project remain external borrowed memory under the established logical policy; this is not an RSS bound.

The immediate emission peak is L+O. After emission succeeds, save only required policy/metrics/E scalars and the desired borrow, drop old syntax/index/maps/names/edits, and only then release their reservations. Carry O forward as live storage. A fresh ledger that forgets O is incorrect even after all old auxiliary state is dropped. A private consumed handoff can move the ledger and release its known old subtotal; it should not expose a public factory accepting arbitrary caller-reported baseline Slots.

Why parser accounting is the consequential seam

Current mixed parsing has an intentionally staged policy:

  • lex.rs:20–55 charges source bytes/raw tokens, then allocates retained significant tokens. Token Usage is separate from auxiliary entries.
  • mixed.rs:96–97,277–283 charges ordinary syntax entries and checks initial file metadata independently.
  • Each whole file is lexed and parsed before metadata adds its tokens, value-end map, projected positions and lexical owners (mixed.rs:297–330).
  • ordinary_position_slots allocates its own traversal Vec before the projection reservation (mixed.rs:379–405); canonical BTreeMap→Vec conversion occurs at :374.
  • Shared Traversal owns folded-path validation strings, stack/active/visited/children containers and cloned paths/locations (source_project/traversal.rs:8–17,55–92,96–191), bounded through its existing ProjectLimits policy rather than the mixed Ledger.
  • Only later does accounting::syntax reserve metadata+Usage.entries, traverse decoded owned text and reserve its own work slots (accounting.rs:109–118,234–280), after resolver has started a new ledger.

Thus passing O only into resolve checks too late, and independently reducing a local metadata ceiling is not a complete proof: syntax entries, retained metadata, owned decoded text and parser scratch coexist. The narrow successor work must identify the parser's authoritative live subtotal, check O plus that subtotal before relevant allocation, and transfer that subtotal into the resolver without charging it twice. Work counters and auxiliary reservations need distinct handling; merely subtracting O from the Limits object would silently alter the per-snapshot policy and conflate domains.

Two compatible candidates merit consideration:

  1. Private carried-ledger parsing path: thread a private accounting context through existing mixed parser growth seams, retain its ledger in the syntax witness, and reuse resolver accounting with an explicit already-reserved-syntax handoff. Reuse actual lexer/parser/project semantics; do not create a second parser. This is the clearest proof but touches more than an emitter wrapper. Inventory token/AST/position text, temporary work and file-table transition overlap once.
  2. Conservative verification envelope reserved before parsing: potentially fewer parser changes, but only sound with a proved envelope for every parser/resolver temporary and text copy under the output/profile. The existing original metadata/E counts alone do not bound decoded-text copies, Traversal scratch or corrupted-output shapes. Reserving the whole current hard limit in every domain would frequently make any nonempty O impossible. Do not claim this shortcut is available without an independent bound and useful-cap evidence.

Prefer candidate1 unless candidate2 receives a concrete source-derived proof. The contract must explicitly state treatment of existing Traversal/projection/conversion scratch; adding new copied paths or a new temporary container cannot disappear behind an old exclusion. This is a bounded accounting decision at real allocation sites, not a request to redesign parsing or retroactively claim every existing caller had an aggregate parser ledger.

Actual output admission and final equality

Use the exact inherited Limits and ProjectLimits for the deliberate new parse. Original parse Usage/numeric units are historical metrics; output has separate measured counters. Preserve static admission policy and use the existing complete validation::validate_with_usage result, not a name-only check. The consumed-old-owner transition avoids needing two full syntax/index owners simultaneously; O remains live throughout new parsing, lowering, warnings and comparison.

No new typed or ordinary index is required merely to accept output: resolve/admit actual bytes, then compare the entire Project with normal PartialEq, including the renamed aliases/parameter names. Do not call the planner's same_project, which deliberately exempts those fields and would accept an admissible but incompletely renamed output.

Retain original E as a checked scalar before dropping the old witness. The plan already proved desired expression shapes equal to original; the intended target supplies the same frontier bound even when actual output is wrong. Reserve E against the new live verification ledger before full Project equality, release after its vectors drop. This is an additional comparison phase, not a reason to retain old raw arenas. Existing all-carrier signed-zero equality applies; non-name source-byte preservation comes from exact copying and byte oracles, not from semantic equality alone.

Malformed output must fail parsing/resolution; admissible-but-wrong aliases or another payload must fail whole-target equality. Failure returns only located diagnostics and destroys output/verification state. Do not debug-format arbitrary target expressions or adopt history/save before success.

Owning result without self-reference

A temporary inner verification scope can borrow the newly owned SourceBundle, resolve it, compare it, and then consume the resolved owner into owned Project, warnings and copied policy/usage metadata. Drop temporary syntax/raw arenas before moving SourceBundle into an owning accepted result. None of the moved fields borrow output strings, so this requires no self-referential wrapper, Pin or unsafe code. Actual warnings contain owned paths/messages (project.rs:603–620). Preserve their reservations until the corresponding result fields move/drop; do not release still-retained warning strings as though all resolver auxiliary storage vanished.

This result should make no reusable-index claim. A future edit would parse/index again unless a separately justified caller-owned-output borrowing API is chosen. Reusing public CompiledSourceProject (source_project.rs:111–117) would misleadingly require its different SourceIndex/stabilization conventions; prefer a narrow private accepted result with the capability actually established.

An explicit unchanged execution outcome can return the original AuthoredMixedProject after the full current-snapshot check, without output copies or new parsing. A changed outcome can own the new bundle/model/warnings. No-op planning may already have needed E headroom; no-op execution does not retroactively waive that check.

Discriminating next evidence

Before implementation acceptance, require independent exact complete output bytes for mixed/scoped swaps and comments/Unicode, including growing and shrinking edits whose combined total fits; unchanged files must be included. Tighten bytes/entries/numeric/frame and ProjectLimits independently to prove exact policy retention. Isolate L+O, O+parser storage, O+resolver scratch/warnings, and O+resolved+E boundaries with successful predecessors. Include malformed output, valid-but-wrong name output, stale untouched-file/entry/path changes, late failure/drop and no-op unchanged ownership. The current planner tests do not establish these execution guarantees.