research: settle retail parent-cell propagation and scope C4 route 3
Two read-only research landings that unblock the last two C4 routes. **Parent-cell propagation (unblocks route 7).** Retail DOES re-cell children when the parent crosses a cell, recursively to unbounded depth. SetPositionInternal @0x00515330 branches on `this->cell == curr_cell` @0x0051536d; the changed branch reaches change_cell @0x00513390, whose delegates leave_cell @0x00510f50 and enter_cell @0x00510ed0 self-recurse over children and write the FULL identity (add_object @0x00510ee2, objcell_id @0x00510f1e, part-array cell id @0x00510f2b, cell pointer @0x00510f35). change_cell itself has no child loop — the recursion is in the delegates. The clincher: update_object @0x00515d10 early-returns on `parent != 0` @0x00515d40, so a child never runs its own physics tick and parent propagation is the ONLY mechanism maintaining its cell. The trap this retires: the depth-1 loop @0x0051539c-0x005153d8 is the SAME-CELL fast path (objcell_id and part-array id only, deliberately not the cell pointer), not the propagation. An implementer finding it first would conclude "depth-1, id-only" and ship equipped items stranded at landblock boundaries — the #184 class. Route 7's planned set_parent-only write would have done exactly that. Settled by READING, not by a debugger trace. The scoping had listed this as needing live cdb evidence, but change_cell/set_cell's child handling had simply never been read; the project's grep -> decompile -> verify order had not been exhausted. One BN field-name gap was closed by walking struct CPhysicsObj in the verbatim acclient.h, so no PE byte-decode was needed either. A breakpoint set is recorded for optional confirmation only. **Route 3 scoping (portal, the last route).** ~225-400 added non-comment production lines, ONE slice, contingent on #280 splitting out. Portalling works today; route 3 removes a duplicate authority (LocalPlayerTeleportPlacement.Place), it does not fix a bug. Eight dated-inventory claims are now false, the most consequential being "the binding machinery is 100% dormant end to end" — the portal authority's CONSUMPTION and validation side is live production code at three layers and is exercised by every placement; only the PRODUCER adapter is missing. That makes route 3 materially smaller than the campaign plan implies. #280 SPLITS from route 3, definitively: it is a reveal-gate/prefetch-window concern (WorldRevealReadinessBarrier's neighbourhood radius versus retail's mid_radius, LScape::PreFetchCells @0x00505660 / SmartBox::SetRegion @0x00453227), mechanically disjoint from the placement cutover — route 3 reads the ready predicate, #280 rewrites it. The campaign plan already sequences #280 separately; only the session handoff said it "rides with" route 3, and the plan is right. Retail's local portal arrival is the GENERIC path for the third route running: SmartBox::TeleportPlayer @0x00453910 is SetPositionSimple(player, dest, 1) with flags 0x1012 — route 2's exact primitive — plus PlayerPositionUpdated. Two rule inversions recorded so route 3's implementer cannot carry the wrong rule forward from the routes just landed: route 2's "never re-arm the leash" INVERTS here (the teleport branch arms ConstrainTo @0x0045418A and zeroes velocity @0x004541B4), and 4b-3's hook-before-placement ordering INVERTS (the local teleport_hook runs AFTER placement, from PlayerPositionUpdated @0x004538AE). The classifier's dormant LocalPlayer-teleport route already encodes both. Two documentation defects found in passing and recorded, not fixed: the 2026-07-16 portal pseudocode attributes portal arrival to enter_world (that is the login path), and a stale comment hides a live second writer — the generic wire-pose write does run for the local player (AP-131/C5 scope). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
cff52c44f4
commit
ca96ea5e32
2 changed files with 1120 additions and 0 deletions
600
docs/research/2026-08-04-c4-route-3-scoping.md
Normal file
600
docs/research/2026-08-04-c4-route-3-scoping.md
Normal file
|
|
@ -0,0 +1,600 @@
|
|||
# C4 route 3 — portal / local-player placement: SCOPING (2026-08-04)
|
||||
|
||||
**This is scoping, not a pinned contract.** Verified at HEAD **`cff52c44`**, branch
|
||||
`claude/acdream-physics-divergence-5aa784`, clean tree. Line numbers are
|
||||
as-of-HEAD and will go stale; every citation also names the symbol — trust the
|
||||
symbol (process rule 6).
|
||||
|
||||
**Route 3 is NOT a bug fix.** Portalling works today — `/ls`, spell recalls,
|
||||
portal use, and admin teleports all place correctly and are user-accepted
|
||||
behaviour. Route 3 removes a **duplicate placement authority**: the local
|
||||
player's portal arrival is committed by two host-owned hand copies
|
||||
(`LocalPlayerTeleportPlacement.Place` in App,
|
||||
`ResynchronizeLocalPlayerForPortalArrival` in Headless) instead of the one
|
||||
canonical Runtime SetPosition transaction every other C4 route now uses.
|
||||
Nobody should read this document as "portals are broken".
|
||||
|
||||
Route 3 is the LAST C4 route. Routes 1 (C3a-c), 2 (`9966b531`), 4a, 4b-1/2/3,
|
||||
5 (`36255af0`), and 6 (zero production lines, `1b484937`) are landed; route 7
|
||||
is scoped with its research blocker resolved
|
||||
(`2026-08-04-retail-child-cell-ownership.md`).
|
||||
|
||||
Inputs verified for this scoping: the campaign plan
|
||||
(`docs/plans/2026-08-02-placement-cutover.md`), the 2026-08-02 route inventory
|
||||
(**dated — §3 below lists what is now false**), the route-5 contract + its
|
||||
round-3 reviews (the current contract standard), the 4b-3 contract's 13
|
||||
invariants, `claude-memory/project_portal_space.md`, the J6.2/J6.3 closeouts,
|
||||
the six process rules in `2026-08-04-session-handoff-c4-remaining.md`, and
|
||||
direct reads of every file cited below plus the retail pseudo-C.
|
||||
|
||||
---
|
||||
|
||||
## 1. Headline findings
|
||||
|
||||
1. **The campaign plan overstates what is missing.** Plan line ~92-93 says
|
||||
"`RuntimePortalPlacementAuthority` has zero producing call sites; the
|
||||
adapter from `RuntimeWorldTransitState` does not exist." The first half is
|
||||
still true — zero production producers, confirmed by exhaustive read of
|
||||
every `Begin*`/`TryPrepareAndSubmit*` call site (§4). The second half is
|
||||
now HALF-false: the **consumption/validation side of the adapter exists
|
||||
and is LIVE production code**, exercised (with an empty portal) by every
|
||||
placement in the game:
|
||||
- `RuntimeWorldTransitState.IsCurrentPlacementAuthority`
|
||||
(`RuntimeWorldTransitState.cs:258-275`) — generation + sequence + cell +
|
||||
host-token + not-superseding check;
|
||||
- `RuntimePlacementPresentationSink.TryApply`
|
||||
(`src/AcDream.App/World/RuntimePlacementPresentationSink.cs:100-106`) —
|
||||
every graphical `Place` receipt is already gated on it;
|
||||
- `HeadlessRuntimePlacementProjectionSink.TryApply`
|
||||
(`src/AcDream.Headless/Hosting/HeadlessRuntimePlacementProjectionSink.cs:100-121`)
|
||||
— the headless twin;
|
||||
- `LiveEntityRuntime.IsValidPortalPlacementAuthority`
|
||||
(`src/AcDream.App/World/LiveEntityRuntime.cs:1448-1457`) — token-shape
|
||||
validation inside every projection-record lookup;
|
||||
- `RuntimeSetPositionState.BeginAcceptedPlacementCore:1528-1534` — Begin
|
||||
refuses a non-empty portal unless kind is `LocalAuthoritative` AND the
|
||||
authority's destination cell equals the record's accepted-position
|
||||
landblock;
|
||||
- the portal authority is threaded through the whole pipeline already:
|
||||
`RuntimeSetPositionCommand.Portal` (`:128`),
|
||||
`RuntimeSetPositionMoverPreparation.Portal`
|
||||
(`RuntimeSetPositionMoverPreparation.cs:121`, consistency-checked in
|
||||
`TryBuild:146`), `Operation.Portal` (`:433`), and
|
||||
`RuntimePlacementProjectionToken.Portal` (`:250`, a REQUIRED positional
|
||||
on every projection token).
|
||||
|
||||
**What is actually missing is only the producer**: nothing constructs a
|
||||
`RuntimePortalPlacementAuthority` with `Present: true` (grep: zero in
|
||||
`src/`; three test constructors), and no portal arrival drives a Runtime
|
||||
placement at all. That makes route 3 materially smaller than the plan's
|
||||
phrasing implies.
|
||||
|
||||
2. **Retail's local portal arrival is the GENERIC path — the pattern from
|
||||
routes 2 and 5 holds a third time** (§5). `SmartBox::TeleportPlayer`
|
||||
@0x00453910 is two calls: `CPhysicsObj::SetPositionSimple(player, dest, 1)`
|
||||
— the EXACT primitive route 2 already routed through Runtime's
|
||||
`CommitCanonical` for ForcePosition, flags 0x1012 — and
|
||||
`SmartBox::PlayerPositionUpdated(this, 1, FLT_MAX)`. There is no dedicated
|
||||
local portal placement path to port; the work is wiring, ordering, and the
|
||||
post-placement suffix.
|
||||
|
||||
3. **The classifier's LocalPlayer+TeleportAdvanced route is fully modeled and
|
||||
steady-state dead** (`RuntimeAuthoritativePositionRouteClassifier.cs:349-368`):
|
||||
`SetPositionSimple` + `AuthoritativeTeleportFlags` + hook
|
||||
`AfterPositionOperation` + constrain `AfterPositionOperation` +
|
||||
`ZeroVelocity: true` + `SendPositionImmediately: false` — matching the
|
||||
retail listing exactly (§5). Its only production caller today is the
|
||||
initial-create continuation executor inside the residence window; route 3
|
||||
would be its first steady-state producer.
|
||||
|
||||
4. **#280 is mechanically distinct from route 3 and must SPLIT** (§7).
|
||||
|
||||
---
|
||||
|
||||
## 2. Site inventory at HEAD (re-verified, not inherited)
|
||||
|
||||
### 2.1 The duplicate authorities to replace (both hosts)
|
||||
|
||||
| # | site (symbol) | at HEAD | what it does |
|
||||
|---|---|---|---|
|
||||
| D1 | `LocalPlayerTeleportPlacement.Place` | `src/AcDream.App/Streaming/LocalPlayerTeleportController.cs:214-278` (class `:183-290`) | The graphical duplicate authority, intact and essentially as the 2026-08-02 inventory described plus the 2026-07-25 rebucket fix: `_physics.Resolve(pos, cell, 0, StepUpHeight)` `:219` → `controller.SetPosition` `:230` (which runs the whole teleport tail in `SetPositionCore`, see 2.4) → direct `entity.SetPosition/ParentCellId/Rotation` `:242-244` → `RebucketLiveEntity` (throws on failure) `:254` → `_host.Host?.NotifyTeleported()` `:264` → `SetBodyOrientation` `:265` → camera resets `:267-268` → `_spatial.Reconcile()` `:269`. No Runtime transaction, no receipt, no portal authority. |
|
||||
| D2 | `HeadlessSessionWorldProjection.ResynchronizeLocalPlayerForPortalArrival` | `src/AcDream.Headless/Hosting/HeadlessSessionWorldProjection.cs:788-836` | The headless duplicate authority — the old `SynchronizeLocalPlayer` body, SURVIVING ONLY FOR THIS ROUTE (its own doc at `:779-787` says "TODO-C4 (route 3)"): `CenterOn` → `Physics.Engine.Resolve(wire, lb, 0, 100f)` `:810` → `Engine.ResolvePlacement(0.48f/1.835f, IsPlayer\|EdgeSlide)` `:816` → `controller.SetPosition` `:831` → `SetBodyOrientation` `:835`. Called from `PrepareDestination:757-762`. |
|
||||
|
||||
### 2.2 The drive machinery (graphical)
|
||||
|
||||
| site | at HEAD | note |
|
||||
|---|---|---|
|
||||
| `LocalPlayerTeleportController` (drive) | `LocalPlayerTeleportController.cs:385-789` | `OnTeleportStarted:436-459` (F751 → `TryQueueTeleportStart`); `OfferDestination:461-470`; `Tick:472-570` — readiness = destination + `!IsRecenterPending` + `_worldReveal.Evaluate(cell).IsReady`; on `TeleportAnimEvent.Place`: `CanPlacePortalDestination` preflight `:514` → `_placement.Place` `:521` → `ObserveMaterialized` `:527` (**still a rubber-stamp AFTER the mutation** — the inventory's structural claim holds); `PlayExitSound` → `RevealWorldViewport`; `FireLoginComplete` → `EnterWorld` + `SendLoginComplete` + `Complete`. |
|
||||
| destination offer | `src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs:2950-2957` (was `:1906-1913`) | Last statement of `OnPosition`: `Apply` disposition + local guid → `_localPlayerTeleport.OfferDestination(FromAcceptedPosition(update), timestamps.TeleportAdvanced)`. No placement runs for a local Apply anywhere in `OnPosition` (route 2's ForcePosition drive at `:2014-2071` is disposition-exclusive with it). |
|
||||
| `WorldRevealCoordinator` | `src/AcDream.App/Streaming/WorldRevealCoordinator.cs` (574 lines) | Holds the current `RuntimeWorldHostProjectionToken` PRIVATELY in `_hostProjections` (`:40-62`, `FindCurrentHostProjection:516`); `TryBeginPortal:117-149` mints generation + registers the host projection. **The producer needs read access to this token (or re-derives it via the transit's idempotent `TryRegisterHostProjection`)** — a small exposure decision for the contract. |
|
||||
| local generic render-pose write | `LiveEntityNetworkUpdateController.cs:2284-2289` + `:2314` | **Live finding, verified against the code (the comment at `:2276` is stale):** `TryApplyGenericRemoteRenderPose(entity, null, …)` gate is `OwnsSteadyState(route)` (`:1037-1052`) which is FALSE for the local player's null route — so every accepted local Apply, including the portal DESTINATION Position, writes the raw wire pose onto the local player's `WorldEntity` and rebuckets to the wire landblock while portal space still covers the viewport. Pre-existing, hidden by the portal viewport, later overwritten by `Place`. AP-131/#275 territory — see trap T8. |
|
||||
|
||||
### 2.3 The headless portal flow
|
||||
|
||||
`RuntimeLiveEntitySessionController.TryCompletePortal`
|
||||
(`src/AcDream.Runtime/Session/RuntimeLiveEntitySessionController.cs:339-428`),
|
||||
called from `OnPositionUpdated:296` and `OnTeleportStarted:330`:
|
||||
`TryGetAcceptedTeleportDestination` → `TryBeginPortalReveal` →
|
||||
`TryRegisterHostProjection` → ack `ProjectionRegistered` →
|
||||
**`PrepareDestination(generation, destination)`** `:368` (this is where D2
|
||||
runs, plus `controller.State = PlayerState.InWorld` and the readiness report)
|
||||
→ `AcknowledgeDestinationReadiness` → `AcknowledgePortalMaterialized` → ack
|
||||
`SimulationReleaseProjected` → `RequireDestinationReservationRelease` → ack
|
||||
`DestinationReservationReleased` → `AcknowledgeWorldViewportVisible` +
|
||||
`Complete` → ack `TerminalProjected` → `SendGameAction(LoginComplete)` →
|
||||
`EndTeleport`. The J6 lifecycle itself is canonical and healthy; only the
|
||||
placement inside `PrepareDestination` is the duplicate.
|
||||
|
||||
### 2.4 Runtime surfaces route 3 builds against
|
||||
|
||||
| site | at HEAD | relevance |
|
||||
|---|---|---|
|
||||
| `RuntimePortalPlacementAuthority` | `RuntimeSetPositionState.cs:105-119` | `(bool Present, long RevealGeneration, ushort TeleportSequence, RuntimeWorldHostProjectionToken Projection)`. **The shape is RIGHT for what transit holds** — it is exactly the tuple `RuntimeWorldTransitState` owns per reveal (`Snapshot.Generation`, `ActiveTeleportSequence`, the registered host token whose `DestinationCell` is validated everywhere). No shape change needed. |
|
||||
| `RuntimeWorldTransitState` | `RuntimeWorldTransitState.cs` (1,012 lines) | Producer inputs all exist: `IsTeleportActive:96`, `ActiveTeleportSequence:97`, `TryGetAcceptedTeleportDestination:522`, `CanPlacePortalDestination:534` (read-only preflight), `TryRegisterHostProjection:189` (idempotent for the same generation/cell — a legitimate token re-derivation path), `AcknowledgePortalMaterialized:595`, `IsCurrentPlacementAuthority:258`. |
|
||||
| `RuntimeAcceptedPositionDriveController` | `src/AcDream.Runtime/Session/RuntimeAcceptedPositionDriveController.cs` (924 lines) | Route 2's landed local-player accepted-Position seam over `TryBeginExclusiveAuthoredPlacement:389` + `TryPrepareAndSubmitAuthoredPlacement:677` (`resolveWorldOffsetFromRuntimeFrame: true`). **ForcePosition-only by gate** (`:340-360`); its `Pending`/ack funnel is ForcePosition-shaped (`PositionEventOwed`). The natural home for a sibling portal arm — but see trap T7 before inheriting any of its funnel. |
|
||||
| `PlayerMovementController` teleport tail | `src/AcDream.Runtime/Gameplay/PlayerMovementController.cs:1845-1920` (`SetPositionCore`) | Today's `controller.SetPosition` on the portal path performs, in one method: body snap, render-lerp anchor reset, `UpdateCellId` publication, Contact\|OnWalkable\|Active transient set, zero velocity, `StopCompletelyAtPhysicsObjectBoundary` (retail StopCompletely 0x00527E40), input-edge/mouse state reset, `UnStick` + `UnConstrain` + `RearmConstraintLeashAtCurrentPosition` (retail @0x0045418A analog), and `_objectClock.ResetForEnterWorld()`. Under a canonical commit the BODY write moves into Runtime's `CommitCanonical`; **every one of these controller-local duties must be re-homed into a teleport analog of `CommitCanonicalForcePositionFrame` (`:1944-1950`)** — losing any one of them is the 4b-2 round-1 defect class. This is the single largest and riskiest piece of the slice. |
|
||||
| classifier LocalPlayer teleport branch | `RuntimeAuthoritativePositionRouteClassifier.cs:349-368` | See §1.3. Production classify callers: the drive controller `:922` (Force only), `ClassifyRemoteAcceptedPosition` (remote/projectile), the continuation executor `:1928` (residence window). |
|
||||
| `SpawnPlacementSettler` | `src/AcDream.Core/Physics/SpawnPlacementSettler.cs:22`; local-player call site `RuntimeLocalPlayerPhysicsPublicationState.cs:812` | First-entry only (C3c-F5/AD-61). **Not invoked on the portal path today, and retail's portal arrival has no settle sweep either** — contact resolves inside `SetPosition`'s own transition (SLIDE flags). Do not add it (trap T10). |
|
||||
| world frame | `RuntimePhysicsState.ObserveLocalWorldFrame:550-562`; callers `RuntimeEntityObjectLifetime.cs:1739/:1794` | Runtime's world frame rebases on `teleportAdvanced` at the accepted-Position merge; App's `LiveWorldOriginState` recenters asynchronously afterwards. See trap T4. |
|
||||
|
||||
### 2.5 What is already canonical and must not regress (J6)
|
||||
|
||||
Slice J6.2/J6.3/J6.4 ownership stands: `RuntimeWorldTransitState` owns the
|
||||
reveal generation, destination latch, F751 correlation (both packet orders),
|
||||
materialization/simulation edge, viewport observation, wait cue, completion/
|
||||
cancellation, and the 4-stage host acknowledgement suffix. Route 3 must not
|
||||
move ANY of that; it only makes the transit owner additionally gate the
|
||||
placement mutation it currently rubber-stamps. The lifecycle gate's
|
||||
`transitOwnership` zero-at-stable-checkpoint discipline
|
||||
(`tools/run-connected-world-lifecycle-gate.ps1`) already covers this state.
|
||||
|
||||
---
|
||||
|
||||
## 3. The dated inventory: claims now false
|
||||
|
||||
The 2026-08-02 route inventory predates C3c, route 2, the four route-4
|
||||
sub-slices, route 5, and the OnPosition collapse. **Eight of its claims
|
||||
bearing on routes 3/8 are now materially false**, plus pervasive stale line
|
||||
numbers:
|
||||
|
||||
1. *"The binding machinery is real but 100% dormant end to end."* — FALSE.
|
||||
The validation half is live at three production layers (§1.1) and runs for
|
||||
every placement (empty-portal case). Only the producer is dormant.
|
||||
2. *"Neither host has ever constructed a production `IRuntimePlacementObserver`
|
||||
implementation"* (prerequisite D "100% unbuilt on the host side") — FALSE.
|
||||
`RuntimePlacementPresentationSink` (graphical) and
|
||||
`HeadlessRuntimePlacementProjectionSink` (headless, wired at
|
||||
`HeadlessSessionHost.cs:701`) are production consumers of the placement
|
||||
FIFO.
|
||||
3. *"`BeginAcceptedPlacement`/`BeginAuthoredPlacement` … zero external callers
|
||||
repo-wide"* / *"a placement transaction … never begun anywhere in
|
||||
production"* — FALSE. Three production controllers drive
|
||||
`TryBeginExclusiveAuthoredPlacement` + `TryPrepareAndSubmitAuthoredPlacement`
|
||||
(local force, remote, first-entry). (The two named legacy wrappers
|
||||
`BeginAcceptedPlacement`/`BeginAuthoredPlacement` themselves are now
|
||||
test-only entry points.)
|
||||
4. *"`InboundPhysicsStateController.TryApplyPosition` is today's only
|
||||
PRODUCTION Position wire caller; the classifier-based path is test-only"*
|
||||
— FALSE since routes 2/4a/4b-2/4b-3/5.
|
||||
5. The entire route-2 chain (`LocalForcePositionTransaction`, pre-commit ack,
|
||||
generic-tail double write for ForcePosition) — GONE; route 2 landed.
|
||||
6. Headless route-8: *"`SynchronizeLocalPlayer` (566-615) is the duplicate
|
||||
placement authority … `CreateController` (639-655) constructs
|
||||
`PlayerMovementController`"* — FALSE at HEAD. C3c deleted the route-1/8
|
||||
initial-entry hand-copy and the controller construction; the ONLY
|
||||
surviving headless duplicate is the renamed portal-arrival re-resolve (D2).
|
||||
7. *"`BlipLocalPlayer` (617-637) direct blip"* — FALSE; deleted by route 2
|
||||
(halves split into `CenterOnAcceptedForcePosition` + the drive controller).
|
||||
8. *"The executor publishes only generic entity deltas; nothing bridges its
|
||||
completion to `RuntimePlacementProjectionChannel`"* — FALSE since C0/C3-1
|
||||
(`ExecutorCompleted` receipts; `TryGetInitialCreateCompletion`).
|
||||
|
||||
Still TRUE from the inventory's route-3 section: the call-chain shape
|
||||
(F751 → queue → offer → aim → `TryBeginPortal` → Place at anim event), the
|
||||
`Place`-mutates-then-`ObserveMaterialized`-rubber-stamps sequencing, the
|
||||
"discard/cancellation semantics structurally sufficient but UNEXERCISED for a
|
||||
real placement" warning (now with live validators, still zero portal-carrying
|
||||
operations — the explicit cutover tests it demanded are still owed), and the
|
||||
executor scope note (portal arrival is a steady-state placement, not a
|
||||
Create admission — the FIFO executor is not the target).
|
||||
|
||||
Stale-but-substantively-true: the offer site (`:1906` → `:2950`), the
|
||||
validator (`:1162` → `:1448`), `PrepareDestination` (`:539` → `:752`,
|
||||
re-resolve retained under a new name), `RuntimeWorldTransitState` still 1,012
|
||||
lines.
|
||||
|
||||
---
|
||||
|
||||
## 4. The missing producer, precisely
|
||||
|
||||
What route 3 must build (and ALL it must build on the authority side):
|
||||
|
||||
1. **The producer**: at the placement moment, construct
|
||||
`new RuntimePortalPlacementAuthority(Present: true, RevealGeneration,
|
||||
ActiveTeleportSequence, hostProjectionToken)` from the live transit state.
|
||||
Graphical: the generation is already at hand
|
||||
(`_pendingRevealGeneration`, `LocalPlayerTeleportController:404/694`), the
|
||||
sequence is `_transit.ActiveTeleportSequence`, and the host token needs a
|
||||
small accessor on `WorldRevealCoordinator` (or re-derivation via the
|
||||
idempotent `TryRegisterHostProjection`). Headless: all three are in scope
|
||||
inside `TryCompletePortal` (generation, `destination.TeleportSequence`,
|
||||
`projection`).
|
||||
2. **The placement call**: a portal arm on the local-player drive seam that
|
||||
runs `TryBeginExclusiveAuthoredPlacement(record, version,
|
||||
LocalAuthoritative, portal)` + `TryPrepareAndSubmitAuthoredPlacement(…,
|
||||
portal, resolveWorldOffsetFromRuntimeFrame: true)` with the classifier's
|
||||
LocalPlayer-teleport route, invoked at each host's existing placement edge
|
||||
(graphical: the `TeleportAnimEvent.Place` handler after
|
||||
`CanPlacePortalDestination`; headless: `PrepareDestination`).
|
||||
3. **The controller-local teleport frame commit** (§2.4's `SetPositionCore`
|
||||
re-homing) invoked on the committed receipt.
|
||||
4. **Re-sequencing**: `AcknowledgePortalMaterialized` fires from the committed
|
||||
placement receipt (it then actually gates — `IsCurrentPlacementAuthority`
|
||||
requires the materialization state it sets), camera reset +
|
||||
`_spatial.Reconcile()` become acknowledge-edge reactions, and D1/D2's
|
||||
direct mutations are deleted.
|
||||
|
||||
**The authority's shape does not need changing** (§2.4). One genuine edge to
|
||||
design for: `BeginAcceptedPlacementCore:1528-1534` validates the authority's
|
||||
destination cell against `record.Snapshot.Physics?.Position ??
|
||||
record.Snapshot.Position` — the LATEST merged Position — while transit pins
|
||||
the FIRST accepted destination per generation (J6.3). A second local Position
|
||||
merging between the offer and the Place edge would make Begin refuse
|
||||
(default token). Today that window is benign (ACE sends one destination per
|
||||
teleport), but the refusal path must be defined and tested rather than
|
||||
discovered: on refusal the transit generation must be cancelled or the
|
||||
placement re-aimed — never a silent wedge in portal space.
|
||||
|
||||
---
|
||||
|
||||
## 5. Retail ground truth (verified in `acclient_2013_pseudo_c.txt` for this scoping; verify again at contract time)
|
||||
|
||||
| claim | address | status |
|
||||
|---|---|---|
|
||||
| F751 (`SmartBox::HandlePlayerTeleport`) writes exactly three flags — `position_update_complete = 0`, `has_been_teleported = 0`, `waiting_for_teleport = 1` — after a wrap-safe TELEPORT_TS check. No position, no cell, no physics. | @0x00452150, writes @0x00452193-0x004521A7 | ✓ read |
|
||||
| `HandleReceivedPosition`'s local/non-local split is `arg2 != this->player` @0x0045414D. The LOCAL teleport branch (`newer_event(TELEPORT_TS)` @0x0045415F): `TeleportPlayer` @0x00454168 → **`ConstrainTo(player, &var_48 /* the WIRE destination */, start, max)` @0x0045418A** → **`set_velocity(player, 0, 1)` @0x004541B4** → return. | @0x00453FD0 | ✓ read |
|
||||
| `SmartBox::TeleportPlayer` is TWO calls: `CPhysicsObj::SetPositionSimple(player, dest, 1)` @0x00453924 and `PlayerPositionUpdated(this, 1, FLT_MAX)` @0x00453932. **The generic placement primitive — the same one route 2 ported** (`BlipPlayer` @0x00453940 is the identical shape with arg 0). | @0x00453910 | ✓ read |
|
||||
| `SetPositionSimple(…, 1)` builds flags **0x1012** = SEND_POSITION_EVENT \| SLIDE \| TELEPORT (`acclient.h:6123`) → generic `CPhysicsObj::SetPosition` @0x005160C0. Identical flags to the remote teleport branch. SLIDE is consumed in `CheckPositionInternal` @0x00511E90 (accept what find_valid_position resolved). | @0x005162B0 (0x1012 @0x005162C2) | ✓ read |
|
||||
| `PlayerPositionUpdated` teleport arm (AFTER the placement): `position_update_complete = 0`, **`waiting_for_teleport = 0` (the F751 wait ends at PLACEMENT, not at reveal)**, `has_been_teleported = 0`, **`teleport_hook(player)`** @0x004538AE, `cmdinterp->PlayerTeleported()` (= `SetAutoRun(0,1)` + `SendMovementEvent`, @0x006B32B0), `set_viewer(&player->m_position, 1)` (camera reset, reset_sought), `LScape::update_viewpoint(0)` (destroys the terrain draw list), `CellManager::ChangePosition(&m_position, 1 /* blocking */)`. | @0x00453870 | ✓ read |
|
||||
| **The hook ordering FLIPS versus the remote route**: local runs `teleport_hook` @0x00514ED0 AFTER `SetPositionSimple` returns (from `PlayerPositionUpdated`); the remote branch runs it BEFORE `SetPosition` (@0x005163EF). The hook `UnConstrain`s @0x00514F0C, and `HandleReceivedPosition` re-arms `ConstrainTo` @0x0045418A after `TeleportPlayer` returns, so the leash survives. The classifier already encodes this (`TeleportHookPhase.AfterPositionOperation` local vs `BeforePositionOperation` remote). | | ✓ read |
|
||||
| **`CPhysicsObj::enter_world` @0x00516170 is NOT on the portal path.** Its local-player caller is the initial-login path only (@0x00455095, with `store_position` + blocking `ChangePosition`). Portal arrival never re-runs `enter_world` or `CPartArray::HandleEnterWorld`/`MovementManager::HandleEnterWorld` — the cell install happens inside `SetPosition` itself. **`2026-07-16-portal-completion-pseudocode.md` §2.1 attributes portal arrival to `enter_world` — that is the login path and the doc needs a correction note** (its conclusion about committing the cell before releasing simulation survives; the cited mechanism is wrong). | callers of 0x00516170 | ✓ read (agent-verified caller sweep) |
|
||||
| The FORCE_POSITION branch (@0x0045400C → `BlipPlayer` → `SendPositionEvent` → return @0x0045409D) never reaches any `ConstrainTo` — route 2's finding reconfirmed. The local TELEPORT branch DOES arm, wire-anchored, and DOES zero velocity — **the inversion trap T1**. | | ✓ read |
|
||||
| Prefetch (#280's oracle, re-verified): blocking `CellManager::ChangePosition` @0x004559B0 releases the old landscape and calls `CellManager::PreFetchCells` @0x00455820 → outdoor `LScape::PreFetchCells` @0x00505660 walking **±`mid_radius`** landblocks (DAT-record residency, not GPU upload); indoor `CEnvCell::PreFetchCells`. `mid_radius` = `Render::m_RenderPrefs.LandscapeDrawDistance` via `SmartBox::SetRegion` @0x00453227 / `set_mid_radius` @0x00453180 — **the prefetch window IS the landscape draw distance, centred on the destination**. While `blocking_for_cells`, `SmartBox::UseTime` @0x00455410 runs ONLY `CheckPrefetchStatus`; object/physics/landscape/game-time/ambient all hold. Reveal (SmartBox::Show) is a further TunnelFadeOut second after the readiness edge; LoginComplete a WorldFadeIn second after that. | | ✓ read |
|
||||
| Retail places IMMEDIATELY on the accepted destination Position and blocks SIMULATION on prefetch behind the portal viewport. acdream inverts this: it holds the PLACEMENT until reveal-readiness (`ready` in `LocalPlayerTeleportController.Tick`) and then places. This is the accepted portal-presentation architecture (J6/E5, user-gated repeatedly) — **route 3 keeps the deferred-Place timing and changes only WHO commits it** (trap T3). | | ✓ (architecture fact) |
|
||||
|
||||
Unverified residuals from the retail pass (mark for the contract, none
|
||||
load-bearing for scope): the exact second argument of `teleport_hook` at
|
||||
@0x004538AE (decompiler-elided, almost certainly 1); `CheckPrefetchStatus`'s
|
||||
apparent 5.0 s re-check throttle (@0x00455BEE — suspicious, byte-verify if
|
||||
#280 uses it); where SEND_POSITION_EVENT/TELEPORT flag bits are consumed
|
||||
below `SetPositionInternal` (not traced; irrelevant to route 3's seam
|
||||
choice).
|
||||
|
||||
---
|
||||
|
||||
## 6. Shape sketch (scoping altitude — the contract pins the real design)
|
||||
|
||||
- **Runtime**: a portal arm on `RuntimeAcceptedPositionDriveController` (a
|
||||
sibling entry point, e.g. `TryExecuteAcceptedPortalArrival(record, route,
|
||||
authority)`), sharing Begin/Submit/status handling with the force arm but
|
||||
NOT its `PositionEventOwed`/re-issue funnel (trap T7). It consumes the
|
||||
classifier's LocalPlayer-teleport route, applies `ZeroVelocity`, invokes
|
||||
the controller-local teleport frame commit on the committed receipt, and
|
||||
arms the leash post-operation (the route's `ConstrainPhase` — today's
|
||||
`SetPositionCore` re-arm relocates here).
|
||||
- **Graphical**: `LocalPlayerTeleportPlacement.Place` becomes
|
||||
acknowledge-only — build the authority, call the Runtime arm, and on the
|
||||
committed receipt run the presentation suffix (camera resets,
|
||||
`NotifyTeleported`, `_spatial.Reconcile()`), then
|
||||
`ObserveMaterialized`. The direct Resolve/SetPosition/entity-write/rebucket
|
||||
bodies are deleted; the render entity moves via the existing
|
||||
`RuntimePlacementPresentationSink` Place projection (whose portal gate
|
||||
finally goes live).
|
||||
- **Headless**: `PrepareDestination` keeps `CenterOn` + readiness reporting +
|
||||
state writes; `ResynchronizeLocalPlayerForPortalArrival` is deleted and the
|
||||
same Runtime arm is driven from the portal completion flow.
|
||||
- **Probe**: `ACDREAM_PROBE_LOCAL_TELEPORT=1` (PhysicsDiagnostics-owned,
|
||||
TEMPORARY family) — one line per portal arrival with cause
|
||||
(portal/recall), placement status, portal generation/sequence,
|
||||
destination cell, and hook/leash confirmation.
|
||||
|
||||
Register bookkeeping to expect (contract finalizes): AD-42's headless
|
||||
portal-arrival-resync citation dies with D2; locate-or-add the row recording
|
||||
the deferred-place timing adaptation (§5 last row — **UNVERIFIED whether an
|
||||
existing AD row states it**; if none exists the route-3 commit must add it —
|
||||
a deviation without a row is a bug twice over); the 2026-07-16 pseudocode
|
||||
correction note (§5); the stale `:2276` comment (§2.2) corrected or the
|
||||
finding filed.
|
||||
|
||||
---
|
||||
|
||||
## 7. #280 — definitive recommendation: SPLIT (do not bundle into route 3)
|
||||
|
||||
**The campaign plan and the session handoff disagree, and the plan is
|
||||
right.** The plan lists #280 as its own numbered work item (item 3 of the
|
||||
remaining campaign work), separate from "finish C4's routes 2-7" (item 2).
|
||||
Only the 2026-08-04 session handoff says "#280 rides with [route 3]". They
|
||||
cannot both be followed; this scoping recommends the plan's sequencing.
|
||||
|
||||
Why they are mechanically distinct:
|
||||
|
||||
- **Route 3 changes WHO commits the placement.** Its blast radius is
|
||||
`RuntimeSetPositionState`/drive-controller/`PlayerMovementController`/the
|
||||
two host placement bodies. It does not touch readiness evaluation at all —
|
||||
the `ready` predicate in `LocalPlayerTeleportController.Tick:489-493` and
|
||||
everything behind `WorldRevealCoordinator.Evaluate` is read, not written.
|
||||
- **#280 changes WHAT the reveal waits for.** Its fix shape (per its own
|
||||
ISSUES entry, whose retail oracle this scoping re-verified §5): replace
|
||||
`WorldRevealReadinessBarrier.OutdoorNeighborhoodRadius = 1`
|
||||
(`src/AcDream.App/Streaming/WorldRevealReadinessBarrier.cs:38`) with a
|
||||
retail-derived, quality-configured destination prefetch window
|
||||
(`mid_radius` == landscape draw distance) and hold one generation-scoped
|
||||
reservation across terrain/statics/EnvCells/render
|
||||
publication/composites/collision until the complete visible window is
|
||||
ready. Its blast radius is streaming/reveal/render-resource scheduling —
|
||||
`WorldRevealReadinessBarrier`, `GpuWorldState` readiness joins, the
|
||||
streaming reservation schedulers. It does not touch placement.
|
||||
- The ONLY shared surface is the transit lifecycle both sit inside — and J6
|
||||
already owns that; neither change moves it.
|
||||
- Bundling would put a placement-authority cutover (physics-review skillset,
|
||||
connected teleport gate) and a streaming-window change (render/streaming
|
||||
skillset, view-distance visual gate at multiple quality settings) in one
|
||||
diff, and would push the slice far past the ~500-line budget (#280 alone
|
||||
plausibly rivals route 3 in size). 4b-2's process lesson ("split on
|
||||
discovery; a defect outside scope rides for three review rounds") applies
|
||||
prospectively here.
|
||||
|
||||
Sequencing: #280 can land before or after route 3 with no dependency in
|
||||
either direction — route 3 keeps the Place gated on the SAME `ready`
|
||||
predicate, whatever radius that predicate uses. Recommend: route 3 first
|
||||
(closes C4), #280 immediately after as its own slice with its own visual
|
||||
gate, before C5's closeout matrix (the campaign plan already sequences it
|
||||
exactly there).
|
||||
|
||||
One honest caveat: bundling advocates would note both changes gate "what
|
||||
happens at the Place edge" and a single connected session could gate both.
|
||||
True but insufficient — a shared test session is not a shared mechanism, and
|
||||
the review lenses are disjoint.
|
||||
|
||||
---
|
||||
|
||||
## 8. Size estimate and split recommendation
|
||||
|
||||
Calibration: route 4a 364; 4b-1 230+57; 4b-2 350-500; 4b-3 ~250 net new
|
||||
(400-700 budget) with 739 deleted; route 5 ~131 added, ~180 deleted.
|
||||
|
||||
| piece | est. non-comment production lines |
|
||||
|---|---|
|
||||
| Runtime portal arm on the drive controller (Begin/Submit/status/receipt handling, ZeroVelocity, leash arm) | 90-150 |
|
||||
| `PlayerMovementController` teleport frame commit (re-home the `SetPositionCore` suffix; split shared private helpers) | 40-80 |
|
||||
| Graphical producer + `Place` rewrite + `ObserveMaterialized`/camera/reconcile re-sequencing | 60-110 (deletes ~55) |
|
||||
| `WorldRevealCoordinator` host-token exposure | 10-20 |
|
||||
| Headless: `PrepareDestination` flip + drive call | 15-30 (deletes ~50 incl. D2) |
|
||||
| Probe line | ~10 |
|
||||
| **Total added** | **~225-400** |
|
||||
|
||||
Net roughly +150 to +250 (deletions ~105-120). Tests are the larger share, an
|
||||
estimated 500-900 lines (per-outcome placement tests on the portal arm,
|
||||
supersession/cancellation/stale-generation discard tests — the inventory's
|
||||
still-owed "explicit cutover test" for the discard semantics — presentation
|
||||
assertions at #312's layer, dual-host parity, the Begin cell-mismatch edge of
|
||||
§4).
|
||||
|
||||
**Recommendation: ONE slice, no split** — comfortably under the ~500
|
||||
threshold PROVIDED #280 splits out (§7). Stop-and-report conditions for the
|
||||
implementer: added production lines exceed ~500; the design starts needing
|
||||
changes to `RuntimeWorldTransitState`'s lifecycle semantics, the
|
||||
`TeleportAnimSequencer` timings, or the readiness barrier (each is a sign
|
||||
#280 or a J6 regression is being smuggled in); or the Begin cell-mismatch
|
||||
edge (§4) turns out to be reachable in ordinary play.
|
||||
|
||||
Allocation: a portal placement is once-per-teleport, not frame-frequency —
|
||||
the C2 1,536 B budget is not an activation blocker here (route 2's
|
||||
reasoning applies). Do not spend lines pooling.
|
||||
|
||||
---
|
||||
|
||||
## 9. The connected gate (real and mandatory — unlike route 5)
|
||||
|
||||
Portals are trivially reachable and user-visible; a live gate exists and is
|
||||
required. **A clean-looking session is NOT a pass** (process rule 5; 4b-3's
|
||||
gate was a pass only because 16 probe lines proved the arm executed, and its
|
||||
cell-less half is still honestly recorded as unverified).
|
||||
|
||||
**Recipe (user-run, graphical):** Release build, `ACDREAM_RETAIL_UI=1`,
|
||||
`ACDREAM_PROBE_LOCAL_TELEPORT=1`, live ACE. Exercise, in one session:
|
||||
1. a physical portal (e.g. Holtburg portal) — outdoor destination;
|
||||
2. a dungeon portal (indoor destination, EnvCell readiness path);
|
||||
3. `/ls` lifestone recall and one spell recall (the F751 recall family);
|
||||
4. an ACE admin teleport of the LOCAL player (`@teleto`/`@teleloc`) — this
|
||||
advances ObjectTeleport and, per the route-2 visual-gate doc, exercises
|
||||
exactly this route;
|
||||
5. a same-destination revisit (ACE may omit CreateObject on revisit);
|
||||
6. graceful close.
|
||||
|
||||
**Pass requires ALL of:**
|
||||
- one probe line per arrival showing the CANONICAL path executed:
|
||||
`placement=Committed`, the portal authority's generation/sequence, and the
|
||||
resolved destination cell — zero arrivals through the deleted path (which
|
||||
no longer exists to run) and zero `Refused/Contention` lines in ordinary
|
||||
play;
|
||||
- user visual: purple materialization silhouette without an opaque pop or
|
||||
late tail (the 2026-07-25 accepted baseline must not regress), camera
|
||||
reset behind the player at arrival, movement works immediately (walk out
|
||||
with W held — the input-edge reset half of the teleport frame commit),
|
||||
idle stance not a run-in-place, **no rubber-band or tether after arrival
|
||||
AND no leash absence** (the leash IS armed on this route — a creature-free
|
||||
way to observe it is beyond a visual check, so add a probe field
|
||||
`leash=armed` instead of inventing a visual);
|
||||
- the exact lifecycle/reconnect gate
|
||||
(`tools/run-connected-world-lifecycle-gate.ps1`) passes with every
|
||||
`transitOwnership` counter zero at every stable checkpoint — this is the
|
||||
supersession/cancellation convergence evidence;
|
||||
- **headless parity**: the K-style connected portal route (four-stop portal
|
||||
routing from the K3 closeout) with the probe enabled — same
|
||||
probe-line-per-arrival requirement, proving D2's replacement executed on
|
||||
the no-window host.
|
||||
|
||||
**Known gap to state up front, 4b-3-style:** mid-transit supersession (a
|
||||
second teleport starting before the first materializes) and mid-transit
|
||||
disconnect are hard to provoke against ACE on demand. If the session does
|
||||
not produce them, record the stale-generation discard behaviour as
|
||||
test-verified-only — do not fold it into a blanket "gate passed".
|
||||
|
||||
---
|
||||
|
||||
## 10. Traps — rules from earlier routes that flip or do not transfer
|
||||
|
||||
- **T1 — route 2's leash rule INVERTS.** Route 2 pinned "the constraint
|
||||
leash is NOT re-armed" because the FORCE_POSITION branch returns at
|
||||
@0x0045409D before every `ConstrainTo`. The local TELEPORT branch is the
|
||||
opposite: retail arms `ConstrainTo` @0x0045418A (anchored at the received
|
||||
destination) AND zeroes velocity @0x004541B4. The classifier already
|
||||
carries both (`ConstrainPhase.AfterPositionOperation`,
|
||||
`ZeroVelocity: true`); the drive-controller doc comment
|
||||
(`RuntimeAcceptedPositionDriveController.cs:127-132`) explaining why the
|
||||
force arm never arms MUST NOT be generalized to the portal arm. Also
|
||||
inverted: `SendPositionImmediately` is FALSE (no `AutonomousPosition` ack
|
||||
on this route — retail's teleport branch returns without
|
||||
`SendPositionEvent`; the outbound tail is LoginComplete, which stays where
|
||||
it is, see T11) and `PreserveHeading` is FALSE (the wire orientation
|
||||
applies).
|
||||
- **T2 — 4b-3's hook ordering INVERTS.** Remote: `teleport_hook` BEFORE the
|
||||
placement (@0x005163EF). Local: the hook runs AFTER `SetPositionSimple`,
|
||||
from `PlayerPositionUpdated` @0x004538AE. The classifier encodes the flip
|
||||
(`AfterPositionOperation` vs `BeforePositionOperation`). Copying 4b-3's
|
||||
hook-first arm shape onto the local route would be retail-wrong. Also: the
|
||||
local "hook" is not `RemoteTeleportHook` — its live actions for the local
|
||||
player are the controller-local UnStick/UnConstrain (+ re-arm afterwards),
|
||||
`NotifyTeleported` (TargetManager pair), the autorun cancel
|
||||
(`PlayerTeleported` → `SetAutoRun(0,1)` — verify against the J5.4 autorun
|
||||
latch at contract time), and `report_collision_end`.
|
||||
- **T3 — do NOT move the placement to packet-accept time.** Retail places
|
||||
immediately and blocks simulation on DAT prefetch; acdream's accepted
|
||||
portal architecture defers the placement to the reveal-ready Place edge
|
||||
behind the portal viewport (user-gated repeatedly; J6/E5). Route 3 changes
|
||||
the executor of the Place, never its timing. An implementer "fixing" the
|
||||
timing toward retail would regress the whole accepted presentation and
|
||||
collide with #280's territory. Locate-or-add the register row for this
|
||||
adaptation (§6).
|
||||
- **T4 — two world frames disagree during the teleport window (#283).**
|
||||
Runtime's frame rebases at the accepted teleport Position's merge
|
||||
(`ObserveLocalWorldFrame(…, teleportAdvanced: true)`); App's
|
||||
`LiveWorldOriginState` recenters asynchronously. Today `Place` runs only
|
||||
after `!IsRecenterPending` (inside `ready`), so both frames agree at
|
||||
placement time. The canonical arm must keep that gating and must resolve
|
||||
through Runtime's frame (`resolveWorldOffsetFromRuntimeFrame: true`, as
|
||||
route 2 does) — the App-translated `_pendingPosition` vector dies with D1.
|
||||
A placement submitted during the disagreement window is the failure mode.
|
||||
- **T5 — the Begin cell-mismatch edge** (§4): transit pins the FIRST
|
||||
accepted destination per generation; Begin validates against the LATEST
|
||||
merged snapshot. Define and test the refusal path; never wedge in portal
|
||||
space.
|
||||
- **T6 — hands off J6 and the presentation.** `RuntimeWorldTransitState`'s
|
||||
lifecycle semantics, the 4-stage host acknowledgement, the
|
||||
`TeleportAnimSequencer` seven-state machine, AD-38's viewport-retire
|
||||
timing, the wait cue, and `TeleportViewPlaneController` are all
|
||||
user-accepted and out of scope. The ONLY transit-adjacent change is that
|
||||
`AcknowledgePortalMaterialized` fires from the commit receipt instead of
|
||||
rubber-stamping after a host mutation.
|
||||
- **T7 — do not inherit the force arm's funnel.** `PositionEventOwed`, the
|
||||
`_newestForce` re-issue observation (AD-62), and `SendImmediatePosition`
|
||||
are ForcePosition-shaped: ACE never repeats a portal destination, the
|
||||
portal route owes no AutonomousPosition ack, and a dead-watch re-issue of
|
||||
a portal placement would fight the transit generation. The portal arm
|
||||
shares Begin/Submit/receipt handling only. (The mirror of 4b's "do NOT
|
||||
port route 2's re-issue funnel" lesson.)
|
||||
- **T8 — the local generic render-pose write is a pre-existing second
|
||||
writer; do not silently delete OR silently keep it.** Every accepted local
|
||||
Apply — including the portal destination Position — writes the raw wire
|
||||
pose to the local player's `WorldEntity` and rebuckets to the wire
|
||||
landblock (`:2284-2289`/`:2314`; the `:2276` comment claiming otherwise is
|
||||
stale). Hidden by the portal viewport today and overwritten by Place. It
|
||||
is AP-131/#275 (the ordinary local Apply path no route owns) — route 3
|
||||
must TOLERATE it (the canonical projection overwrites on commit) and the
|
||||
contract must decide explicitly whether the teleport window suppresses it;
|
||||
whichever way, correct the stale comment (process rule 6).
|
||||
- **T9 — no allocation work.** Once-per-teleport; the C2 budget is not in
|
||||
play.
|
||||
- **T10 — no settle sweep.** `SpawnPlacementSettler` is first-entry-only
|
||||
(C3c-F5); retail's portal arrival has none — contact resolves inside the
|
||||
SLIDE placement itself. If arrival contact looks wrong in the gate, the
|
||||
bug is in the placement flags/transition, not a missing settle.
|
||||
- **T11 — LoginComplete does not move.** It stays on
|
||||
`TeleportAnimEvent.FireLoginComplete` (retail: ~2 s after reveal; TS-28 is
|
||||
narrowed to initial login only). C3c's `175ad6b0` moved LOGIN's
|
||||
LoginComplete to the first-placement terminal edge — that reasoning does
|
||||
NOT transfer to the portal route.
|
||||
- **T12 — headless keeps its non-placement duties.** `PrepareDestination`'s
|
||||
`CenterOn`, readiness report, and `PlayerState` writes stay host-owned;
|
||||
only the D2 re-resolve body flips. `BeginTeleport`'s direct
|
||||
`PlayerState.PortalSpace` write is out of scope.
|
||||
|
||||
---
|
||||
|
||||
## 11. What route 3 does NOT do / what remains for C5
|
||||
|
||||
- **#280** — split out (§7); its own slice with its own visual gate.
|
||||
- **AP-131 / #275** — the shared merge call and the ordinary local Apply
|
||||
path (including T8's generic write) stay for C5.
|
||||
- **AP-1/AD-1 retirement, the legacy-deletion sweep, parity tests, the
|
||||
final connected matrix** — C5. Route 3's deletions are only D1/D2's bodies
|
||||
and their direct wiring; any surviving dead seams
|
||||
(`ILocalPlayerTeleportPlacement` if it reduces to a trivial adapter,
|
||||
legacy `BeginAcceptedPlacement`/`BeginAuthoredPlacement` test-only
|
||||
wrappers) are C5 sweep candidates, recorded not deleted here.
|
||||
- **Route 7** (pickup/parent/delete) — separate, already scoped.
|
||||
- **No headless remote consumer, no reveal-gate changes, no presentation/
|
||||
anim/viewport changes, no `enter_world`/`HandleEnterWorld` additions**
|
||||
(retail does not run them on this path — §5).
|
||||
- The six `LiveEntityRuntimeTests` fixture failures named in the campaign
|
||||
handoff and the final-binary soak remain campaign-level obligations, not
|
||||
route-3 scope.
|
||||
|
||||
## 12. Open gaps (each with the check that closes it)
|
||||
|
||||
1. **The deferred-place register row** — grep the divergence register for
|
||||
the portal place-at-readiness adaptation; if absent, the route-3 commit
|
||||
adds it (T3).
|
||||
2. **The autorun cancel** — confirm acdream's arrival path cancels autorun
|
||||
(retail `PlayerTeleported` → `SetAutoRun(0,1)`): read the J5.4
|
||||
`RuntimeLocalPlayerMovementState` autorun latch against
|
||||
`SetPositionCore`'s input reset.
|
||||
3. **`WorldRevealCoordinator` token exposure shape** — accessor vs
|
||||
re-registration; decide at contract with a test that a superseded token
|
||||
can never be handed to the producer.
|
||||
4. **The Begin cell-mismatch refusal path** (§4/T5) — design + test.
|
||||
5. **Retail residuals** from §5's unverified list (teleport_hook arg,
|
||||
prefetch throttle) — byte-verify only if the contract leans on them.
|
||||
6. **`RuntimePlacementPresentationSink` Place projection for the local
|
||||
player** — route 2's B2 recorded that no test drives a local-player
|
||||
Place end-to-end through the sink to a moved `WorldEntity`; route 3 makes
|
||||
that seam load-bearing for portals and MUST close the coverage gap (an
|
||||
App-layer test asserting the render entity moved from the committed
|
||||
receipt), not inherit it.
|
||||
|
||||
---
|
||||
|
||||
## Summary for the campaign plan
|
||||
|
||||
- **Size: ~225-400 added non-comment production lines, net ~+150-250 — ONE
|
||||
slice, no split** (contingent on #280 splitting out).
|
||||
- **#280: SPLIT.** The handoff's "rides with route 3" is wrong; the campaign
|
||||
plan's own sequencing (separate item) is right. Reveal-window/streaming
|
||||
concern, not placement.
|
||||
- **Eight dated-inventory claims now false** (§3), the most consequential
|
||||
being "100% dormant end to end" — the validation half of the portal
|
||||
machinery is live production code; only the producer is missing.
|
||||
- **Contradictions with the campaign plan:** (a) plan line ~92-93's "the
|
||||
adapter … does not exist" overstates the gap — only the producer is
|
||||
missing; (b) the plan's #280 sequencing contradicts the session handoff's
|
||||
bundling — this scoping sides with the plan; (c) the inventory's "route
|
||||
3's target is `RuntimeSetPositionState` directly" is refined: the target
|
||||
is a portal arm on route 2's `RuntimeAcceptedPositionDriveController` seam
|
||||
OVER `RuntimeSetPositionState`.
|
||||
- **Two documentation defects found while verifying:** the 2026-07-16 portal
|
||||
pseudocode attributes portal arrival to `enter_world` (that is the LOGIN
|
||||
path — needs a correction note), and
|
||||
`LiveEntityNetworkUpdateController.cs:2276`'s "the local player never
|
||||
reaches this generic-remote code path" is false for
|
||||
`TryApplyGenericRemoteRenderPose`/`RebucketLiveEntity` (T8).
|
||||
Loading…
Add table
Add a link
Reference in a new issue