# C1 body/controller-publication writer map (2026-08-02) Repo: `C:\Users\erikn\.codex\worktrees\af5e\acdream`, branch `codex/port-claude-agents`, HEAD `ae296393`. READ-ONLY research; this file is the only write target. Context read: `docs/plans/2026-08-02-placement-cutover.md` (slice C1), `docs/research/2026-07-31-remaining-physics-campaign-handoff.md` (rejected-prototype section, lines 143-168; prerequisite C, lines 203-221), and `docs/research/2026-08-02-cutover-route-inventory.md` route 1 + prerequisite-C section (lines 174-220) + route 8 (headless). --- ## 1. Every writer of `RuntimeEntityRecord.PhysicsBody` `PhysicsBody` is `public PhysicsBody? PhysicsBody { get; private set; }` (`src/AcDream.Runtime/Entities/RuntimeEntityRecord.cs:72`). The ONLY mutator is the internal method `SetPhysicsBody(PhysicsBody? body)` (`RuntimeEntityRecord.cs:176-182`): ``` internal void SetPhysicsBody(PhysicsBody? body) { if (ReferenceEquals(PhysicsBody, body)) return; PhysicsBody = body; PhysicsOwnershipEpoch++; // <-- the ONLY place PhysicsOwnershipEpoch is bumped } ``` So every "writer" is a caller of `.SetPhysicsBody(...)` (all 6 call sites, confirmed by full-repo grep, zero others): 1. **`RuntimeEntityDirectory.cs:359`** — inside `GetOrCreatePhysicsBody(RuntimeEntityRecord record, Func factory)` (need exact surrounding signature — read below). Public/internal API used by the route-1 "SECOND, narrower body-construction duplicate authority" for non-player static-animating physics objects (`DatLiveEntityProjectionMaterializer.cs:1003-1016`, per the route inventory). Guard: only sets if record has no body yet (idempotent-create pattern) — see full read below for exact guard. 2. **`RuntimeEntityObjectLifetime.cs:766`** — `Entities.SetPhysicsBody(canonical, null)` inside a teardown method (need to confirm exact method — likely delete/retire path, paired with `Entities.SetPhysicsBodyAcquisitionInProgress(canonical, false)` at line 767 in the SAME method). Clears body on deletion/teardown. 3. **`RuntimeLocalPlayerPhysicsPublicationState.cs:405`** — `candidate.Record.SetPhysicsBody(candidate.Body)` inside `Commit(token, out activationToken)` (lines 373-411). **THIS IS THE DORMANT OPTION-2 MECHANISM** — see section 4 below. Guarded by `IsCurrent(candidate)` (epoch/session/identity/null-state re-check, lines 891-922) immediately before, and by `_physics.SetPosition.PrepareDormantLocalActivationOwnership(...)` called first (line 394) as the "seal the exact SetPosition owner before the irreversible no-fail suffix" step — i.e. this call site DOES chain into PrepareDormantLocalActivationOwnership per task 4's target. 4. **`RuntimeLocalPlayerPhysicsPublicationState.cs:1025`** — `_entities.SetPhysicsBody(activation.Record, null)` inside `DiscardActivation()` (994-1032), the rollback/teardown path for the SAME dormant mechanism — only fires if `_entities.IsCurrent(activation.Record)` AND `ReferenceEquals(activation.Record.PhysicsBody, activation.Body)` (i.e. never clobbers a body some OTHER newer owner already installed — the exact anti-pattern the rejected prototype failed on). 5. **`RuntimePhysicsState.cs:1558`** — `Entities.SetPhysicsBody(record, candidateBody)` — need full read; this is inside the remote/projectile body-binding family (see section 3). 6. **`RuntimePhysicsState.cs:1666`** — `Entities.SetPhysicsBody(record, candidate)` — need full read; this is the OTHER binding site, guarded by `PhysicsBodyAcquisitionInProgress` (set true at :1645, cleared at :1676/1678). **Writer count: 6 call sites, across 3 files** (`RuntimeEntityDirectory.cs` x1, `RuntimeEntityObjectLifetime.cs` x1, `RuntimeLocalPlayerPhysicsPublicationState.cs` x2, `RuntimePhysicsState.cs` x2). ## Consumers of `PhysicsOwnershipEpoch` Only bumped in one place (`RuntimeEntityRecord.SetPhysicsBody`, above). Consumers (all in `RuntimeLocalPlayerPhysicsPublicationState.cs`) treat it as a compare-and-reject epoch stamped into every token/activation struct: - `RuntimeLocalPlayerPhysicsPublicationToken.PhysicsOwnershipEpoch` (field, :53) captured at `Prepare` time (:314). - `RuntimeLocalPlayerPhysicsActivationToken.PhysicsOwnershipEpoch` (:70) captured as `token.PhysicsOwnershipEpoch + 1UL` (:328) — i.e. the activation token encodes "the epoch AFTER my own commit bumps it", so `IsActivationCurrent` (931-962) and `IsActivationOwnershipEnvelopeCurrent` (717-745) comparing `activation.Record.PhysicsOwnershipEpoch == activation.Token.PhysicsOwnershipEpoch` will FAIL (reject) the instant any OTHER writer (remote/projectile bind, GC clear, non-player static body creation via `RuntimeEntityDirectory` — none of which should ever touch a local-player record, but the check is defense-in-depth) touches the same record's PhysicsBody between prepare and commit. - `IsCurrent(candidate)` (891-922, pre-Commit re-check) also compares `candidate.Record.PhysicsOwnershipEpoch == candidate.Token.PhysicsOwnershipEpoch` (unincremented — i.e. "nobody touched the body between Prepare and Commit"). **This IS the reentrancy defense the rejected prototype lacked** — see section 6. ## 2. The two production local-player controller constructions, end to end ### Graphical: `PlayerModeController.BuildControllerAndCamera` `src/AcDream.App/Input/PlayerModeController.cs:244-525`. Constructor list (52-74) shows it is injected with `RuntimeLocalPlayerMovementState controllerSlot` (the SAME slot type headless writes) — confirms the route-inventory's "open question" (2026-08-02-cutover-route-inventory.md:204-207): **App DOES write `_controllerSlot.Controller = controller` directly, at line 486.** Not a mystery/asymmetry — both hosts write the exact same public setter. Steps, in order: 1. `_approachCompletions.BeginControllerLifetime()` (250) — App-only approach lifecycle token. 2. Capture rollback snapshots: `_camera.CaptureState()` (255), `_shadow.Capture()` (256) — presentation-only. 3. `new PlayerMovementController(_physics, playerRecord.ObjectClock, PlayerMovementConstructionOptions.From(_skills.Snapshot))` (259-262) — **uses the PUBLIC constructor**, whose default publication lifecycle is `StandalonePublished` (`PlayerMovementController.cs:617-626`), NOT `CandidatePreparing`/`CreatePublicationCandidate`. This is the key divergence from the dormant mechanism (section 4): this controller never enters the `CandidatePreparing -> CandidateSealed -> RuntimeOwnedDormant -> RuntimePublished` lifecycle at all. 4. Builds `MoveToManager`/`EntityPhysicsHost` closures over captured locals (267-346) — presentation-adjacent glue, host-specific. 5. `EntityPhysicsHostComposition.SelectStableHostWithoutRebind` (347-350) — canonical-state read (checks `LiveEntityRecord.PhysicsHost`). 6. `RuntimeMovementSkillProjection.ApplyTo(_skills, controller)` (366-368). 7. `ApplyStepHeights(controller, playerEntity, playerGuid)` (375) — **reads `DatReaderWriter.DBObjs.Setup` directly** (per headless's own comment contrasting itself, `HeadlessSessionWorldProjection.cs:685-689`) — NOT through the prepared-collision/`IPreparedCollisionSource` seam headless uses. Divergence #1. 8. `_controllerSlot.BeginMotionPreparation(controller, drainPriorAnimationQueue)` (404-407) — the ONE existing narrow "preparation lease" concept already in `RuntimeLocalPlayerMovementState` (separate from the dormant physics publication state) that lets a synchronous PartArray/type-5 completion reach the candidate `MotionInterpreter` before publish. 9. **Duplicate authority** — `_physics.Resolve(...)` (409-413) then `_physics.ResolvePlacement(...)` (422-430) — direct canonical-state-free collision resolve, entirely outside `RuntimeSetPositionState`. 10. `controller.PreparePositionForCommit(...)` (434-437), `controller.SetBodyOrientation(...)` (438). 11. Camera construction + `_camera.EnterChaseMode(...)` (440-447) — presentation-only, but happens BEFORE the final canonical commit (445-447 precede line 482-484) — i.e. camera activation today is NOT gated on a Runtime placement acknowledgement. 12. Re-check host stability (449-458) — throws if the host changed during camera activation (defensive, but ad hoc — not an epoch/token check, a bespoke `ReferenceEquals` re-read). 13. Shadow sync (`_shadow.SyncPose(...)`, 460-466). 14. `EntityPhysicsHostComposition.InstallOrRebind(...)` (472-475) + another `ReferenceEquals` stability re-check (476-480). 15. **Duplicate authority — final commit** (482-484): `playerEntity.SetPosition(initial.Position); playerEntity.ParentCellId = initial.CellId; controller.CommitPreparedPosition();` — direct writes to the App-side `WorldEntity`/render sidecar AND `controller`'s own internal frame, bypassing any Runtime `Place` receipt or `RuntimeEntityRecord` write. **`RuntimeEntityRecord.PhysicsBody`/`PhysicsOwnershipEpoch` are NEVER touched anywhere in this method** — `controller.PhysicsBody` (the `_body` field created in step 3) stays a private field of the `StandalonePublished` controller; nothing calls `Entities.SetPhysicsBody(playerRecord, controller.PhysicsBody)`. This means TODAY the canonical `RuntimeEntityRecord.PhysicsBody` slot for the graphical local player is **never populated at all** by this path — a previously-unstated confirmation that `SubmitPreparedPlacement`'s `operation.Record.PhysicsBody is not { } body` requirement (section 3) would REJECT any ordinary (non-initial) SetPosition submitted for the graphical local player today, because no writer ever puts a body on that record. (Route 2's "ForcePosition" duplicate authority, `LocalForcePositionTransaction`, works around this by mutating `PlayerMovementController`'s own body directly via `BlipPosition`, never touching `RuntimeEntityRecord.PhysicsBody` either — internally consistent with each other, both equally disconnected from the canonical record.) 16. Slot commits (485-492): `_hostSlot.Host`, `_controllerSlot.Controller = controller` (the public, unguarded setter — bumps `ControllerOwnershipEpoch` unconditionally, see section 4), `_chase.Legacy/Retail`, `_mode.IsPlayerMode = true`. 17. `catch`: rolls back camera + shadow only (494-518); does NOT roll back steps 15-16 because those are the LAST lines before `lifetimeCommitted = true` — structurally "hope nothing after this throws" rather than an explicit no-fail invariant. **Canonical-state mutations in this method: NONE on `RuntimeEntityRecord`** (no `SetPhysicsBody`, no `SetFullCell`, no object-clock call) — everything mutated is App-local (`WorldEntity`, `PlayerMovementController`'s private body, `RuntimeLocalPlayerMovementState.Controller`, `LocalPlayerPhysicsHostSlot`, camera, shadow). The ONLY canonical-record writes for the local player's initial placement happen earlier in the hydration pipeline (`LiveEntityRuntime.MaterializeLiveEntity`/ `RebucketLiveEntity`, route 1 hops 9-11) — entirely disjoint from this method. ### Headless: `HeadlessSessionWorldProjection.CreateController` + `SynchronizeLocalPlayer` `src/AcDream.Headless/Hosting/HeadlessSessionWorldProjection.cs:566-655` (read in full). `SynchronizeLocalPlayer` (566-615): 1. Guards on `record.ServerGuid == _runtime.PlayerIdentity.ServerGuid` and a present `Snapshot.Position` (568-573). 2. `_collision.CenterOn(position.LandblockId)` (575) — headless collision- neighborhood readiness, no graphical analog. 3. `_runtime.MovementOwner.Controller ?? CreateController(record)` (576-578) — lazy-construct-once via the SAME public `Controller` getter/setter `RuntimeLocalPlayerMovementState` exposes; no reentrancy guard against two concurrent calls both observing `null` (single-threaded host loop makes this safe in practice today, not structurally). 4. `_runtime.EntityObjects.Physics.Engine.Resolve(...)` (589-594) then `.ResolvePlacement(...)` (595-605) — **the exact same duplicate-authority shape as graphical step 9**, hardcoded `DefaultRadius`/`DefaultHeight` constants (visible in the call, actual values not read here) instead of `_motionBindings.GetSetupCylinder`. 5. `controller.SetPosition(...)` + `controller.SetBodyOrientation(...)` (610-614) — **duplicate final commit**, headless's version of graphical step 15. Also never touches `RuntimeEntityRecord.PhysicsBody`. `CreateController` (639-655): 1. `new PlayerMovementController(_runtime.EntityObjects.Physics.Engine, record.ObjectClock, PlayerMovementConstructionOptions.From(_runtime.CharacterOwner.MovementSkills.Snapshot))` (642-646) — **same PUBLIC constructor / `StandalonePublished` lifecycle** as graphical step 3. 2. `ApplySetupStepHeights(record, controller)` (649, body at 657-691) — **reads via `_preparedCollision.ReadSetupCollision(setupId)`** (668-679), the prepared-asset seam, NOT raw DAT — divergence #1 mirrored (headless uses the "correct"/prerequisite-B-aligned source; graphical does not). **Throws `InvalidDataException`** if the read status isn't `Loaded` (672-675) — propagates uncaught up through `SynchronizeLocalPlayer` -> `ProjectSpawn`/`ProjectPosition` -> the wire-dispatch call chain. This IS gate 10 (late headless prepared-collision failure) manifesting today as an unhandled exception, not a retry. 3. `RuntimeMovementSkillProjection.ApplyTo(_runtime.CharacterOwner.MovementSkills, controller)` (650-652). 4. `_runtime.MovementOwner.Controller = controller;` (653) — **the exact same public setter graphical step 16 uses.** **No headless equivalent of graphical steps 1 (approach lifetime), 8 (motion preparation lease), 11-14 (camera + host-stability re-checks), 17 (camera/ shadow rollback)** — headless has no camera/shadow/approach concept at all (confirmed, matches the route inventory's "No headless equivalent of graphical hops 12-14/19"). ### Top divergences between the two hosts (summary) 1. **Setup/collision data source**: App reads raw DAT (`ApplyStepHeights` via `_dats`/`_datLock`); headless reads the prepared/baked asset (`ApplySetupStepHeights` via `IPreparedCollisionSource`). Same target values, different pipeline — a real fidelity risk if the two ever diverge (baking staleness). 2. **Default cylinder fallback**: App falls back to `0.48f`/`1.835f` inline (`PlayerModeController.cs:416-420`) when `GetSetupCylinder` returns `< 0.05f` radius; headless uses named `DefaultRadius`/`DefaultHeight` constants at the `ResolvePlacement` call site (:599-600) — same intended values, defined in two places. 3. **Failure handling**: App's `BuildControllerAndCamera` has an explicit try/catch/rollback for camera+shadow; headless's `CreateController`/ `ApplySetupStepHeights` has NO surrounding try/catch — a prepared-collision read failure is a raw unhandled exception today. 4. **Presentation surface**: App additionally owns approach-completion lifetime, motion-preparation lease, chase camera, shadow sync — none of which headless has or needs. 5. **Neither host touches `RuntimeEntityRecord.PhysicsBody`, `PhysicsOwnershipEpoch`, or any `RuntimeSetPositionState` API** — both are 100% off to the side of the canonical record, confirmed by exhaustive grep (section 1's 6 writer call sites do not include either `PlayerModeController.cs` or `HeadlessSessionWorldProjection.cs`). --- ## 3. Every other body binding/consumer - **Remote dead-reckoning** (`RuntimeRemotePhysicsUpdater.cs` — flagged protected/dirty, read-only, NOT modified): grep confirms it only READS `record.PhysicsBody` via `ReferenceEquals(record.PhysicsBody, remote.Body)` currency checks (line 817) — it does not call `SetPhysicsBody`. The actual writer for remote motion is `RuntimePhysicsState.SetRemoteMotion` (`RuntimePhysicsState.cs:1446-1570`, full read) — throws `InvalidOperationException` on: binding-already-in-progress (1460-1464), body-would-be-replaced when a body already exists and doesn't match (1487-1492), losing an existing remote-placement contract (1493-1498), or post-callback ownership drift detected via a captured `sessionVersion`/`expectedBody`/`expectedRuntime` triple re-checked after the bind callback (1539-1549, "changed ownership during remote-motion binding"). Calls `Entities.SetPhysicsBody(record, candidateBody)` (:1558) ONLY when `expectedBody is null` (first bind) via `InitializeNewPhysicsBody` (:1556) — i.e. this is throw-on-conflict exclusivity (Option-1 flavor), not epoch/token gating. For a LOCAL PLAYER record this path should never fire (remote motion is for non-local entities) but the guard is defense-in-depth and IS one of the explicit gate checks (`!activation.Record.RemoteMotionBindingInProgress`/`RemoteMotion is null`) the dormant local-publication mechanism re-validates at every stage (section 4). - **Projectile binding**: `RuntimeProjectilePhysicsUpdater.cs` similarly only READS `record.PhysicsBody` (lines 447, 459, `ReferenceEquals` currency checks). The writer is `RuntimePhysicsState.BindProjectile` (`RuntimePhysicsState.cs:1309-1382`, full read) — same throw-on-conflict shape: binding-in-progress (1343-1347), body-mismatch on rebind (1330-1337), must-already-own-canonical-body-before-binding (1348-1352, "projectile must borrow its canonical physics body" — i.e. UNLIKE remote motion, `BindProjectile` requires `record.PhysicsBody` to ALREADY be non-null and matching BEFORE it will bind — it never calls `InitializeNewPhysicsBody`/`SetPhysicsBody` itself for a first-time body; something else (route 5's `ProjectileController.TryBind`, `ProjectileController.cs:176-265` per the route inventory) must construct the body ad hoc first via a DIFFERENT path than `GetOrCreatePhysicsBody` — worth flagging: **this is a 7th, App-side, ad hoc body-construction site not funneled through any of the 6 canonical writer methods** — App's `ProjectileController.TryBind` constructs a body and must be setting it onto the record through some other route (not confirmed by this pass; App-side `ProjectileController.cs` was not read in full — flag as open item, but it is explicitly OUT of C1's local-player scope per the campaign handoff's gate list item "remote and projectile binding/update" being about *interaction with* the local-player transaction, not projectile's own authority). - **`RuntimeSetPositionState.SubmitPreparedPlacement`** (`RuntimeSetPositionState.cs:2224-2274`, full read): requires `operation.Record.PhysicsBody is not { } body` to already be true (line 2254) — i.e. EVERY non-initial-construction SetPosition submission (ForcePosition, portal, remote Position, projectile correction) requires a body to already exist on the record, confirming the 6 writer sites in section 1 are the exhaustive set of "who can put the FIRST body on a record." For the local player specifically, only `RuntimeLocalPlayerPhysicsPublicationState.Commit` (section 4) does this today (dormant, unwired); in PRODUCTION, no writer ever populates `RuntimeEntityRecord.PhysicsBody` for either host's local player (section 2 finding) — meaning `SubmitPreparedPlacement` would reject a local-player submission in production today, which is consistent with the route inventory's finding that Route 2 (ForcePosition) and Route 3 (portal) both bypass `RuntimeSetPositionState` entirely via their own duplicate authorities instead. - **`RuntimeSetPositionState.PrepareDormantLocalActivationOwnership`**: see section 4 — the ONE place the local-player-specific dormant body attach happens; requires a pre-opened `Operation` in stage `AwaitingPreparation` from `TryBeginExclusiveAuthoredPlacement`. - **Object-clock epoch transitions** (`RuntimeEntityRecord.SuspendObjectClock`/`ResetObjectClockForEnterWorld`, both `internal`, bump `ObjectClockEpoch`): full call-site grep found BOTH the expected `RuntimeEntityDirectory` wrapper call sites (which run `EnsureKnown(record)` first, `RuntimeEntityDirectory.cs:311-321`) AND **direct unwrapped calls from `src/AcDream.App/World/LiveEntityRuntime.cs` at lines 879, 891, 897, 1258, 3030, 3033** — App calls `record.SuspendObjectClock()`/`record.ResetObjectClockForEnterWorld(...)` straight on the `RuntimeEntityRecord` (accessible because these are `internal` and `AcDream.App` has `InternalsVisibleTo`), bypassing the `RuntimeEntityDirectory` facade's `EnsureKnown` check entirely. This is inside `LiveEntityRuntime`'s `RebucketLiveEntity`-family code (comment references `prepare_to_enter_world`/retail `update_object`'s parent early-out — matches the already-known route-1/prerequisite-D `RebucketLiveEntity` duplicate authority). **Previously-unstated implication for C1**: the SAME record whose `ObjectClockEpoch` the dormant publication mechanism gates on can have its epoch bumped by this direct-call path DURING the window between `RuntimeLocalPlayerPhysicsPublicationState.Prepare` and `.Commit()`/ `.CommitActivation()` if `RebucketLiveEntity` runs concurrently for the SAME entity (e.g. a second CreateObject/Position causing a re-rebucket mid-construction) — the epoch check (`IsCurrent`/`IsActivationOwnershipEnvelopeCurrent` comparing `record.ObjectClockEpoch == token.ObjectClockEpoch`) WOULD catch and reject this correctly (fail-safe), but it confirms the gate is load- bearing against a REAL, already-existing production writer, not a hypothetical. - **Deletion/teardown**: `RuntimeEntityObjectLifetime.TryAcceptDelete` (`RuntimeEntityObjectLifetime.cs:1555+`) calls `Entities.TryDelete` then `Entities.RemoveActive(active)` (1587) — this IMMEDIATELY flips `Entities.IsCurrent(record)` to `false` for that record (removes it from the active-by-guid table), which is the single check `CanPrepare`/`IsCurrent`/`IsActivationCurrent`/every gate in section 4 depends on — so a delete landing at any point rejects the in-flight publication transaction on its NEXT check. Full body clear happens later in `RuntimeEntityObjectLifetime.CompleteProjectionRetirement` (:745-771, called from `RetireCanonicalOnly`/the graphical teardown-ack path): `Entities.SetPhysicsBody(canonical, null)` (:766) after `Physics.SetPosition.Forget(canonical, releasePreparedMover: true)` (:753, cancels any in-flight ordinary placement) and `ForgetInitialCreateResidence(canonical)` (:751, cancels any in-flight residence lease) — i.e. deletion cancels BOTH placement-lease families before clearing the body, consistent with prerequisite E's "quiesce before demote" discipline (though for landblock collision, not entity teardown — the pattern rhymes). - **`RuntimePhysicsState` per-frame body access**: `RuntimeOrdinaryPhysicsUpdater.cs`, `RuntimeRemotePhysicsUpdater.cs`, `RuntimeProjectilePhysicsUpdater.cs` each gate their per-tick work on `record.PhysicsBody is not { } body` / `ReferenceEquals(record.PhysicsBody, body)` currency checks (grep-confirmed, e.g. `RuntimeOrdinaryPhysicsUpdater.cs:68,284`) — read-only w.r.t. the `PhysicsBody` reference itself (they mutate the BODY's internal fields every tick, which is expected/normal simulation, not an ownership-slot write). No workset iterates and calls `SetPhysicsBody`. `RuntimePhysicsState.cs` itself has only two visible "workset" mentions (`ClearSpatialWorksets` at :1951, a doc-comment at :1307) — the ordinary/remote/projectile worksets live in their respective `RuntimeXPhysicsUpdater` files, out of this pass's read budget beyond the grep-confirmed read-only currency pattern above. --- ## 4. `RuntimeSetPositionState.PrepareDormantLocalActivationOwnership` — nucleus or dead end? **Definition** (`RuntimeSetPositionState.cs:1026-1052`, full read): ```csharp internal void PrepareDormantLocalActivationOwnership( RuntimeEntityRecord record, PhysicsBody body, in RuntimeEntityPlacementToken token) { ... if (!token.IsValid || record.Key != token.Entity || !_operations.TryGetValue(token.Entity, out Operation? operation) || operation.Token != token || operation.Stage is not RuntimeEntityPlacementStage.AwaitingPreparation || !ReferenceEquals(operation.Record, record) || record.PhysicsBody is not null // <- record must have NO body yet || !IsCurrent(operation) || body.InWorld || (body.TransientState & TransientStateFlags.Active) != 0) { throw new InvalidOperationException( "Dormant local activation must bind to the exact current placement owner."); } operation.Body = body; operation.DormantLocalActivation = true; } ``` It THROWS (does not return a status) on any invariant violation — by design a "this should be structurally impossible if the caller validated first" assertion, not a retryable rejection. It requires a PRE-EXISTING placement `Operation` already opened via `TryBeginExclusiveAuthoredPlacement` (`RuntimeSetPositionState.cs:1004-1024`) in stage `AwaitingPreparation` — i.e. it is NOT a standalone entry point; it is ONE STEP inside a larger chain that also needs prerequisite B's mover-preparation authority (`IsExactPreparedPlacementCurrent`, `RuntimeSetPositionState.cs:1318-1340`) satisfied for the SAME token/command before `RuntimeLocalPlayerPhysicsPublicationState.CanPrepare` will even call it. **What it was built for**: it is called from exactly ONE place in the whole repo — `RuntimeLocalPlayerPhysicsPublicationState.Commit` (`RuntimeLocalPlayerPhysicsPublicationState.cs:394-397`), as the "seal the exact SetPosition owner before the irreversible no-fail suffix" step, immediately before `candidate.Controller.CommitRuntimeOwnership(...)` and `candidate.Record.SetPhysicsBody(candidate.Body)`. It exists purely to make the PLACEMENT OPERATION (owned by `RuntimeSetPositionState`) and the BODY (owned by `RuntimeEntityRecord`) become mutually aware atomically, so that the SAME operation can later be walked through the full retail SetPosition staged commit (ground phase -> collision dispatch -> response -> final commit) via `TryEvaluateDormantLocalActivation` -> `TryPrepareDormantLocalActivationCommit` -> `TryApplyDormantLocalActivationCommit` -> `TryPrepareDormantLocalActivationFinalCommit` -> `TryApplyDormantLocalActivationFinalCommit` (`RuntimeSetPositionState.cs:2025-2077`, full read of the final-commit method) — the LAST of which is where `_entities.SetFullCell`, `_entities.AdvancePlacementCommit`, `body.InWorld = true`, `_entities.SetPhysicsHost`, `controller.CommitRuntimeActivationFrame()`, `_physics.Engine.UpdatePlayerCurrCell`, `_physics.AcknowledgeSpatialProjection`, `_entities.ResetObjectClockForEnterWorld` (object-clock epoch bump, task 3), and `controller.ActivateRuntimePublication()` (controller goes LIVE) ALL happen in one synchronous, no-branch-for-failure block (:2025-2077), gated immediately before by `IsDormantLocalActivationPrephaseCurrent`/re-validated epoch checks. **This is genuinely the full retail SetPosition commit, already ported, already wired to the same body/controller the dormant publication candidate built.** **Verdict: NUCLEUS, not a dead end** — but it is only ONE LOAD-BEARING STEP inside a much larger, ALREADY-COMPLETE mechanism: `RuntimeLocalPlayerPhysicsPublicationState` (1033 lines, `src/AcDream.Runtime/Gameplay/RuntimeLocalPlayerPhysicsPublicationState.cs`) + its ~15 `RuntimeSetPositionState` dormant-activation methods. Constructed once at `GameRuntime.cs:261` and exposed via `RuntimeLocalPlayerMovementState.PhysicsPublication` (:59-61, itself `internal`, throws if unbound). **Confirmed by exhaustive grep: ZERO production callers in `src/AcDream.App/` or `src/AcDream.Headless/`** — the only callers anywhere are `tests/AcDream.Runtime.Tests/Gameplay/RuntimeLocalPlayerPhysicsPublicationStateTests.cs`. This is, functionally, **Option 2 from the rejected-prototype note ("Off- canonical preparation followed by one validated atomic Runtime commit that publishes the prepared controller/body relationship without copying stale state over newer authority") already built end to end** — complete with: - a `Prepare`/`Commit`/`Discard` triad for the BODY/CONTROLLER pair (analogous to, and reusing, the SAME token-epoch pattern as `RuntimeSetPositionState`'s ordinary placement operations); - a SEPARATE `EvaluateActivation`/`CommitActivation`/`DiscardActivation` triad for actually driving the body through retail SetPosition's staged commit once the body/controller pair is sealed; - re-validation of `PhysicsOwnershipEpoch`, `ObjectClockEpoch`, `ControllerOwnershipEpoch`, `SessionLifetimeVersion`, identity `ServerGuid`+`Revision`, and null/in-progress state for RemoteMotion/ Projectile/PhysicsHost/DeleteAcceptedForTeardown at EVERY external entry point (`CanPrepare`, `IsCurrent`, `IsActivationCurrent`, `IsActivationOwnershipEnvelopeCurrent`, `IsCommittedActivationSuffixCurrent`) — this IS the reentrancy defense the rejected snapshot-lease prototype explicitly lacked (see section 6). **What is genuinely missing (the real C1 work), given this mechanism already exists:** 1. Nobody calls `TryBeginExclusiveAuthoredPlacement` + prerequisite B's `PrepareMover`/`ReadSetupCollision` chain + `PhysicsPublication.Prepare`/ `Commit`/`EvaluateActivation`/`CommitActivation` from either host — this IS the wiring gap, exactly like every other route in the cutover. 2. **The public `RuntimeLocalPlayerMovementState.Controller` setter (`RuntimeLocalPlayerMovementState.cs:37-50`) remains a live, unguarded escape hatch** — both `PlayerModeController.BuildControllerAndCamera:486` and `HeadlessSessionWorldProjection.CreateController:653` write it directly today, and NOTHING stops either host from continuing to do so even after C1 wires the dormant mechanism, unless that direct-write path is deleted/sealed off (e.g. made `internal` to only `RuntimeLocalPlayerPhysicsPublicationState`/`CommitRuntimeOwnedController`). The setter has NO epoch/token check on write (`CanCommitRuntimeOwnedController` is a SEPARATE, unused-by-the-setter validation method) — it will happily accept a second unguarded assignment even while a dormant activation is in flight, silently retiring whatever the dormant mechanism just published (`_controller?.RetireRuntimePublication()` at :45, which is a real no-op for anything not currently `RuntimeOwnedDormant`/ `RuntimePublished` — see section 6 gate 7). **This is the single most important pre-existing defect C1 must close: the "exclusive" adjective in prerequisite C's "one Runtime-owned exclusive/versioned...transaction" is not yet true while this direct setter remains reachable from hosts.** 3. Neither `new PlayerMovementController(physics, objectClock, options)` (public ctor, `StandalonePublished`) call site in the two hosts has been swapped for `PlayerMovementController.CreatePublicationCandidate` — until that swap happens, controllers built by either host never enter the `CandidatePreparing/CandidateSealed/RuntimeOwnedDormant/RuntimePublished` lifecycle the dormant mechanism's gates all key off of. --- ## 5. `PlayerMovementController` construction requirements Constructor needs (from both direct-ctor call sites AND `CreatePublicationCandidate`, `PlayerMovementController.cs:617-690`): - `PhysicsEngine physics` (shared engine reference, both hosts pass their own `RuntimePhysicsState`/`_runtime.EntityObjects.Physics.Engine`). - `RetailObjectQuantumClock? objectClock` — App passes `playerRecord.ObjectClock` (the CANONICAL record's clock, `RuntimeEntityRecord.ObjectClock` at `RuntimeEntityRecord.cs:62`, always non-null per its field initializer); headless passes `record.ObjectClock` identically. The dormant mechanism's `CreatePublicationCandidate` instead passes a THROWAWAY `new RetailObjectQuantumClock()` (`PlayerMovementController.cs:687-688`) at construction time and only swaps in the REAL `candidate.Record.ObjectClock` later, inside `Commit`, via `controller.CommitRuntimeOwnership(candidate.Record.ObjectClock)` (`RuntimeLocalPlayerPhysicsPublicationState.cs:403-404` -> `PlayerMovementController.cs:774-786`) — i.e. the dormant candidate is built against a SCRATCH clock so construction can never observe or mutate the canonical record's real clock before the atomic commit swaps it in. This is exactly the "off-canonical preparation" half of Option 2. - `PlayerMovementConstructionOptions` (RunSkill/JumpSkill) — both hosts build via `PlayerMovementConstructionOptions.From()`; the dormant mechanism's `Prepare` also takes this as a caller- supplied parameter (`Prepare(..., PlayerMovementConstructionOptions options, ...)`, :191) — no divergence in shape, only in WHERE the skill snapshot is read from (App's local `_skills` field vs. headless's `_runtime.CharacterOwner.MovementSkills` vs. the dormant mechanism taking it as a caller parameter either way). What construction MUTATES (beyond the private `_body`): `LocalEntityId`, `StepUpHeight`/`StepDownHeight` (Setup-derived), `SphereList` (Setup-derived, prerequisite B territory), `ObjectScale`, initial position/orientation via `PreparePositionForCommit`/`SetBodyOrientation`, physics state via `ApplyPhysicsState`, `MoveToFactory`/`PositionManager` (`MovementManager`/`MotionInterpreter` wiring). ALL of this is exactly what `RuntimeLocalPlayerPhysicsPublicationState.Prepare` (`RuntimeLocalPlayerPhysicsPublicationState.cs:187-355`) already does against its private `CreatePublicationCandidate`-built controller, reading `command.Physics.StepUpHeight/StepDownHeight/Spheres/Scale/Position/CellId/ CellLocalPosition/Orientation` from the CALLER-SUPPLIED `RuntimeSetPositionCommand` (i.e. the command already carries everything prerequisite B's mover-preparation chain produces) rather than reaching into DAT/prepared-collision itself. **What an "off-canonical preparation followed by one validated atomic commit" must DEFER** (confirmed by the dormant mechanism's own design, section 4): - The record's REAL `ObjectClock` (use a scratch clock during prep). - `RuntimeEntityRecord.PhysicsBody`/`PhysicsOwnershipEpoch` (never touch the canonical record during prep; only `SetPhysicsBody` inside `Commit`, and only after `PrepareDormantLocalActivationOwnership` succeeds). - `RuntimeLocalPlayerMovementState.Controller`/`ControllerOwnershipEpoch` (only via `CommitRuntimeOwnedController`, never the public setter, during prep). - `body.InWorld`/`TransientState.Active` (explicitly forced false during prep, `Prepare`, :292-293) — the body must not be simulatable until the LATER activation commit flips it (`TryApplyDormantLocalActivationFinalCommit`, `body.InWorld = true` at :2056). - World-residence/host/shadow/camera publication (all deferred to the activation phase / presentation-observer layer, never inside `Prepare`). --- ## 6. Adversarial gate list — exact code paths that would race TODAY (Campaign handoff's list, `docs/research/2026-07-31-remaining-physics-campaign-handoff.md:210-221`.) For each: what the ALREADY-BUILT dormant mechanism does (if wired) vs. what the CURRENT production direct-construction paths do (today, unwired). 1. **Nested construction** — Dormant: `CanPrepare` requires `_activation is null` AND `record.PhysicsBody is null` AND `_movement.Controller is null` (`RuntimeLocalPlayerPhysicsPublicationState.cs:862-889`) — a second `Prepare` while one is in flight is REJECTED structurally. Today: NEITHER `BuildControllerAndCamera` NOR `CreateController` has any such guard — `CreateController`'s `_runtime.MovementOwner.Controller ?? CreateController(record)` (`HeadlessSessionWorldProjection.cs:576-578`) is a bare null-coalesce, not an atomic test-and-set; only single-threaded host-loop scheduling prevents an actual race today. 2. **Reentrant SetPosition** — Dormant: every gate re-checks `PhysicsOwnershipEpoch`/`record.PositionAuthorityVersion` currency. Today: `BuildControllerAndCamera`'s final mutation (`playerEntity.SetPosition`/`ParentCellId`/`CommitPreparedPosition`, PlayerModeController.cs:482-484) has zero epoch check — a same-thread reentrant call (e.g. from a nested wire dispatch) would silently clobber with no detection. 3. **Remote and projectile binding/update** — Dormant: `CanPrepare`/ `IsCurrent`/`IsActivationCurrent` all check `record.RemoteMotion is null`, `record.Projectile is null`, `!RemoteMotionBindingInProgress`, `!ProjectileBindingInProgress` (defense-in-depth; should never legitimately fire for a local-player record). Today: no such check exists in either host's direct construction path. 4. **Deletion and same-GUID new incarnation** — Dormant: `_entities.IsCurrent(record)` checked at every gate; `TryAcceptDelete` -> `RemoveActive` flips this immediately (section 3). Today: `BuildControllerAndCamera`/`CreateController` take a fixed `RuntimeEntityRecord`/`WorldEntity` parameter with NO re-validation against current canonical identity at the final commit. 5. **Projection-owner replacement** — Dormant: `_entities.SessionLifetimeVersion == token.SessionGenerationAuthority` checked throughout. Today: no generation check in either direct path. 6. **Object-clock epoch change** — Dormant: `ObjectClockEpoch` compared at every gate (section 3/4). Today: no check; AND there is a REAL, live concurrent writer already in production — `LiveEntityRuntime.cs:879/891/897/1258/3030/3033`'s direct `record.SuspendObjectClock()`/`ResetObjectClockForEnterWorld(...)` calls inside the `RebucketLiveEntity` family (section 3) — this is not a hypothetical gate, it is a currently-active call path on the SAME record type. 7. **Reset and disposal** — Dormant: `ResetSession()`/`Dispose()` on `RuntimeLocalPlayerMovementState` explicitly cascade into `_physicsPublication?.ResetSession()`/`Dispose()` (`RuntimeLocalPlayerMovementState.cs:244-295`), which tear down candidate/activation state via `ReferenceEquals`-gated clears (never clobbering a newer owner, `DiscardActivation`, `RuntimeLocalPlayerPhysicsPublicationState.cs:1002-1032`). Today's direct- construction controllers are built via the PUBLIC constructor (`StandalonePublished` lifecycle) — **`RetireRuntimePublication()` (`PlayerMovementController.cs:837-846`) only transitions `RuntimeOwnedDormant`/`RuntimePublished` state; it is a NO-OP for `StandalonePublished` controllers** — a previously-unstated finding: TODAY, `ResetSession()`/`Dispose()`/replacing `.Controller` on either host's directly-built controller produces NO explicit lifecycle transition at all; the controller is simply dropped/GC'd. Not a visible bug today (nothing reads `IsRuntimePublished` for these), but it means today's controllers are invisible to the exact teardown bookkeeping C1's target mechanism relies on. 8. **Commit and rollback after replacement** — Dormant: ALL validation happens before the single canonical mutation (`PrepareDormantLocalActivationOwnership`, which itself throws leaving state untouched on failure); everything after is documented as "callback-free, non-allocating, and cannot fail" (`RuntimeLocalPlayerPhysicsPublicationState.cs:391-393`) — no rollback- after-newer-authority path exists BECAUSE nothing after that point can fail by construction. Today: `BuildControllerAndCamera`'s try/catch rolls back camera+shadow only; the final `playerEntity.SetPosition`/ `ParentCellId`/`CommitPreparedPosition` triad (482-484) has nothing after it that can throw, so it's accidentally safe today, not structurally guaranteed. 9. **Late graphical camera/shadow/host failure** — Today: `BuildControllerAndCamera` DOES handle this (explicit `_camera.RestoreState`/`_shadow.Restore` in the catch block, 494-518) — this is the ONE gate the CURRENT graphical path already handles reasonably. The dormant Runtime-side mechanism has NO camera/shadow concept (presentation-independent by design) — C1 must layer this handling in the PRESENTATION/observer phase (post-Runtime- commit), matching prerequisite D's rule that a host exception must not roll Runtime back, only retry the FIFO head. 10. **Late headless prepared-collision failure** — Today: `ApplySetupStepHeights` (`HeadlessSessionWorldProjection.cs:657-691`) throws a raw, uncaught `InvalidDataException` (672-675) if the prepared Setup collision isn't `Loaded` — this propagates up through `CreateController` -> `SynchronizeLocalPlayer` -> `ProjectSpawn`/ `ProjectPosition` with NO try/catch anywhere in between (grep-confirmed no surrounding try/catch in `HeadlessSessionWorldProjection.cs`'s these methods) — a genuinely unhandled-exception risk in production headless TODAY, not just a hypothetical C1 gate. --- ## Summary for the C1 contract - **Writer count**: 6 confirmed call sites of `RuntimeEntityRecord.SetPhysicsBody` across 3 files (`RuntimeEntityDirectory.cs:359`, `RuntimeEntityObjectLifetime.cs:766`, `RuntimeLocalPlayerPhysicsPublicationState.cs:405,1025`, `RuntimePhysicsState.cs:1558,1666`) — plus a probable 7th App-side ad hoc projectile body-construction site not yet traced to a canonical writer (flagged, out of local-player scope). - The dormant `RuntimeLocalPlayerPhysicsPublicationState` + `RuntimeSetPositionState`'s ~15 dormant-activation methods already implement essentially the COMPLETE Option 2 transaction (off-canonical prepare against a scratch clock/sealed candidate controller, single validated atomic commit, full retail-staged SetPosition activation) with epoch/token/generation/identity re-validation at every external entry point — it has ZERO production callers in either host. - The single largest remaining defect even AFTER wiring: the public `RuntimeLocalPlayerMovementState.Controller` setter is an unguarded escape hatch both hosts currently use directly; it must be sealed (made unreachable from hosts, or itself epoch-gated) for the word "exclusive" in prerequisite C to be true.