User-run against the exact 6dc7ba51 Release binary with the retail UI; user
verdict "all works". The probe proves the run actually exercised the arm: 16
[remote-teleport] lines over 7 creatures, all hookRan=True placement=Committed,
every guid in the 0x8xxxxxxx creature range rather than the 0x50xxxxxx player
range — so the corrected creature-target recipe reached the NPC-guid branch
where all three NPC-arm MAJORs lived.
Recorded as a partial pass, not a blanket one: all 16 lines are
cause=teleport-ts and cause=cellless was never observed, so the cell-less half
of the same arm remains test-covered only. Folding that into "gate passed"
would repeat 4b-2's #309 shape, where every park probe shared one cause and the
unexercised cause went unrecorded.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
710 lines
46 KiB
Markdown
710 lines
46 KiB
Markdown
# C4 route 4b-3 — remote teleport + cell-less: pinned contract (2026-08-04)
|
|
|
|
Split rationale:
|
|
[`2026-08-04-c4-route-4b-scoping-and-split.md`](2026-08-04-c4-route-4b-scoping-and-split.md).
|
|
4b-1 (infrastructure) landed at `2e8e09ac`; 4b-2 (far snap) landed at
|
|
`7f1c1f5a` after four fix rounds; the shared-core park restore it forced is at
|
|
`634bc551` and inside 4b-2's rounds 3/4. Read the whole findings chain before
|
|
implementing — every defect class it names reappears here at larger scale:
|
|
[round 1](2026-08-04-c4-route-4b-2-review-findings.md) →
|
|
[round 2 (delta)](2026-08-04-c4-route-4b-2-delta-review-findings.md) →
|
|
[round 3](2026-08-04-c4-route-4b-2-round3-correction.md) →
|
|
[round 4](2026-08-04-c4-route-4b-2-round4-correction.md).
|
|
|
|
**4b-3 flips the LAST remote classification on: `SetPosition` — teleport
|
|
(TELEPORT_TS advanced) and cell-less (the body has no committed cell) — through
|
|
4b-1's `RuntimeRemotePlacementDriveController`, runs retail's `teleport_hook`
|
|
before the placement, and deletes the legacy remote-teleport machinery:
|
|
`RemoteTeleportController` (605 lines), `RemoteTeleportPlacement` (85),
|
|
`RemoteShadowPlacementSynchronizer` (49, two classes), the
|
|
`remotePlacementRequired` predicate, the `TeleportHookRequired` timestamp
|
|
plumbing, the legacy pre-operation `ConstrainTo` fallback, and the player arm's
|
|
legacy `!update.IsGrounded` fallback — plus 1,709 lines of their tests.**
|
|
|
|
This retires AP-137's cell-less enqueue-vs-place delta. AP-135 does NOT retire
|
|
(its two writes sit physically inside the method this slice rewrites — see
|
|
"Must remain true" item 8). AP-131 does not retire. #276 does not close.
|
|
|
|
## Retail ground truth — verified in `acclient_2013_pseudo_c.txt`, verify again yourself
|
|
|
|
`CPhysicsObj::MoveOrTeleport` @0x00516330, teleport/cell-less branch:
|
|
|
|
```
|
|
00516375 eax_8 = CPhysicsObj::newer_event(this_1, TELEPORT_TS, arg3);
|
|
00516386 if ((eax_8 != 0 || this_1->cell == 0)) {
|
|
005163ef CPhysicsObj::teleport_hook(this_1, edx_2);
|
|
005163f8 SetPositionStruct::SetPositionStruct(&var_64);
|
|
00516406 SetPositionStruct::SetPosition(&var_64, arg2);
|
|
00516414 SetPositionStruct::SetFlags(&var_64, 0x1012);
|
|
00516420 CPhysicsObj::SetPosition(this_1, &var_64);
|
|
00516438 return 1;
|
|
00516386 }
|
|
0051638e if (arg4 != 0) { ... near @0x005163AF / far @0x005163C1-E8 ... }
|
|
0051636d return 0;
|
|
```
|
|
|
|
Five facts in that listing decide this slice:
|
|
|
|
1. **The teleport branch is decided BEFORE the contact test** (`arg4` is only
|
|
read @0x0051638E, after the branch). A teleport/cell-less packet places
|
|
unconditionally — airborne wire bit, airborne body, any distance. acdream's
|
|
routing must therefore decide the teleport arm AHEAD of every
|
|
airborne/landing carve-out (see design decision D5).
|
|
2. **`this_1->cell == 0` is the BODY's current cell** — "this object has no
|
|
resolved cell right now" — not the wire destination's cell. See D1: the
|
|
classifier's current input implements a different (and dead) predicate.
|
|
3. **`teleport_hook` @0x00514ED0 runs BEFORE the placement** and is, complete
|
|
(each guarded on the manager existing):
|
|
`MovementManager::CancelMoveTo(0x3C)` @0x00514EDF,
|
|
`PositionManager::UnStick` @0x00514EEE,
|
|
`PositionManager::StopInterpolating` @0x00514EFD,
|
|
`PositionManager::UnConstrain` @0x00514F0C,
|
|
`TargetManager::ClearTarget` @0x00514F1B +
|
|
`TargetManager::NotifyVoyeurOfEvent(Teleported_TargetStatus)` @0x00514F28,
|
|
`CPhysicsObj::report_collision_end(this, 1)` @0x00514F31.
|
|
4. **`SetFlags(0x1012)`** (`Teleport|Slide|SendPositionEvent`) @0x00516414 —
|
|
acdream's analog is the classifier's `AuthoritativeTeleportFlags`, carried on
|
|
`route.SetPositionFlags` into
|
|
`RuntimeSetPositionState.TryPrepareAndSubmitAuthoredPlacement`'s `flags`
|
|
parameter. (There is NO separate "teleport hook phase support" inside
|
|
`RuntimeSetPositionState` — the phase lives on the route,
|
|
`RuntimeTeleportHookPhase.BeforePositionOperation`, emitted at the
|
|
classifier's remote teleport/cell-less branch. The handoff's phrasing
|
|
implied otherwise; this is the correction.)
|
|
5. **The branch returns 1 and discards `SetPosition`'s error**, so
|
|
`SmartBox::HandleReceivedPosition` @0x00453FD0 arms `ConstrainTo`
|
|
@0x00454272 — the remote arm's ONLY arming site, shared by all three
|
|
nonzero-returning branches, anchored `&arg2->m_position` read live
|
|
(post-move). Retail arms even when the placement failed. So: hook
|
|
`UnConstrain` first, place, then ONE post-operation re-arm — never a second
|
|
arming site, and arm on non-commit outcomes too (the 4b-2 B8/R5 lesson).
|
|
|
|
## What must REMAIN true (process rule 1 — the contract causes the defect)
|
|
|
|
For every path this slice adds or rewrites, including every refusal,
|
|
contention, rejection, and short-circuit:
|
|
|
|
1. **The pose still advances.** A teleport-classified packet whose canonical
|
|
placement never reached the engine (`Refused` / `Contention` /
|
|
`RejectedPreparation` / `NotApplicable`) still commits the accepted
|
|
destination pose to the canonical body — the same
|
|
`StoresAcceptedDestination` partition and the same
|
|
`StoreAcceptedDestinationPose` the far arm uses, which is retail's
|
|
`store_position` @0x00515CE2 on the no-transition branch. `Deferred` and
|
|
`RejectedByPlacement` do NOT store, for the reasons already pinned in the
|
|
enum's own doc (`ParkDeferred` already snapped; the engine ran and
|
|
refused / a settled pose must survive). Do not re-litigate the partition —
|
|
extend it to the teleport arm unchanged.
|
|
2. **The render entity still advances.** The teleport arm's tail syncs
|
|
`WorldEntity` (position, `ParentCellId`, rotation) from the RESOLVED body
|
|
and publishes the collision shadow, exactly as both existing grounded arm
|
|
tails do (`LiveEntityShadowPublisher.TryPublishRemote`). A teleport must
|
|
never leave the rendered pose a packet behind the body. #312's lesson:
|
|
presentation state is where this family breaks; tests must assert it
|
|
(see Test plan).
|
|
3. **The object clock keeps running and the entity stays in the world** on
|
|
every non-commit outcome: `body.InWorld`, `TransientStateFlags.Active`,
|
|
`record.ObjectClock` active, `FullCellId != 0`, spatial projection intact,
|
|
`IsSpatiallyVisible` unchanged. No park survives the controller
|
|
(`CancelToken` with `restoreCancelledPark: true`); the pre-flight
|
|
(`CanAttemptDestination`) stays an OPTIMISATION, never the reason a remote
|
|
stops tracking or becomes invisible.
|
|
4. **The interpolation queue is empty after the teleport arm runs** —
|
|
cleared by the hook's `StopInterpolating` (@0x00514EFD), NOT by the route
|
|
flag: the classifier's teleport branch deliberately carries
|
|
`StopInterpolating: false` because retail's clear lives inside the hook.
|
|
The far arm's route-flag-driven clear is untouched.
|
|
5. **The leash is armed exactly once per accepted packet**, post-operation,
|
|
anchored post-move, by the classification partition — never zero times
|
|
(the current shipped hole: `remotePlacementRequired` returns ahead of every
|
|
arming site while `RemoteTeleportHook` has already `UnConstrain`ed, so a
|
|
remote that teleports and stands still is leash-less until the next
|
|
packet), and never twice. See D4 for the complete partition.
|
|
6. **The per-packet prologue keeps running for every classification**:
|
|
`TryApplyGenericRemoteRenderPose` (see D6 for the gate), the
|
|
`RebucketLiveEntity(update.Guid, p.LandblockId)` spatial-bucket
|
|
transaction, the velocity install
|
|
(`TryCommitAuthoritativeVelocity` — retail's PositionPack `set_velocity`,
|
|
upstream of `MoveOrTeleport`), and the incarnation re-validation
|
|
chain. Retail's remote teleport never writes velocity itself
|
|
(`ZeroVelocity` is the LOCAL player's `SmartBox::TeleportPlayer`
|
|
@0x004541B4 only); the teleport arm must not add a velocity write.
|
|
7. **`AcceptedPositionSource`/authority validation is unchanged.** The
|
|
teleport arm executes only an already-classified route from
|
|
`ClassifyRemoteAcceptedPosition` — the shared builder
|
|
(`RuntimeAcceptedPositionRouteRequests`), never a re-derivation.
|
|
8. **AP-135's two writes stay**, on both arms' airborne no-op
|
|
neighbourhoods: the server-cell adopt (`rmState.CellId = p.LandblockId`)
|
|
and the `LastServerPos`/`LastServerPosTime` sample. They are 4a-owned
|
|
acdream-only bookkeeping for the free-fall sweep gate
|
|
(`RuntimeRemotePhysicsUpdater`'s `rm.CellId != 0` gate) and the
|
|
first-grounded-packet velocity synthesis. This slice rewrites the method
|
|
they sit in; they do not go. The register row does not retire.
|
|
9. **`ParkCollisionResidents`'s overlap throw stays unreachable** — see
|
|
"Proof obligations".
|
|
10. **`ArmLostFamilyDeadlines`' reaper gains no production caller.**
|
|
`TickLostCellDeadlines` and `TryDequeueExpiredLostCell`
|
|
(`RuntimeSetPositionState`) have zero production callers today; this
|
|
slice must not add one. `ParkDeferred` arming the family (its
|
|
`ArmLostFamilyDeadlines` call) is pre-existing and stays inert.
|
|
11. **Route 1's classification inputs are unchanged.**
|
|
`RuntimeInitialCreateContinuationExecutor`'s calls into the shared
|
|
builder keep their current semantics (D1 adds an overload for the remote
|
|
PositionEvent path; the builder's own doc mandates "an overload here,
|
|
never a third copy").
|
|
12. **The 4a dispositions are untouched**: `NoPositionOperation` writes
|
|
nothing (plus item 8's bookkeeping), `Interpolate` enqueues, the landing
|
|
block still hard-snaps a wire-grounded packet for a not-in-contact body
|
|
on 4a-owned classifications, AP-87's snap conditions and AP-139's landing
|
|
clear are unchanged.
|
|
13. **The far arm (4b-2) is untouched** except where a shared gate widens to
|
|
include the teleport arm (D6, D7) — widening must not change the far
|
|
arm's own behaviour. Everything round 2's/round 4's "do not churn" lists
|
|
verified stays: the `StoresAcceptedDestination` partition, the
|
|
`IsRestorableQuiescencePark` relocation, the pose-parity composition, the
|
|
two-arm guard/arm ordering.
|
|
|
|
## Design decisions — pinned, not open for redesign
|
|
|
|
### D1 — the classifier's cell-less input becomes the PRE-merge committed cell (resolves trap T1 and undetermined item 3)
|
|
|
|
**Finding (undetermined item 3, now determined by reading the code):** the
|
|
merge cannot zero a previously-nonzero `FullCellId` — it does the opposite.
|
|
`RuntimeEntityObjectLifetime.TryApplyPosition` calls
|
|
`Entities.RefreshSnapshot(canonical, snapshot, refreshPosition: acceptedPosition)`
|
|
for every accepted Position, and `RuntimeEntityRecord.RefreshDerivedState`
|
|
then executes `SetFullCell(position.LandblockId, …)` from the just-merged
|
|
snapshot. So at classification time (OnPosition classifies after the
|
|
authority gate's merge, before the prologue rebucket), `canonical.FullCellId`
|
|
IS the accepted wire cell. A wire cell of 0 fails
|
|
`LandDefs.InboundValidCellId` inside `PositionFrameValidation.IsValid`, which
|
|
the classifier's `ValidPosition` check turns into `RejectedData` BEFORE the
|
|
cell-less test. **Consequence: the classifier's remote `cellless` predicate,
|
|
as fed today (`CommittedCellId: canonical.FullCellId` in
|
|
`RuntimeAcceptedPositionRouteRequests.Build`), is unreachable for a remote
|
|
PositionEvent — the remote `SetPosition` classification currently fires on
|
|
`TeleportAdvanced` alone.** It is not a subset relationship with
|
|
`remotePlacementRequired`; it is a dead predicate. (The classifier's own
|
|
comment above the test — "only a later Runtime SetPosition or simulation
|
|
commit may change FullCellId" — is falsified by `RefreshDerivedState` and
|
|
must be corrected in this slice; process rule 6.)
|
|
|
|
Retail's predicate is the BODY's current cell (`this_1->cell == 0` read at
|
|
`MoveOrTeleport` entry, before any placement) — "this object is not resident
|
|
anywhere right now", e.g. the first Position after an unwield-to-3D
|
|
(`SetFullCell(0,0)` at the pickup/parent leave-world sites) or after any
|
|
canonical withdrawal. The acdream value with exactly that meaning is the
|
|
committed cell BEFORE this packet's merge — the `wasCellless`/`beforeCell`
|
|
pair `TryApplyPosition` already measures.
|
|
|
|
**Pinned:** thread the pre-merge committed cell out of the merge and into the
|
|
remote classification's `CommittedCellId` input, via an overload of the shared
|
|
builder (never a third copy; never a change to the existing overloads' route-1
|
|
semantics). Plumbing shape is the implementer's choice — the natural carrier
|
|
is `AcceptedPhysicsTimestamps` (whose `TeleportHookRequired` field this slice
|
|
deletes; replacing a policy tri-OR with a data field is strictly better) or
|
|
`AcceptedPositionNetworkUpdate`. Constraints: the value is the pre-merge
|
|
`FullCellId` measured by the SAME `TryApplyPosition` call that merged the
|
|
packet (never re-read after the merge); no fabrication (a known record always
|
|
has an honest value — 0 means "was celless", not "unknown").
|
|
|
|
**What is deliberately NOT adopted from `remotePlacementRequired`:** the
|
|
graphical `projectionRequiresTeleportHook` arm
|
|
(`LiveEntityRuntime.TryApplyPosition`: pre-merge `FullCellId == 0` OR
|
|
`!IsSpatiallyProjected` OR `!IsSpatiallyVisible`). Its visibility half is a
|
|
presentation predicate with NO retail analogue — it made "not currently
|
|
rendered" fire the whole teleport machinery on a routine hot path (trap T1's
|
|
warning). After this slice the teleport classification is retail's exact pair
|
|
(`TeleportAdvanced || wasCellless`); a not-visible remote's Position
|
|
classifies by distance like any other, the canonical placement decides
|
|
placeability, and visibility remains presentation-only. This behavioural
|
|
change is recorded in the AP-137 rewrite (D8). The whole
|
|
`projectionRequiresTeleportHook` computation, the lifetime parameter, the
|
|
headless `false` at `RuntimeLiveEntitySessionController`, and the
|
|
`TeleportHookRequired` field + its `timestamps with {…}` write are deleted.
|
|
|
|
### D2 — classifier-null and `Rejected*` keep 4b-2's stated policy (resolves trap T2); the legacy airborne fallback is replaced by the retail return-0 shape
|
|
|
|
The scoping doc's T2 described the pre-4b-2 world; 4b-2 already deleted the
|
|
legacy near/far blocks and routed `null` / `RejectedAuthority` /
|
|
`RejectedData` to `UnroutedCatchUp`
|
|
(`RuntimeRemoteFarSnapPosition.ResolveArm`, AP-137). **4b-3 keeps that policy
|
|
unchanged** — during the login window (null `_playerController` →
|
|
classification refuses; every remote packet) remotes keep tracking through
|
|
AP-87's catch-up, exactly as today. One consequence to state in the register
|
|
rewrite: a TELEPORT_TS-advancing packet that arrives while classification is
|
|
null consumes its teleport sequence in the timestamp gate but runs no hook —
|
|
benign in the only producing window (fresh session: no moveto, stick, leash,
|
|
or target exists yet to tear down), stated rather than discovered later.
|
|
|
|
What T2 actually leaves 4b-3 is the player arm's legacy
|
|
`!update.IsGrounded` fallback (the block whose comment says "4b deletes this
|
|
fallback" — a comment this slice at last makes true), which handled
|
|
wire-airborne packets for classifications 4a does not own. After D1 the
|
|
unowned set shrinks to null and `Rejected*`. **Pinned replacement:** a
|
|
wire-airborne packet with a null/`Rejected*` classification takes the retail
|
|
return-0 shape applied to the acdream-only states — AP-135's two bookkeeping
|
|
writes, no body write, no queue write, no render write, no leash arm, return.
|
|
This deletes the legacy block's entity-revert quirk
|
|
(`entity.SetPosition(rmState.Body.Position)`) and unifies the player and NPC
|
|
arms on one leftover-airborne behaviour. Recorded in the AP-137 rewrite.
|
|
|
|
### D3 — one teleport-hook implementation, triggered by the route, run inside the teleport arm before the placement
|
|
|
|
The hook trigger moves from `timestamps.TeleportHookRequired` (deleted) to
|
|
the classification: `route.TeleportHookPhase ==
|
|
RuntimeTeleportHookPhase.BeforePositionOperation`, which the classifier
|
|
already emits on exactly the remote teleport/cell-less branch. The hook runs
|
|
inside the new teleport arm, immediately before
|
|
`TryExecuteAcceptedRemotePosition` — retail's order (hook @0x005163EF before
|
|
`SetPosition` @0x00516420), and it runs REGARDLESS of what the placement then
|
|
yields (retail runs it before knowing the outcome).
|
|
|
|
There must be exactly ONE hook implementation. The existing
|
|
`RemoteTeleportHook.Execute` sequence — the six actions in retail order with
|
|
a currency re-check between every step — is the port and must be preserved
|
|
verbatim; whether the file moves into `AcDream.Runtime` (every action is
|
|
expressible there: `remote.Movement.CancelMoveTo`,
|
|
`rmState.Host.PositionManager.UnStick/UnConstrain`, `remote.Interp.Clear()`,
|
|
`host.NotifyTeleported()`, `Physics.Engine.ShadowObjects.Suspend(localId)`)
|
|
or stays an App bundle invoked from the arm is the implementer's choice.
|
|
Runtime residence is preferred (it is where the sibling arm logic lives and
|
|
what a future headless remote-motion consumer needs), but not at the cost of
|
|
inventing a second hook path. `RemoteTeleportHookTests` (38 lines) moves or
|
|
adapts with it — not silently dropped.
|
|
|
|
**Undetermined item 2 is RESOLVED — yes, `EntityPhysicsHost.NotifyTeleported()`
|
|
covers retail's TargetManager pair.** Verified on both sides:
|
|
`NotifyTeleported` executes `_targetManager.ClearTarget()` then
|
|
`_targetManager.NotifyVoyeurOfEvent(TargetStatus.Teleported)`
|
|
(`src/AcDream.Runtime/Physics/EntityPhysicsHost.cs`), and retail's
|
|
`teleport_hook` executes `TargetManager::ClearTarget` @0x00514F1B then
|
|
`NotifyVoyeurOfEvent(Teleported_TargetStatus)` @0x00514F28 under one
|
|
`target_manager != 0` guard. One-to-one; no open question remains here.
|
|
|
|
### D4 — the single `ConstrainTo` arm, and its complete partition
|
|
|
|
The legacy pre-operation arming call (the `OwnsAfterOperationConstraint`-gated
|
|
fallback in the player/NPC shared section, whose comment already says "4b-3
|
|
deletes it") is DELETED. The post-operation site —
|
|
`RuntimeRemoteSteadyStatePosition.TryArmConstraintAfterOperation`, called once
|
|
per arm after routing — becomes the only arm, matching retail's single site
|
|
@0x00454272. Its predicate widens from
|
|
`OwnsSteadyState || OwnsFarSnap` to the full retail partition:
|
|
|
|
| classification (routed arm) | wire contact | retail return | arm? |
|
|
|---|---|---|---|
|
|
| teleport / cell-less (`SetPosition`, new arm) | any | 1 | **yes** — after the operation, on every placement outcome (retail discards the error), post-move anchor |
|
|
| `Interpolate` (near) | grounded | 1 | yes (unchanged, 4a) |
|
|
| `SetPositionSimple` (far) | grounded | 1 | yes (unchanged, 4b-2) |
|
|
| `NoPositionOperation` (airborne no-op) | airborne | 0 | **no** (unchanged, 4a) |
|
|
| null / `Rejected*` → `UnroutedCatchUp` | grounded | (no retail state; analog: nonzero) | yes — via the same post-operation site, which must therefore accept a null route for this case |
|
|
| null / `Rejected*`, wire-airborne (D2 shape) | airborne | (analog: 0) | **no** — the current legacy pre-op arm DOES arm these; that was a divergence and it retires with the site |
|
|
|
|
The one-packet unarmed residual on a superseded incarnation (the currency
|
|
guard returning before arming) is AP-138(3) and extends to the teleport arm
|
|
unchanged. This partition closes the shipped hole named in scoping
|
|
correction 2: a remote hard teleport currently arms the leash NOWHERE
|
|
(`remotePlacementRequired` returns ahead of every arming site after the
|
|
hook's `UnConstrain`); after this slice the hook `UnConstrain`s and the
|
|
single post-operation site re-arms — retail's exact sequence.
|
|
|
|
### D5 — routing order: the teleport arm precedes every contact carve-out; sticky does not suppress it
|
|
|
|
Retail decides the teleport branch before reading `arg4`. Therefore:
|
|
|
|
- `RuntimeRemoteFarSnapPosition.ResolveArm` (or its successor) returns the
|
|
new teleport arm ahead of everything else, and
|
|
`ApplyRemoteContactRouting` dispatches it BEFORE the `!remote.Body.InContact`
|
|
free-flight carve-out — an airborne-body teleport packet places, it does
|
|
not `AirborneSnap`.
|
|
- The player arm's landing block (`!rmState.Body.InContact` hard-snap +
|
|
return) must not claim a teleport-classified packet: the teleport
|
|
classification is routed before it (or the block is gated to classifications
|
|
it owns — implementer's choice, pinned outcome: a teleport-classified
|
|
packet always reaches the teleport arm regardless of wire or body contact).
|
|
- The 4a `IsAirborneNoOperation` early returns are classification-gated
|
|
already and cannot claim a `SetPosition` route — unchanged.
|
|
- **The NPC arm's TS-44 sticky suppression (`snapSuppressedByStick`) does not
|
|
suppress the teleport arm.** Retail's sticky cannot survive a teleport —
|
|
`UnStick` is the hook's second action. The suppression remains exactly as
|
|
it is for the near/far/leftover arms (its register row describes an
|
|
NPC-only steady-state gate, which stays true).
|
|
|
|
### D6 — the two per-packet gates widen to the teleport arm, same rule as the far arm
|
|
|
|
- `TryApplyGenericRemoteRenderPose`: the gate stays `OwnsSteadyState` — the
|
|
teleport arm (like the far arm) takes the early wire-pose write, and its
|
|
tail re-syncs the render entity from the resolved body (invariant 2). This
|
|
resolves the standing "route 4b-3 revisits the gate" comment: the answer is
|
|
"unchanged, now stated"; delete the forward reference.
|
|
- `TryAdoptWireCellAfterRouting`: the suppression (currently
|
|
`arm is FarSnapPlacement`) widens to the teleport arm, for the same reason —
|
|
after a canonical placement the placement is the cell authority; retail
|
|
resolves the destination cell through `AdjustPosition`/`set_cell` and
|
|
nothing writes the wire cell over it.
|
|
|
|
### D7 — the post-placement currency guard covers the teleport arm; consolidation is sanctioned
|
|
|
|
Both arms' re-validation ("the far arm is re-entrant — re-validate position
|
|
ownership on EVERY placement status before writing anything else, arming
|
|
included") widens to `Arm is FarSnapPlacement or <TeleportArm>`. Round 2's
|
|
"do not churn" explicitly named for 4b-3 that this guard "belongs behind a
|
|
testable Runtime seam rather than duplicated at two App call sites" — moving
|
|
the duplicated guard into the Runtime seam is sanctioned in this slice, but
|
|
only if the two arms' observable ordering (guard before arm, both arms
|
|
identical — the R5 invariant) is preserved and pinned by test.
|
|
|
|
### D8 — register bookkeeping, in the implementation commit
|
|
|
|
- **AP-137 is REWRITTEN, not deleted.** Its cell-less enqueue-vs-place delta
|
|
(part R2) retires — that is this slice's headline. But the row also records
|
|
the two surviving acdream-only states (null classification during the login
|
|
window; `RejectedData`/`RejectedAuthority` applied through
|
|
`UnroutedCatchUp`), which have no retail mechanism and therefore keep a
|
|
row. Rewrite the row to exactly the survivors plus D1's visibility-arm
|
|
deletion and D2's wire-airborne leftover shape. (The handoff says "row
|
|
deletion"; a deletion that silently dropped the surviving divergences would
|
|
violate register rule 1 — this contract overrides that wording, and the
|
|
summary reports the contradiction.)
|
|
- **AD-42 must be updated**: it cites
|
|
`src/AcDream.App/Physics/RemoteTeleportController.cs (ResolvePlacement)` as
|
|
a surviving two-call enter-world split path. That citation dies with the
|
|
class; the headless portal-arrival resync and
|
|
`PhysicsEngine.ResolvePlacement` citations remain.
|
|
- **AP-136 / AP-138 (D5 scoping text)**: both name "`RemoteTeleportController`'s
|
|
rollback" as the shipped writer that can rebucket `record.FullCellId` to a
|
|
third landblock under a retained retry. That writer is deleted; the
|
|
surviving non-Position rebucket writers are the projection materializer
|
|
(`DatLiveEntityProjectionMaterializer`) and the equipped-child renderer
|
|
(`EquippedChildRenderController.TickChild`). Update both rows and the same
|
|
claim inside `RuntimeSetPositionState`'s `CurrentCellId` doc and
|
|
`RuntimeRemotePlacementDriveController.CanAttemptDestination`'s doc
|
|
(process rule 6).
|
|
- **AP-138's Risk column gains the teleport arm as a second producer** of the
|
|
visible-without-collision residual: a remote that teleports into a
|
|
non-published landblock and stands still is exactly the AP-136/AP-138
|
|
shape, now reachable through this arm. No new machinery — the row's
|
|
retirement path is already #309.
|
|
- **AP-135 is untouched.**
|
|
|
|
## Deletion inventory — every file, wiring site, and test
|
|
|
|
Files deleted (739 production lines):
|
|
|
|
| file | lines |
|
|
|---|---|
|
|
| `src/AcDream.App/Physics/RemoteTeleportController.cs` | 605 |
|
|
| `src/AcDream.App/Physics/RemoteTeleportPlacement.cs` | 85 |
|
|
| `src/AcDream.App/Physics/RemoteShadowPlacementSynchronizer.cs` (contains BOTH `RemoteShadowPlacementSynchronizer` and `RemoteTeleportPlacementPresentation`) | 49 |
|
|
|
|
`src/AcDream.App/Physics/RemoteTeleportHook.cs` (57) is NOT deleted — it is
|
|
the retail `teleport_hook` port and moves/re-wires per D3.
|
|
|
|
Tests deleted (1,709 lines):
|
|
|
|
| file | lines |
|
|
|---|---|
|
|
| `tests/AcDream.App.Tests/Physics/RemoteTeleportControllerTests.cs` | 1,515 |
|
|
| `tests/AcDream.App.Tests/Physics/RemoteTeleportPlacementTests.cs` | 194 |
|
|
|
|
`tests/AcDream.App.Tests/Physics/RemoteTeleportHookTests.cs` (38) moves with
|
|
the hook.
|
|
|
|
Wiring sites (the handoff's list of eight was a raw grep; the true set is
|
|
below — two sites the handoff missed, and three of its entries are
|
|
comment-only):
|
|
|
|
| site | what happens |
|
|
|---|---|
|
|
| `src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs` | The heart of the slice. Delete: ctor param + `_remoteTeleportController` field; `remoteHardTeleport` / `remotePlacementRequired`; `RunRemoteTeleportHook` (moves per D3); the `BeginPlacement` call; the whole `remotePlacementRequired` placement block (the `TryApply` call and its `Applied`/`Superseded` tails); the classification gate's `&& !remotePlacementRequired`; the legacy `!update.IsGrounded` fallback (D2); the legacy pre-operation `ConstrainTo` call (D4). Add: the teleport arm dispatch (D5), widened guards (D6/D7). |
|
|
| `src/AcDream.App/Composition/LivePresentationComposition.cs` | Delete the `RemoteShadowPlacementSynchronizer` + `RemoteTeleportPlacementPresentation` constructions, the `remoteTeleportLease` acquisition, the `RemoteTeleport` record member, and the lease parameter threading. |
|
|
| `src/AcDream.App/Composition/SessionPlayerComposition.cs` | Three `live.RemoteTeleport` pass-throughs (network-update controller ctor, teardown controller ctor, and the third composition site) — replaced by nothing; the drive controller is already threaded. **Missing from the handoff's list.** |
|
|
| `src/AcDream.App/Net/LiveSessionRuntimeFactory.cs` | Delete the `RemoteTeleport` record member and the reset-plan binding `RemoteTeleport = _world.RemoteTeleport.Clear`. |
|
|
| `src/AcDream.App/Net/LiveSessionResetManifest.cs` | Delete the `required Action RemoteTeleport` member and its `new("remote teleport", …)` stage. **Missing from the handoff's list.** Reset coverage is not lost: the drive controller's teardown is `DetachRoute` (cancels every live operation) and its ledger convergence is already asserted. |
|
|
| `src/AcDream.App/Rendering/GameWindow.cs` | Delete the `_remoteTeleportController` field and its assignment from the composition result. |
|
|
| `src/AcDream.App/Rendering/GameWindowLifetime.cs` | Delete the `RemoteTeleportController? RemoteTeleport` shutdown-root member and the `Hard("remote teleport", …)` stage. |
|
|
| `src/AcDream.App/World/LiveEntityRuntimeTeardownController.cs` | Delete the ctor param, field, and the `_remoteTeleport.Forget(record)` cleanup entry. Per-entity teardown coverage is not lost: the drive controller self-heals on `IsPlacementCurrent` and `Forget`-on-accepted-Position retires operations. |
|
|
| `src/AcDream.Runtime/Physics/RuntimeRemotePhysicsUpdater.cs` | **Comment-only** (two doc comments citing `RemoteTeleportPlacement.Apply` — the isCurrent-delegate note and the five-writer `Airborne` list, which becomes a four-writer list; the teleport path's `Airborne` derivation is now the canonical placement commit's, already on the list). Correct both (process rule 6). |
|
|
| `src/AcDream.Runtime/Physics/RuntimeSetPositionState.cs` | **Comment-only** (the `CurrentCellId` retained-retry doc naming `RemoteTeleportController`'s rollback — D8). No code change; there is no teleport-hook machinery in this file to touch. |
|
|
| `src/AcDream.Core/Physics/EntityCollisionFlags.cs` | **Comment-only** (TS-23 history note naming the pre-P3 inlined call sites). Historical statement — rewrite to past tense or leave verifiably historical; do not let it read as a live citation. |
|
|
| `src/AcDream.Runtime/Session/RuntimeRemotePlacementDriveController.cs` | Widen `OwnsPlacement`'s scope comment (it ALREADY matches `SetPosition` + `Teleport` flag — no predicate change needed for the teleport disposition); add the teleport-arm entry point (D3); correct the `Advance()`/`CanAttemptDestination` docs' writer list (D8). |
|
|
| `src/AcDream.Runtime/Entities/RuntimeEntityObjectLifetime.cs` + `src/AcDream.App/World/LiveEntityRuntime.cs` + `src/AcDream.Runtime/Session/RuntimeLiveEntitySessionController.cs` + `src/AcDream.Runtime/Entities/InboundPhysicsStateController.cs` | Delete the `TeleportHookRequired` field, its `timestamps with {…}` computation, the `projectionRequiresTeleportHook` parameter/computation/`false` argument, and thread the pre-merge cell instead (D1). One doc comment in `InboundPhysicsStateController` cites `TeleportHookRequired`-adjacent bookkeeping — reword. |
|
|
| `src/AcDream.App/World/LiveEntityPresentationController.cs` | `BeginAuthoritativePlacement` and `CompleteAuthoritativePlacement(deferShadowRestore: false)` lose their only production callers (`DeferShadowRestore`, `HasActivePlacement`, `HasDeferredShadowRestore` already have none), leaving `_activePlacementOwners` write-never while `IsPlacementActive` still reads it in the visibility suspend/restore gates. Delete the dead half in this commit — do not leave a zombie set that silently gates nothing — but trace the `IsPlacementActive` consumers first and state in the commit what each gate degenerates to. If tracing shows a live non-teleport dependency, STOP and report rather than deleting blind. |
|
|
|
|
Test files updated (not deleted) — each references the deleted machinery
|
|
incidentally: `UpdateFrameOrchestratorTests` (a `typeof(RemoteTeleportPlacementPresentation)`
|
|
row), `RuntimeEntityOwnershipTests` (two `typeof(RemoteTeleportController)`
|
|
exact-key assertions), `GameWindowLiveEntityCompositionTests`
|
|
(`[InlineData("RunRemoteTeleportHook")]`), `LiveEntityLifecycleStressTests`
|
|
(constructs the controller and calls `TryApply` — its scenario must be
|
|
re-expressed against the canonical teleport arm, not dropped),
|
|
`LiveSessionResetPlanTests` (the "remote teleport" stage),
|
|
`CurrentGameRuntimeAdapterTests` (a noop binding),
|
|
`RuntimeInitialCreateResidenceStateTests`
|
|
(`RemoteTeleportSuffixIsQueuedBehindInitialAdmission` — verify what it pins;
|
|
it is about suffix ordering under initial admission and likely survives with
|
|
a rename), plus the eight files matching `TeleportHookRequired`.
|
|
|
|
Stale comments this slice must make true (process rule 6 — verify each
|
|
against the code beside it, and prefer symbol references): the
|
|
`// 4b deletes this fallback` line (D2 deletes the fallback); the
|
|
`// 4b-3 deletes it` on the legacy arm site (D4); the `remotePlacementRequired
|
|
guarantees the classifier's teleport disposition never reaches here` route
|
|
comment; `ClassifyRemoteAcceptedPosition`'s caller-doc sentence "whose
|
|
remotePlacementRequired gate is already false"; `SeedRemoteSpawnPlacement`'s
|
|
"Mirrors `RemoteTeleportPlacement`'s commit"; the AP-140 comment's citation of
|
|
`RemoteTeleportPlacementTests.Apply_PendingGroundToSteepContact_…` as an
|
|
`Airborne`-definition dependent (the test dies; the dependency list shrinks);
|
|
the classifier's "only a later Runtime SetPosition or simulation commit may
|
|
change FullCellId" (D1 shows it false); `TryApplyGenericRemoteRenderPose`'s
|
|
"Route 4b-3 revisits the gate" (D6 resolves it).
|
|
|
|
## Proof obligations (must prove, not assume)
|
|
|
|
1. **`ParkCollisionResidents`'s overlap throw stays unreachable.** The
|
|
argument is 4b-1/4b-2's, extended: every operation this route begins goes
|
|
through `TryBeginExclusiveAuthoredPlacement` (one live operation per key —
|
|
the Begin refuses a second), `DeferredCell` outcomes are cancelled
|
|
synchronously (no park survives the controller), and retained entries are
|
|
preparation retries bounded by the pre-flight re-check and the `Advance()`
|
|
window-drop. The teleport arm adds packets to the same machinery, not a
|
|
new operation shape. State this in the contract-conformance section of the
|
|
implementation commit and keep the honest caveat 4b-1's B2 established:
|
|
the guarded property is `TryAcquireCollisionPrefixMutationPermission`'s
|
|
`HasOldPrefixPlacementDebt` refusal (a stall, not a throw), and the
|
|
ledger convergence tests are the floor under it.
|
|
2. **Ledger convergence with teleports in flight**: teardown, session reset,
|
|
and generation change converge `RemotePlacementDrivePendingCount` (both
|
|
registrations) to zero with retained teleport retries present — the same
|
|
suite shape 4b-1 built, driven through the new arm.
|
|
3. **The one-arm partition (D4)**: a test that counts arming calls per packet
|
|
across the partition table's rows — exactly one for every "yes" row,
|
|
exactly zero for every "no" row. The 4b-2 lesson (R7): assert the
|
|
observable (the arm count / the anchor), not the code shape.
|
|
|
|
## What this slice does NOT do
|
|
|
|
- **AP-131** (shared merge call) — C5.
|
|
- **AP-135** — stays, writes preserved (invariant 8).
|
|
- **#276** — `SeedRemoteSpawnPlacement` is still not classification-gated;
|
|
the AD-61 settle is untouched.
|
|
- **#309 / AP-136 / AP-138 residuals** — the lost-cell/hidden-until-cell-load
|
|
behaviour is not built here; the teleport arm inherits the far arm's
|
|
store-and-stay-visible residual and the register rows say so (D8).
|
|
- **Route 5 (projectile)** — `OwnsPlacement` keeps excluding
|
|
`ProjectileAuthoritative`; no widening here.
|
|
- **No headless remote consumer** — `RuntimeLiveEntitySessionController`
|
|
still returns early for non-local GUIDs; the vacuous-satisfaction statement
|
|
stays in the interface doc and the AP-137 rewrite.
|
|
- **No changes to route 2's local-player ForcePosition/teleport paths**, the
|
|
local-player teleport transit (`LocalPlayerTeleportController` keeps its own
|
|
`NotifyTeleported` call), or route 1's executor.
|
|
- **The recorded-not-consumed route facts stay recorded-not-consumed**:
|
|
`UnparentBeforeRouting` / `ApplyPlacementFrameBeforeRouting` have no reader
|
|
today (the unparent edge is owned by the merge's `EndChildProjection` and
|
|
the hydration recovery); this slice adds no reader and does not delete the
|
|
facts.
|
|
|
|
## Test plan
|
|
|
|
Tests must assert the layer that broke historically (process rule 4 —
|
|
presentation/visibility, not only `InWorld`/clock/residency), and every new
|
|
test must fail against a broken implementation (no source-text pins, no
|
|
tautologies).
|
|
|
|
Focused Runtime tests (`tests/AcDream.Runtime.Tests`):
|
|
|
|
1. Teleport-classified commit: body at resolved destination, `FullCellId` =
|
|
resolved cell, hook ran (moveto cancelled, stick released, interp queue
|
|
empty, leash re-armed post-operation at the post-move anchor), clock
|
|
active, `InWorld`.
|
|
2. Teleport refused (destination outside the service window): pose STILL
|
|
advances to the accepted destination (invariant 1), no park opened, no
|
|
operation retained, entity `InWorld` + clock active + spatial root intact,
|
|
AND the hook still ran (retail runs it before the placement decision).
|
|
3. Teleport `RejectedByPlacement` (engine refused): pose does NOT move;
|
|
`Cancelled`-after-commit: settled pose survives. (The far arm's tests
|
|
exist; these drive the teleport arm through the same partition.)
|
|
4. Cell-less classification now fires: a record whose PRE-merge committed
|
|
cell is 0 (unwield-to-3D shape) classifies `SetPosition` and places
|
|
unconditionally — the AP-137-retiring behaviour. Companion: the same
|
|
packet with a nonzero pre-merge cell and no TELEPORT_TS advance does NOT
|
|
classify `SetPosition` (proves D1's input is the pre-merge value, not the
|
|
post-merge wire cell — this is the test that discriminates the fix from
|
|
the shipped dead predicate).
|
|
5. D4 partition: arm-count table test (proof obligation 3), including the
|
|
wire-airborne null/`Rejected*` no-arm rows and the
|
|
teleport-arm-on-every-outcome row.
|
|
6. D5 ordering: an airborne-body teleport packet places (does not
|
|
`AirborneSnap`, does not take the landing block); a stuck NPC's teleport
|
|
packet runs the hook (`UnStick`) and places despite TS-44's suppression.
|
|
7. Currency: teleport arm's synchronous receipt deletes/replaces the
|
|
incarnation → nothing further written for the packet (guard before arm,
|
|
both arms — the R5 shape, now for the teleport arm).
|
|
8. Ledger/teardown: proof obligation 2.
|
|
|
|
App-layer tests (`tests/AcDream.App.Tests`):
|
|
|
|
9. **The presentation assertion (#312's layer):** after a remote teleport
|
|
commit, the render `WorldEntity` pose equals the resolved body pose,
|
|
`ParentCellId` equals the resolved cell, the entity is spatially visible,
|
|
and the collision shadow was published. After a refused teleport, the
|
|
render pose tracks the stored destination and the entity REMAINS visible.
|
|
10. D2's leftover-airborne shape: wire-airborne null-classified packet writes
|
|
exactly AP-135's two fields and nothing else (body, entity, queue, leash
|
|
all untouched).
|
|
11. AP-135 preservation on the rewritten arms (both airborne no-op paths).
|
|
12. The generic render-pose + wire-cell-adoption gates: teleport arm takes
|
|
the early write and suppresses the post-routing wire-cell adopt (D6) —
|
|
asserted through the existing extracted entry points, not restated
|
|
logic.
|
|
|
|
Live-execution proof (process rule 5): a `[remote-teleport]` probe line —
|
|
`PhysicsDiagnostics`-owned, `ACDREAM_PROBE_REMOTE_TELEPORT=1`, one line per
|
|
routed teleport arm with guid, cause (`teleport-ts` vs `cellless`), hook-ran,
|
|
and placement status, marked TEMPORARY with the existing probe family. The
|
|
connected gate below is recorded as a pass ONLY if the probe line shows the
|
|
new arm executed (a clean-looking session with zero probe lines is a
|
|
not-run, exactly like #309's park probe).
|
|
|
|
## Gates
|
|
|
|
- Focused Runtime + App tests above.
|
|
- Complete Release suite: `$env:ACDREAM_PAK_PATH` set,
|
|
`dotnet test AcDream.slnx -c Release -m:1`. **Baseline 11,027 passed / 4
|
|
skipped / 0 failed** at `2eb39a02`. The net count will move (1,709 test
|
|
lines deleted, new tests added) — measure and record the new figure; do not
|
|
inherit 11,027 as the expectation. Two known flakes, do not chase and do
|
|
NOT conflate: **#302** (`PortalProjectionTests.ClipToRegion_FrameOwnedStore_…`,
|
|
GC-allocation assertion, App.Tests) and **#308**
|
|
(`NakEmissionTests.LossSoak_…`, wall-clock deadline, Core.Net.Tests,
|
|
full-suite load only). If either appears, re-run and say which.
|
|
- **Two-client connected teleport gate (user-run).** **CORRECTION (2026-08-04
|
|
fix round, both independent Opus reviews):** the recipe below originally
|
|
specified "a second character" as the teleport target. That is WRONG — a
|
|
player-character target cannot exercise this arm's NPC/creature code path
|
|
at all, and two of the three MAJOR defects the fix round found (A1's
|
|
zero-arm leash regression, A2/R3's synthesized-velocity/run-cycle defect)
|
|
are BOTH on the NPC-guid branch only; `RemoteServerControlledVelocityCycle.Apply`
|
|
itself early-returns for any `0x50xxxxxx` guid, so a player-target run
|
|
would report a clean pass while both defects shipped underneath it. **The
|
|
target MUST be an NPC/creature** (an ACE admin teleport — `@teleto` /
|
|
`@teleloc` — applied to a drudge/mosswart/etc., NOT a second player
|
|
character) for the gate to see what it is supposed to see. Recipe: acdream
|
|
stands as observer; the creature target is teleported with an ACE admin
|
|
teleport (`@teleto` / `@teleloc`) — those route through `Teleport()` /
|
|
`SendUpdatePosition(true)` and advance **ObjectTeleport** (TELEPORT_TS),
|
|
which is exactly this arm's trigger on the observer (`@pklite` is route
|
|
2's ForcePosition lever, NOT this gate — see
|
|
[`2026-08-03-c4-route-2-visual-gate.md`](2026-08-03-c4-route-2-visual-gate.md)).
|
|
Run with `ACDREAM_PROBE_REMOTE_TELEPORT=1`. Correct: the observed creature
|
|
vanishes from the old spot and appears at the destination in one step (no
|
|
glide, no interpolated streak), **stands STILL with correct idle
|
|
animation — NOT sprinting/running in place** (A2/R3's specific symptom:
|
|
a synthesized teleport-distance velocity planning a RunForward cycle at
|
|
the destination), and moves normally afterward (leash re-armed: no
|
|
rubber-band, no tether — A1's specific symptom is the ABSENCE of a
|
|
rubber-band/re-anchor where one should exist, since a creature that was
|
|
knocked airborne on its first accepted Position after this teleport would
|
|
otherwise never arm at all). Also teleport the remote OUT of view and
|
|
back: it must re-appear correctly. Regressions to watch: a remote gliding
|
|
across the map at teleport (queue not cleared), freezing at the old spot
|
|
(the 4b-2 round-1 freeze class), invisible-but-audible at the destination
|
|
(#312 class), invisible-but-solid (#184 class), a rubber-band after
|
|
arrival, or the creature sprinting/running in place at the destination
|
|
(A2/R3). Confirm at least one `[remote-teleport]` line per teleport, with
|
|
the expected cause. Graceful close (ACE session-clear) per the standing
|
|
rule.
|
|
|
|
## Budget
|
|
|
|
**~400-700 non-comment production lines** (net LOC strongly negative — the
|
|
deletions are 739 production + 1,709 test lines). For calibration: 4a was
|
|
364, 4b-1 was 230+57, 4b-2 landed within its 350-500. Exceed 700 new lines
|
|
and STOP and report rather than pushing through.
|
|
|
|
## Open questions routed to the retail-conformance reviewer
|
|
|
|
1. **D1's evidence chain** (the merge stamps `FullCellId` with the wire cell
|
|
before classification, making the shipped cell-less predicate dead) rests
|
|
on the reading `TryApplyPosition` → `RefreshSnapshot(refreshPosition:
|
|
acceptedPosition)` → `RefreshDerivedState` → `SetFullCell(wire cell)`,
|
|
with classification after the gate and before the prologue rebucket.
|
|
Verify independently — it is the load-bearing claim of this contract, and
|
|
if it is wrong the D1 plumbing is unnecessary churn.
|
|
2. **`report_collision_end(this, 1)` ↔ `ShadowObjects.Suspend(localEntityId)`**:
|
|
the existing hook maps retail's collision-end report to a broadphase
|
|
shadow suspension. This mapping predates 4b-3 and is carried, not
|
|
re-derived. Confirm against @0x00514F31's callee that the "1" argument
|
|
(report-to-partners) has no unported half, or file the delta on the
|
|
AP-137 successor row.
|
|
3. **The `LiveEntityPresentationController._activePlacementOwners` deletion**
|
|
(deletion-inventory last row): confirm by reading `IsPlacementActive`'s
|
|
two consumers that removing the write-never set cannot change a
|
|
Hidden/UnHide or visibility-edge restore for non-teleport entities.
|
|
4. **`RemoteTeleportSuffixIsQueuedBehindInitialAdmission`**
|
|
(`RuntimeInitialCreateResidenceStateTests`): confirm what it pins and
|
|
that it survives (renamed) rather than being deleted as collateral.
|
|
|
|
## Contradictions with the handoff/scoping docs — reported, not smoothed over
|
|
|
|
- **The handoff's "AP-137 row deletion belongs in the implementation
|
|
commit"** conflicts with the row's own content: null and `Rejected*` are
|
|
acdream-only divergences that survive this slice and must keep a row.
|
|
Pinned as rewrite-in-place (D8). If the reviewer prefers
|
|
delete-and-refile-narrow, either satisfies register rule 1; silent whole-row
|
|
deletion does not.
|
|
- **The handoff's wiring-site list (8 sites) is a raw grep, not a wiring
|
|
list**: `SessionPlayerComposition.cs` and `LiveSessionResetManifest.cs` are
|
|
real wiring sites it missed; `RuntimeRemotePhysicsUpdater.cs`,
|
|
`RuntimeSetPositionState.cs`, and `EntityCollisionFlags.cs` are
|
|
comment-only.
|
|
- **The handoff's "`RuntimeSetPositionState.cs` — the teleport-hook phase
|
|
support and SetFlags analog"**: there is no teleport-hook phase support in
|
|
that file. The phase lives on the classifier route
|
|
(`RuntimeTeleportHookPhase`), and the SetFlags analog is the `flags`
|
|
parameter of `TryPrepareAndSubmitAuthoredPlacement` fed from
|
|
`route.SetPositionFlags`.
|
|
- **The scoping doc's T1 ("they disagree in both directions")** understates
|
|
the finding: as fed today the classifier's cell-less predicate is not
|
|
merely different — it is unreachable for remote PositionEvents (D1). The
|
|
design decision is therefore not "reconcile two predicates" but "feed the
|
|
classifier retail's predicate at all".
|
|
- **The scoping doc's T2** describes the pre-4b-2 tree; 4b-2 already
|
|
established the null/`Rejected*` policy. What 4b-3 actually decides is the
|
|
wire-airborne leftover shape (D2), which neither doc names.
|
|
|
|
---
|
|
|
|
## Connected gate RESULT — PASSED 2026-08-04 (user-run, user-accepted)
|
|
|
|
Run against the exact `6dc7ba51` Release binary with the retail UI
|
|
(`ACDREAM_RETAIL_UI=1`) and `ACDREAM_PROBE_REMOTE_TELEPORT=1`, live ACE at
|
|
`127.0.0.1:9000`. Log: `4b3-gate-retailui.log` (440 lines, graceful exit 0).
|
|
|
|
**User verdict: "all works"** — no glide/streak on arrival, correct standing
|
|
animation, normal movement afterward, no rubber-band or tether.
|
|
|
|
**Probe evidence (this is what makes it a pass rather than a clean-looking
|
|
session):** 16 `[remote-teleport]` lines across 7 distinct creatures, every one
|
|
`hookRan=True placement=Committed`. Every guid is in the `0x8xxxxxxx` creature
|
|
range — NOT `0x50xxxxxx` — so the run exercised the NPC-guid branch, which is
|
|
where all three of the fix round's NPC-arm MAJORs lived (A1's zero-arm leash
|
|
regression, R1's missing D2 shape, R3/A2's synthesized run-cycle velocity).
|
|
The corrected creature-target recipe is therefore validated in practice, not
|
|
just in argument.
|
|
|
|
**HONEST GAP — the cell-less half is NOT live-verified.** All 16 lines are
|
|
`cause=teleport-ts`; `cause=cellless` was never observed. So the arm's
|
|
TELEPORT_TS trigger is proven live and its cell-less trigger (retail's
|
|
`this_1->cell == 0` @0x00516386 — a body with no committed cell at all, e.g.
|
|
after an unwield-to-3D `SetFullCell(0,0)` or any canonical withdrawal) is
|
|
covered by tests only. This is deliberately recorded rather than folded into a
|
|
blanket "gate passed", because it is exactly 4b-2's #309 shape: that session's
|
|
11 park probes were all one cause, the other cause went unexercised, and
|
|
without the probe the session would have been recorded as full coverage.
|
|
|
|
To close it later: provoke a Position on an entity whose canonical cell is 0 —
|
|
the unwield-to-3D path is the cheapest reachable trigger — and confirm one
|
|
`cause=cellless` line. Do not treat it as closed by a teleport-ts session.
|