research: scope C5 — the deletion is smaller than the plan implies, and half the rows are blocked on a behaviour change
Verified by symbol at HEAD 52175aa1, behind two exhaustive caller censuses
(legacy placement writers; the probe family).
DELETION INVENTORY: 6 deletable symbol groups (~540 production lines), 2 more
deletable only via #275, and 5 that the plan or handoff names as deletable but
are NOT. Deletable now, all with zero production callers: PhysicsEngine.Resolve
(~360 lines — this IS AD-1's legacy demote/lift body) plus its private
HasCellSurface; PhysicsEngine.ResolvePlacement; PlayerMovementController
.SetPosition (both overloads); CommitPreparedPosition; the BeginAcceptedPlacement
/BeginAuthoredPlacement test wrappers. Hazard recorded: production
IsSpawnCellReady sits physically inside the Resolve block.
THE PLAN'S FRAMING IS WRONG FOR HALF THE ROWS. AP-1 and AD-1 are provably
retirable in the deletion commit — both rows' "production still routes through
the legacy resolver" sentences are already false at HEAD. But AP-131 and
AD-60's legacy half are blocked on #275, which is a BEHAVIOUR CHANGE
(classify-then-merge on every steady-state Position, retail Gate A, wire-cell
withhold across a 45+ site residency-predicate blast radius) — not a deletion.
"C5 deletes the paths and the rows retire" holds for two rows and not the
other two.
SEVEN TEST-ONLY-CALLER CASES, each with a disposition, because this is where a
deletion slice silently removes coverage: Resolve's unit tests (behaviour gone
— delete); Issue133DungeonTeleportPrefixTests (behaviour MOVED — re-point, it
is a named-bug regression pin); InitialPlacementOverlapTests and
TransitionScratchDifferentialTests (verify-then-delete / re-point the
differential arm); ~19 files using PlayerMovementController.SetPosition as
fixture setup (mechanical re-point); CommitPreparedPosition's tests (re-point
at the leash-arm replacement); the Begin* wrappers' ~40 sites (keep as a seam).
Also flagged: the #316-preserving test pins a defect verbatim and inverts by
design once measured.
THE CELL-LESS TRIGGER, ESTABLISHED BY READING rather than deferred to a live
session: pickup-then-drop. TryApplyPickup leaves an ACTIVE cell-0 record, and
ACE's drop sends that guid a bare UpdatePosition (Player_Inventory.cs:1443)
with no client-side delete. What remains unknown is only whether a CreateObject
from NotifyPlayers (Landblock.cs:900) precedes it on the ordered stream, which
depends on when ACE populates the fresh item's known-players set — a two-minute
probe run settles it, with route 5's "the gate cannot exist, record that" as
the honest fallback.
SEQUENCING: run the owed gates FIRST as one cheap user session on the current
binary (route-7 thickening, the cell-less falsification, #316's measurement),
then C5a (deletions + #318 + route-2's B2 parity test + retire AP-1/AD-1), then
C5b (#275 + AP-131/AD-60, own contract and dual review), then C5c (closeout
gates after #280 per the plan's own ordering, the ~1,340-line probe strip, the
ledger). The probe strip goes LAST because the owed gates depend on the probes,
with a REMOTE_LANDING carve-out if #316 stays unmeasured.
Seven false or stale plan claims found and listed, including AP-1/AD-1's own
row texts, ILocalPlayerTeleportPlacement being called deletable when it is a
live post-commit suffix, and the 4b "to delete" list being overtaken — the
pre-op ConstrainTo and duplicate constants are already gone and the remainder
is now canonical post-collapse.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
52175aa14a
commit
0991182198
1 changed files with 357 additions and 0 deletions
357
docs/research/2026-08-05-c5-scoping.md
Normal file
357
docs/research/2026-08-05-c5-scoping.md
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
# 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue