# C5 scoping — legacy deletion + closeout gates (2026-08-05) Scoped at HEAD `52175aa1` (branch `claude/acdream-physics-divergence-5aa784`, identical to `main` — C4 merged and pushed today). Every claim below was verified **by symbol at this HEAD**, not inherited from a planning document; where a planning document turned out wrong, §8 says so explicitly. Inputs: the C4 closeout handoff (`2026-08-05-c4-closeout-handoff.md`), the campaign plan (`2026-08-02-placement-cutover.md`), register rows AP-1 / AD-1 / AP-131 / AD-60 / AP-141..145, and two exhaustive caller censuses run against this worktree (legacy placement writers; the temporary probe family). **One-paragraph verdict:** C5 is three different kinds of work wearing one slice name. (1) A **deletion sweep** that is smaller than the plan implies — most of the big deletions already landed inside C4's routes; what is left is ~500 production lines, all with test-only callers, plus large mechanical test churn. (2) **#275**, which is NOT a deletion: it is a behaviour change on the steady-state inbound-Position merge (the hottest wire path), and it is the *only* thing that can retire AP-131 and AD-60's legacy half. (3) The **closeout gates + probe strip + ledger**. These must not ride in one landing; the split is drawn in §7. --- ## 1. The deletion inventory, verified at HEAD by symbol ### 1a. Deletable now — zero production callers, test callers only Every entry below was grepped across all of `src/`; the caller lists are exhaustive at `52175aa1`. | # | Symbol | Where | Production callers | Test callers | ~Lines | |---|---|---|---|---|---| | D1 | `PhysicsEngine.Resolve` | `src/AcDream.Core/Physics/PhysicsEngine.cs:1863-2222` | **ZERO** (the live per-tick method is `ResolveWithTransition`, a different member) | `tests/AcDream.Core.Tests/Physics/PhysicsEngineTests.cs` (12 sites) + `Issue133DungeonTeleportPrefixTests.cs:58` | ~360 | | D2 | `PhysicsEngine.HasCellSurface` | `PhysicsEngine.cs:1767-1783` | only `Resolve` itself (`:1887`) — deletes with D1 | none | ~17 | | D3 | `PhysicsEngine.ResolvePlacement` | `PhysicsEngine.cs:2748-~2810` | **ZERO** (its retirement is already recorded as done in `HeadlessSessionWorldProjection.cs:794`) | `InitialPlacementOverlapTests.cs:42`; `TransitionScratchDifferentialTests.cs:185,194,208,217` | ~65 | | D4 | `PlayerMovementController.SetPosition` (both overloads) | `src/AcDream.Runtime/Gameplay/PlayerMovementController.cs:1746,1760` | **ZERO** (only stale doc-comment mentions at `ConstraintManager.cs:25`, `PhysicsBody.cs:442` — both also still name the long-deleted `BlipPosition`) | ~19 test files, used as **fixture setup**, not as subject (see §3) | ~30 | | D5 | `PlayerMovementController.CommitPreparedPosition` | `PlayerMovementController.cs:1789` | **ZERO** (production replacement is `ArmConstraintLeashAtCommittedPlacement:1815`, called from `RuntimeLocalPlayerPhysicsPublicationState.cs:774`) | `PlayerMovementPlacementTransactionTests.cs:42`; `PlayerMovementControllerTests.cs:1158`; `RuntimeLocalPlayerPhysicsPublicationStateTests.cs:3007` | ~25 | | D6 | `RuntimeSetPositionState.BeginAcceptedPlacement` / `BeginAuthoredPlacement` | `src/AcDream.Runtime/Physics/RuntimeSetPositionState.cs:1321,1333` | **ZERO** — pure pass-throughs to `BeginAcceptedPlacementCore`, which production reaches via `Apply` (`:1304`) and the authored sequence (`:1466`) | ~40 call sites across 10 Runtime test files | ~25 | | D7 | Doc hygiene | tombstone comment `LiveEntityNetworkUpdateController.cs:2469-2478`; stale `BlipPosition` refs above; stale `TryApplyPickup (:1116)` citation in `RuntimeAcceptedPositionDriveControllerTests.cs:221` (the method is now at `RuntimeEntityObjectLifetime.cs:1258`) | — | — | ~20 | **Deletion hazard inside D1/D2's block:** `IsSpawnCellReady` (`PhysicsEngine.cs:1807`) sits physically BETWEEN `HasCellSurface` and `Resolve` and is **production** (`RuntimeSetPositionState.cs:2169,4378`; `SessionPlayerComposition.cs:374`). A region-wise delete takes it by accident. Production-line total for 1a: **~540 lines**, all compile-loud (see §3 for why that matters). ### 1b. Deleted only BY #275 — cannot be deleted standalone These two sites are the code bodies of AP-131 and AD-60's legacy half. They have a **live production caller** — the steady-state Position merge — so deleting them is not a sweep item; it is the #275 behaviour change (§2). - `InboundPhysicsStateController.TryApplyPosition` (the simple overload, `src/AcDream.Runtime/Entities/InboundPhysicsStateController.cs:610`, which hardcodes `installPlacementFrame: true, clearParent: true` at `:662-663`). Production path at HEAD: `LiveEntityInboundAuthorityGate.cs:161` → `LiveEntityRuntime.cs:2550` → `RuntimeEntityObjectLifetime.TryApplyPosition` `:1781` → `RuntimeEntityDirectory.cs:654` → this overload. The route-flag-threaded overload (`:681`) already exists and is what the continuation executor uses (`RuntimeInitialCreateContinuationExecutor.cs:1991-1992`). - `RuntimeEntityObjectLifetime.cs:1918` — `RefreshSnapshot(canonical, snapshot, refreshPosition: acceptedPosition)`: the wire-acceptance-derived `FullCellId` write AD-60 names as "part of the AP-1 divergence this campaign is removing". The executor's equivalent already withholds it (`refreshPosition: false`, executor `:1996`). ### 1c. Named by the plan/handoff as sweep material but NOT deletable — with reasons This is where the plan is most wrong at HEAD. Five items: 1. **`ILocalPlayerTeleportPlacement` / `LocalPlayerTeleportPlacement.Place`** (`src/AcDream.App/Streaming/LocalPlayerTeleportController.cs:176,207-284`). The handoff lists it as a "sweep candidate (now a thin acknowledge seam)". It IS thin, but it is **live production**: route 3 kept it as the post-commit presentation suffix (target-watcher `NotifyTeleported`, camera reset, spatial reconcile) and the A10 review fix explicitly decided its redundant `WorldEntity` pose writes are "kept because they cost nothing". Disposition: **no deletion**. Optional zero-risk simplification (inline the interface) is not worth review cost; recommend leaving it and striking it from the sweep list. 2. **`PlayerMovementController.SetPositionCore`** (`:1845-1920`) — STILL PRODUCTION via `PreparePositionForCommit` (`:1782`) ← `RuntimeLocalPlayerPhysicsPublicationState.cs:219` (the first-entry publication candidate build). The AD-61 force-seed (`Contact|OnWalkable|Active` at `:1860-1863`) is still inside it — filed, argued inert (overwritten by the faithful activation commit + settle), and **not** a C5 retirement target. Note the tension the census surfaced: the route-3 comment at `PlayerMovementController.cs:1975-1985` repudiates this exact overwrite for the teleport path while first-entry still runs it — that is AD-61's documented state, not new debt. 3. **The route-4 leftovers the 4b plan listed as "4b's to delete"** — the plan text is overtaken. At HEAD: the pre-operation unconditional `ConstrainTo` **is already deleted** (tombstone at `LiveEntityNetworkUpdateController.cs:2469-2478`; the only arming site is the post-operation one at `:2853`); the duplicate `96f`/`4f` constants **are already deleted** (zero hits in the file); the `!update.IsGrounded` early return (`:2622-2627`) is **no longer a player-arm carve-out** — since the OnPosition collapse it is the guid-blind D2 wire-airborne return-0 shape (retail `MoveOrTeleport @0x0051636D`), i.e. canonical, not legacy; and `ApplyRemoteContactRouting` (`:1175-1348`) is the canonical five-arm post-collapse routing with exactly one production caller. **None of these is C5 deletion material.** 4. **AP-135's bookkeeping** (`RemoteMotion.CellId` writers at `:1392,:1622`; `LastServerPos`/`LastServerPosTime` at `:1393-1394,:2895-2896,:786`) — deliberately retained per the row's own retirement condition (retires with the free-fall sweep gate, which C5 does not touch). Keep. 5. **`RuntimeLiveEntitySessionController.cs:141`** — the content-less headless host's pre-flip direct `RegisterEntity` path, the one forward-looking "C4/C5 revisit" comment in all of `src/`. Its stated unblock condition ("once the direct-host conductor drive no longer requires prepared content") is not met at HEAD. **Carry, do not delete.** Also checked and confirmed already-deleted (comment references only): `RemoteTeleportController`, `RemoteTeleportPlacement`, `LocalForcePositionTransaction`, `HeadlessSessionWorldProjection.BlipLocalPlayer`, `ResynchronizeLocalPlayerForPortalArrival`, `LocalPlayerTeleportPlacement`'s old duplicate `Place` authority, the `ClassifyLeaveWorld` family, `BlipPosition`. `LiveEntityRuntime` has **no** legacy CreateObject position seed; `HeadlessSessionWorldProjection` has **no** remaining direct placement writer; `PhysicsEngine.SetPosition` (Core) is called **only** from `RuntimeSetPositionState` (`:2028,:3125,:4789`) in production. `PhysicsBody.SnapToCell`'s eleven src callers are three canonical-owner sites, two per-tick simulation sites, and five projectile/static/first-entry body seeds that are live by design (AP-141 pinned the projectile no-machinery decision) — none deletable. --- ## 2. Register rows: provable retirements vs blocked | Row | Verdict | Evidence | |---|---|---| | **AD-1** | **RETIRABLE in the deletion commit.** Its divergence sentence — "Production authoritative placement still routes through the legacy recoverable outdoor demote and outdoor-restore `max(terrainZ, z)` lift" — is **already false at HEAD**: that code is `PhysicsEngine.Resolve` (`:1863-2222`; demote at `:1906`, lift at `:2168-2173`) and it has zero production callers. Its listed prerequisites (authored-mover, rebucketing, prefix-quiescence, body-publication, route cutover) all landed C0–C4. Deleting D1/D2 makes the retirement structural rather than merely observational. | census §2; `PhysicsEngine.cs:1863` | | **AP-1** | **RETIRABLE in the deletion commit.** "Production zero-delta routes deliberately remain on the legacy resolver until 4B2" is stale: every production placement writer now reaches Core `SetPosition` only through `RuntimeSetPositionState`; the local controller's body adoption / sealed setter landed at C3c; deleting D1/D3/D4/D5 removes the last resolver-shaped entry points (all already caller-free). The narrower survivors (#276 settle-cell discard, AD-61 force-seed, AD-62 non-commit outcomes) are separately filed rows/issues and do NOT block AP-1's own condition. | census §§2,3,4,7 | | **AP-131** | **BLOCKED — retires only with #275, which is a behaviour change, not a deletion.** The legacy caller AP-131 says "is deleted at the production cutover" is still the ONLY steady-state production Position merge at HEAD (chain in §1b), still passing unconditional `true/true`. Retiring it means computing the classified `ApplyPlacementFrameBeforeRouting` / `UnparentBeforeRouting` flags (plus retail's FORCE_POSITION Gate A skip) BEFORE the merge on the steady-state path, exactly as the executor already does for residence-pending entities. That changes what every ordinary inbound Position does to animated and parented entities — retail-correcting, but a live-path behaviour change requiring the full contract + dual-review discipline. | `InboundPhysicsStateController.cs:662-663`; executor `:1991-1992` | | **AD-60 legacy half** | **BLOCKED — same gate, #275.** `RuntimeEntityObjectLifetime.cs:1918` still derives `FullCellId` from bare wire acceptance on every accepted steady-state Position (the 4b-3 D1 comment at `:1886-1899` states it plainly). Withholding it (executor's `refreshPosition: false` rule) moves residency changes onto placement/simulation commits only — the retail rule — but `FullCellId` is the residency predicate at 45+ sites (AP-142's own count), so the blast radius is real and this must not be smuggled into a sweep. | `RuntimeEntityObjectLifetime.cs:1915-1918` | **Rows adjacent but NOT C5 targets:** AD-61 (force-seed, deliberate), AD-62 (non-commit force outcomes), AP-135 (retained bookkeeping), AP-141–145 (all filed with their own conditions; AP-145 retires with #318's *fix*, not its test — the test only makes the asymmetry assertable). --- ## 3. THE DANGEROUS CASE — every test-only-caller path, with disposition First a sharpening the scoping question deserves: deleting a method whose callers are tests is **compile-loud** (the test project breaks), same as a production caller. The genuinely silent case is the *disposition of the tests afterward*: deleting a test that pinned behaviour which MOVED (instead of re-pointing it) is the silent coverage loss. Per item: | Path | Test callers | Behaviour gone or moved? | Disposition | |---|---|---|---| | `PhysicsEngine.Resolve` | `PhysicsEngineTests.cs` ×12 | **Gone** — the outdoor-demote/floor-snap/terrain-lift semantics are legacy-only; the canonical replacements have their own suites (`PhysicsSetPositionTests`, `RuntimeSetPositionStateTests`) | **Delete tests with the path**, after a one-pass audit that no individual assertion pins something canonical-owned (e.g. `AdjustPosition` behaviour, which survives — tests touching it re-point at `AdjustPosition` directly) | | `PhysicsEngine.Resolve` | `Issue133DungeonTeleportPrefixTests.cs:58` | **Moved** — #133's invariant (landblock-prefix correctness on dungeon teleport claims) is now the canonical portal/teleport placement's job | **Re-point** at the canonical path (drive a teleport-classified `RuntimeSetPositionState` placement with a prefixed dungeon claim and assert the committed cell), or prove an existing canonical test already pins it and record that in the deleting commit. Do NOT silently delete — this is a regression pin for a named historical bug | | `PhysicsEngine.ResolvePlacement` | `InitialPlacementOverlapTests.cs:42` | **Moved** — placement-ring occupancy search is ported inside canonical SetPosition (`find_placement_position`, covered by `PhysicsSetPositionTests`) | **Verify-then-delete**: confirm `PhysicsSetPositionTests` covers the occupied-spawn ring-search case this test pins; if not, re-point it at `Transition.FindPlacementPos` via the canonical entry before deleting | | `PhysicsEngine.ResolvePlacement` | `TransitionScratchDifferentialTests.cs:185-217` | **Moved** — these are Slice-I zero-alloc differential arms | **Re-point or drop the arm explicitly**: if `ResolvePlacement` was one of the differential's measured entry points, replace with the surviving canonical entry; a silent drop would shrink the I-slice differential's coverage without anyone deciding it | | `PlayerMovementController.SetPosition` | ~19 test files (~45 sites in `PlayerMovementControllerTests` alone) | **Neither** — these tests USE it as fixture setup (position the player), they do not test it | **Mechanical re-point** through one shared test helper that drives the production seeding path (publication `PreparePositionForCommit` → activation), or — cheaper and honest — keep ONE explicitly-named internal test-seed method with a doc comment stating it exists for fixtures only. Either way the fixture semantics (grounded start via the force-seed) must be reproduced deliberately, since dozens of movement tests assume a grounded, zero-velocity start | | `PlayerMovementController.CommitPreparedPosition` | 3 sites | **Moved** — replaced by `ArmConstraintLeashAtCommittedPlacement` | **Re-point**: the prepared-position transaction assertions should run against the production arm/commit pair; `RuntimeLocalPlayerPhysicsPublicationStateTests:3007` likely already half-covers it — audit before deciding delete-vs-rewrite per test | | `BeginAcceptedPlacement`/`BeginAuthoredPlacement` wrappers | ~40 sites, 10 files | **Neither** — the CORE (`BeginAcceptedPlacementCore`) is production; the wrappers are test conveniences | Two defensible calls: (a) keep the wrappers, documented as test seams (zero churn, zero coverage change); (b) delete and mechanically re-point every site at `Apply`/the authored sequence. The ~40-site churn buys nothing behavioural; **recommend (a)** unless the campaign wants the sweep to be absolute — in which case budget the churn (it is mechanical but touches the Runtime suite broadly) | | `InboundPhysicsStateController.TryApplyPosition` (true/true overload) — #275's deletion | its unit tests assert the UNCONDITIONAL flags | **Deliberately changed** — the old assertions describe the divergence being removed | **Rewrite, never delete-only**: each unconditional-flag assertion becomes a classified-flag assertion (animated entity keeps its placement frame; ForcePosition on a parented entity does NOT unparent — retail Gate A), sabotage-verified both directions per process rule (e) | One more test-shaped landmine, inherited not created: the #316-preserving pair (`LandingPacket_PlayerGuid_QueueClearedNoShadowPublish_316Preserved` / `..._CreatureGuid_ShadowPublishedQueueNotCleared`) pins a **defect preserved verbatim**. If C5's connected session measures #316 and the fix lands, that test inverts by design — do not "fix" the test without the measurement. --- ## 4. The C4 inheritance, sized | Item | What it is | Size / shape | |---|---|---| | **#318 composition test** | Drive a real portal arrival through the canonical drive controller + REAL `RuntimePlacementPresentationSink` + REAL `PhysicsEngine`; assert **`PhysicsEngine.ShadowObjects` holds a row at the destination** (never just `LocalPlayerShadowState`'s dedup cache — AP-145's `TryPublishPlace` → `.Set()` bypass both skips the publish AND pre-seeds `SyncPose`'s dedup so the next tick can skip too; a cache-only assertion is satisfied by the bug) plus the T8 write ordering | Test-only, ~150–300 lines, App.Tests. The wiring cost is composition (real sink + real engine in one fixture), not assertion count. Retires nothing by itself; it makes AP-145 falsifiable | | **AP-145 asymmetry** | The cache-without-publish seam itself | NOT a C5 fix unless the composition test proves a live miss; the row argues why it self-heals in practice. Land the test first, decide after | | **Route-2 B2 parity test** | The plan's recorded acceptance gap (plan §C4 route 2): no test drives an accepted ForcePosition end-to-end through the presentation sink and asserts the render entity moved from the committed receipt | ~100–200 test lines. **Flag: this deliverable is in the PLAN but absent from the handoff's "What C5 inherits" list** — carry it explicitly so it doesn't fall between documents | | **#276 remainder** | `SpawnPlacementSettler.TrySettle` discards `settle.CellId` | ~30–80 production lines + a conformance test; NOT named a C5 deliverable by the plan — carry unless cheap to fold; does not block AP-1 (separately filed) | | **#277** | far-Create service-window conversion | Trigger-conditioned (no radius changed); **zero C5 work** | | **#313** | `DeclareValid` selection transfer | Selection UX, outside placement; carry | | **#316** | player-arm landing never publishes the shadow — **measure before fixing**; the named instrument is `ACDREAM_PROBE_REMOTE_LANDING` | The measurement is a two-client landing observation — fold it into the early gate session (§5); the fix (if the #184 class) is its own later commit | | **#317** | velocity-chain retail audit | Research-only (decomp), no code; carry unless the session has slack | | **#309 narrow half** | `GotoLostCell` hidden-until-`reenter_visibility` | Carried, re-scope before running; not C5 | | **#280** | portal destination prefetch | Its own slice with its own visual gate. **Ordering note the handoff does not restate:** the campaign plan's numbered order (items 3→4→5) puts #280 BEFORE C5's final-binary soak/matrix — sensible, since #280 changes reveal behaviour the matrix would exercise. C5's implementation slices are independent of it and can proceed; the **final** closeout gates should run after #280 lands, or the matrix will need re-running | | **Probe strip** | six TEMPORARY flags | **~1,340 lines** total: REMOTE_SLIDE ~700, REMOTE_LANDING ~300, LOCAL_TELEPORT ~215, REMOTE_TELEPORT ~50, PARK ~41, CHILD_CELL ~33. All env-only (no DebugPanel mirrors), **zero test references** — the strip is test-free. Hazards recorded by the census: keep `ParseHexIdList` (shared with permanent `ACDREAM_DUMP_*`), keep the DISTINCT older `ACDREAM_PROBE_TELEPORT`/`LogTeleport` block that sits adjacent to `LogLocalTeleportArrival` (two flags, documented distinct at `RuntimeAcceptedPositionDriveController.cs:769-770`), keep the probe-aliased production members (`BodySnapThreshold`, `InterpolationManager` queue state, `bodyOnWalkableAtTickStart`), and trim `ResetForTest` line-wise, not wholesale | --- ## 5. Gate sequencing — and the cell-less trigger, answered by reading **State at HEAD:** three of C4's four gates were run and user-passed on 2026-08-05 (route 3 unambiguous incl. the autorun-cancel line; route 6 visual; route 7 pass but THIN — one `cause=propagate`). Owed: (a) route 7 thickening (several equipped landblock crossings, expect double-digit `propagate`), and (b) gate 4, `cause=cellless`, whose recorded recipe route 7 invalidated. ### The cell-less trigger — what reading establishes The classifier's cell-less arm needs `PreMergeCommittedCellId == 0`, which requires an **ACTIVE canonical record whose `FullCellId` is 0** at merge time (`RuntimeEntityObjectLifetime.TryApplyPosition:1898` — a fully-withdrawn record yields `null`, "no opinion", not 0). The production population of such records exists and is well-defined: 1. **Post-pickup items**: `TryApplyPickup` (`:1258`) commits `SetFullCell(canonical, 0u, 0u)` at `:1314` and leaves the record ACTIVE (withdrawn presentation, suspended clock, but in the directory). 2. Children zeroed by `WithdrawCommittedChildrenToCellless` on parent delete — but ACE deletes tracked equipment alongside its wielder (`Player_Tracking.cs:108-112`), so these tombstone rather than linger. 3. Unwield — **no longer cell-less** (route 7 D1/D2: committed child carries the parent's cell), which is exactly why the old recipe died. The one ACE message that delivers a bare `UpdatePosition` to population (1): **dropping the item**. `HandleActionDropItem` (`references/ACE/.../Player_Inventory.cs:1437-1443`) sends the dropper `GameMessageUpdatePosition(item)` directly after `TryDropItem` — and for `RemoveFromInventoryAction.DropItem` no client-side delete precedes it (no `InventoryRemoveObject`, no `DeleteObject`; `:222-247`), so the client-side record is still the active cell-0 one from the pickup. **The deciding nuance, which reading could not fully settle:** inside `TryDropItem`, `Landblock.AddWorldObjectInternal` calls `wo.NotifyPlayers()` (`Landblock.cs:900`) which sends `CreateObject` to every player in the item's freshly-created `PhysicsObj.ObjMaint` known-players set — all enqueued on the same ordered reliable stream BEFORE the `UpdatePosition` at `:1443`. If the dropper is in that set at that instant (populated synchronously during `AddPhysicsObj`), the Create precedes the Position, the Position lands in the initial-create residence branch, and it classifies against the Create's own resolved cell — **not** cell-less. If known-player registration is deferred to the player's next visibility tick, the `UpdatePosition` arrives first and **IS the live cell-less trigger**. **Recommendation:** a bounded two-minute falsification run, not an open investigation: with `ACDREAM_PROBE_REMOTE_TELEPORT=1`, pick up a ground item, drop it, repeat a few times (outdoors + once indoors), and read the `[remote-teleport]` lines. Either `cause=cellless` appears (gate 4 closes with a recorded recipe: *pickup-then-drop*), or it provably takes the Create path — in which case record the cell-less arm as **synthetic-fixture-covered by design with no reachable live trigger against ACE**, exactly the route-5 precedent ("when a gate cannot exist, record that, never a substitute"), process rule (g). Do not leave gate 4 on file as pending indefinitely. ### Sequencing **Run the owed gates FIRST, before any C5 implementation**, as one cheap user session on the current binary: route-7 thickening (PROBE_CHILD_CELL) + the cell-less falsification (PROBE_REMOTE_TELEPORT) + **#316's measurement** (PROBE_REMOTE_LANDING; a second client jumping/landing while observed). Rationale: (a) C4's ledger closes on evidence from the binary family its routes were gated on; (b) if thickening or the cell-less run surfaces a defect, C5's deletion inventory could change; (c) all three consume probes the strip will later delete. C5 absorbs the *bookkeeping* of these gates (ledger updates), not their execution debt. --- ## 6. Probe-strip ordering The strip is **last — after every connected gate in this campaign has consumed its probe evidence**, as its own commit: 1. Owed-gate session (§5) consumes CHILD_CELL, REMOTE_TELEPORT, REMOTE_LANDING. 2. C5 implementation slices land (deletions, #275, tests) — probes untouched; they are env-gated and production-inert. 3. C5 closeout gates run on the final implementation binary — the lifecycle/reconnect route re-exercises portals, so LOCAL_TELEPORT evidence remains readable if anything regresses; keep the probes through this. 4. **Strip commit** (~1,340 lines, hazards per §4), then full Release suite + one short lifecycle route as the strip's own gate. The strip is behaviour-neutral by construction (env-gated emission only), so the final-binary soak from step 3 remains valid evidence; the post-strip re-run is the cheap proof of neutrality. **Conditional carve-out:** if #316's measurement does NOT happen in the §5 session, `ACDREAM_PROBE_REMOTE_LANDING` must be **excluded from the strip** (it is the issue's named instrument) and the family stripped five-wide with a note — do not let a hygiene pass delete an open issue's measurement apparatus. --- ## 7. Size and split recommendation Calibration: this campaign's landings ran ~127–~500 production lines each (4a 364, 4b-2 350–500, 4b-3 ~250, r5 ~131, r7 ~127, r3 ~418), each with full contract/dual-review discipline. | Piece | Production lines | Test lines | Risk | |---|---|---|---| | Deletion sweep (§1a) | ~540 deleted | ~25 files touched; ~1,500–2,000 test lines deleted/re-pointed | Low (all compile-loud), but the §3 dispositions are judgment work | | #275 unification (§1b/§2) | ~150–400 changed on the hottest inbound path | ~300–600 rewritten/added | **High** — behaviour change on every steady-state Position; 45+ residency-predicate blast radius for the AD-60 half | | #318 + route-2 B2 tests | 0 | ~250–500 | Low | | Probe strip | ~1,340 deleted | 0 | Low, hazard-listed | | Gates + ledger/docs | 0 | 0 | User time | Combined this is far past the ~500-line calibration, and #275 is a different RISK CLASS from everything else. **Split into three landings plus the pre-session:** - **C5-gate session (first, user-run):** route-7 thickening + cell-less falsification + #316 measurement. Closes C4's ledger. - **C5a — deletion sweep + tests:** §1a deletions, §3 dispositions, #318 composition test, route-2 B2 parity test, **retire AP-1 and AD-1 in the same commit as the deletions** (register rule 1). Deletion-only + test-only; reviewable as one diff. - **C5b — #275:** pinned contract (the executor's classify-then-merge order is the template; retail Gate A is the FORCE_POSITION skip), single implementer, dual reviews, sabotage-verified flag tests both directions. **Retires AP-131 and AD-60's legacy half in its own commit.** This slice is where process finding (a) — "verify the load-bearing premise in code at implementation start" — applies to the classifier-flag semantics before building on them. - **C5c — closeout:** final-binary complete suite, lifecycle/reconnect route, canonical nine-stop soak, two-client observation, user visual matrix (sequenced after #280 per the plan's own ordering, §4), then the probe strip + its neutrality gate, then register/roadmap/milestones/memory + the successor handoff, close #275, close the campaign ledger. --- ## 8. Plan claims found false or stale at HEAD (the seventh-stale-doc guard) 1. **Campaign plan / handoff framing that C5's register retirements are a deletion product:** AP-131 and AD-60's legacy half **cannot** retire by deletion — they require #275, a live-path behaviour change (the plan does name "close #275", so this is a framing error, not a missing item — but a session that read only "delete every superseded legacy path" would ship the sweep and wrongly retire the rows). 2. **AD-1's and AP-1's own row texts are stale in the conservative direction:** the "production still routes through the legacy resolver" sentences are already false at HEAD (`PhysicsEngine.Resolve` / `ResolvePlacement` have zero production callers). They over-claim a divergence, not a completed port — retire with the deletion commit. 3. **The handoff's sweep candidate `ILocalPlayerTeleportPlacement` is not deletable** — it is the live post-commit presentation suffix with a production caller (§1c item 1). 4. **The 4b plan's "every legacy fallback 4a left is 4b's to delete" list is overtaken:** at HEAD the pre-op `ConstrainTo` and duplicate constants are already gone, and the `!IsGrounded` return + `ApplyRemoteContactRouting` are the canonical post-collapse retail shapes, not deletable debt (§1c item 3). 5. **Stale line citations:** the handoff's `TryApplyPickup (:1116)` (now `:1258`; the same stale `:1116` lives on in `RuntimeAcceptedPositionDriveControllerTests.cs:221`'s doc comment); `ConstraintManager.cs:25` and `PhysicsBody.cs:442` still document the deleted `BlipPosition`/`SetPosition` pair. 6. **The handoff's "What C5 inherits" list omits the route-2 B2 parity test** that the campaign plan itself records as "carry it into C5's parity tests" — carried here (§4). 7. **The cell-less trigger is no longer "UNESTABLISHED needing its own investigation" in the open-ended sense:** reading pins the candidate population, the single candidate wire path (pickup-then-drop, `Player_Inventory.cs:1443`), and the one ACE ordering fact a two-minute probe run settles (§5). The honest outcomes are a recorded recipe or a recorded cannot-exist — not a standing investigation.