acdream/docs/research/2026-07-26-slice-j5-5-physics-remote-ownership.md
Erik fce8e7b18e docs(runtime): close per-session physics ownership
Record J5.5 production SHA, complete Release baseline, exact-binary lifecycle/reconnect and nine-stop collision/movement evidence, and rollback. Synchronize architecture, roadmap, milestones, AGENTS/CLAUDE, and advance the active program to J5.6 projectile runtime.

Co-authored-by: Codex <noreply@openai.com>
2026-07-26 13:59:06 +02:00

9.4 KiB

Slice J5.5 — per-session physics and remote-simulation ownership

Date: 2026-07-26 Scope: ownership relocation only; no retail algorithm or gameplay-policy change

Objective

Make one AcDream.Runtime instance own one complete mutable physics world:

  • one PhysicsEngine, its transition-scratch arena, and its shadow registry;
  • one production PhysicsDataCache/cell graph;
  • canonical physics bodies and physics hosts;
  • canonical remote movement/interpolation state;
  • loaded/cell-backed ordinary and remote update worksets.

App remains responsible for DAT/package preparation, streaming policy, animation pose production, render projection, effects, meshes, debug drawing, and UI. It publishes immutable prepared collision records and animation-root inputs to the Runtime owner, then applies committed Runtime snapshots to graphical objects.

This is the J5.5 boundary from docs/plans/2026-07-26-modern-runtime-slice-j5.md. Projectile component ownership and prediction remain explicitly deferred to J5.6.

Named-retail oracle

Primary source: docs/research/named-retail/acclient_2013_pseudo_c.txt.

  • CPhysics::UseTime 0x00509950
  • CPhysicsObj::UpdatePositionInternal 0x00512C30
  • CPhysicsObj::transition 0x00512DC0
  • CPhysicsObj::SetPositionInternal(CTransition const*) 0x00515330
  • CPhysicsObj::UpdateObjectInternal 0x005156B0
  • CPhysicsObj::update_object 0x00515D10
  • CPhysicsObj::MoveOrTeleport 0x00516330
  • CPhysicsObj::add_shadows_to_cells 0x00514AE0

The complete translated control flow is already pinned in docs/research/2026-07-19-r6-update-object-order-pseudocode.md. The current Core/App implementation was cross-checked there and in the R6/physics digest against ACE's PhysicsObj interpretation and the extracted WorldBuilder collision/content pipeline. J5.5 reuses that port unchanged.

Preserved pseudocode

for each ordinary object in the active object table:
    elapsed = current physics time - object update time
    apply retail epsilon / stale-quantum / subdivision gates

    if object is Active:
        if not Hidden:
            advance PartArray and obtain the complete root-motion Frame
        apply PositionManager correction to that Frame
        compose the candidate position and orientation
        if not Hidden:
            integrate acceleration, velocity, and omega
        drain object animation hooks

        if the candidate frame moved:
            run Transition against the object's current full cell
            commit accepted frame, contact state, and full cell
            update the object's collision shadows

        DetectionManager.CheckDetection
        TargetManager.HandleTargetting
        MovementManager.UseTime
        PartArray.HandleMovement
        PositionManager.UseTime

    ParticleManager.UpdateParticles
    ScriptManager.UpdateScripts

The App/Runtime seam may split pose production from simulation, but it must not change this observable ordering. In particular:

  • root motion and the position-manager delta are complete before collision;
  • the transition's swept full cell is canonical;
  • a Hidden object is not the same as an inactive or deleted object;
  • exact record/incarnation, authority version, and object-clock epoch are revalidated after every callback;
  • remote shadows follow the committed body frame, never a raw server sample;
  • CellGraph.CurrCell remains local-player-only state.

Baseline ownership gap

The canonical RuntimeEntityRecord already owns PhysicsBody, IPhysicsObjHost, full cell, final physics state, accepted authority versions, and RetailObjectQuantumClock. The remaining duplicate boundary is:

  • GameWindow constructs the session PhysicsEngine and production PhysicsDataCache;
  • App LiveEntityRecord stores the remote-motion component;
  • App LiveEntityRuntime stores remote and ordinary spatial workset indexes;
  • App updaters both mutate canonical simulation and project WorldEntity;
  • App streaming mutates the engine directly.

That baseline shape prevented a no-window Runtime from owning the same simulation graph and made two simultaneous sessions harder to prove isolated. J5.5 retires this gap.

Target ownership

RuntimeEntityObjectLifetime constructs one RuntimePhysicsState beside its entity directory. RuntimePhysicsState owns:

  • the exact PhysicsEngine and production cache;
  • remote components and physics hosts stored on RuntimeEntityRecord;
  • keyed ordinary/remote worksets containing exact RuntimeEntityKey values;
  • typed collision admission/withdrawal receipts;
  • simulation commits and immutable presentation snapshots;
  • reset/disposal convergence and an ownership ledger.

App acknowledgements contain no gameplay policy:

prepared collision publication -> Runtime typed admission -> receipt
render spatial visibility edge  -> Runtime workset acknowledgement
animated root Frame             -> Runtime remote/ordinary tick
Runtime committed snapshot      -> App WorldEntity/rebucket/pose projection

The immutable prepared collision payload may originate in App streaming. The engine, transition scratch, cell graph, body, shadow registry, interpolation, manager state, and workset are never shared across Runtime instances.

Implemented boundary

  • RuntimeEntityObjectLifetime constructs and disposes exactly one RuntimePhysicsState.
  • RuntimePhysicsState constructs the production PhysicsDataCache and the sole PhysicsEngine, including its ten-deep reusable transition scratch and shadow registry. App borrows both objects and cannot construct alternatives.
  • RuntimeEntityRecord owns the canonical PhysicsBody, RemoteMotion, EntityPhysicsHost, full cell, object clock, and exact-incarnation binding guards.
  • RuntimePhysicsState owns keyed ordinary/remote worksets, body acquisition, host installation/rebinding/lookup, remote component binding, and typed canonical cell commits.
  • RuntimeRemotePhysicsUpdater and RuntimeOrdinaryPhysicsUpdater contain the unchanged presentation-free retail simulation. Their App adapters supply DAT-derived shape/animation inputs and project immutable pose snapshots only.
  • LandblockPhysicsPublisher publishes the prepared collision root through a generation-scoped RuntimeCollisionAdmission; demotion and withdrawal cross the same typed Runtime boundary.
  • Runtime cell commits synchronously publish RuntimePhysicsCellCommit. The graphical subscriber revalidates the exact record and spatial-authority version before rebucketing the render projection.
  • Two Runtime instances own distinct engines, caches, cell graphs, scratch arenas, shadow registries, components, hosts, bodies, and worksets.

No retail algorithm, constant, order, packet, or gameplay policy changed, and this ownership relocation introduces no retail-divergence row.

Staged implementation boundary

  1. Construct engine/cache under RuntimePhysicsState; make App borrow them.
  2. Move presentation-free RemoteMotion and EntityPhysicsHost types into Runtime and store the remote component on RuntimeEntityRecord.
  3. Move remote/ordinary keyed worksets and their visibility acknowledgements into RuntimePhysicsState.
  4. Split remote/ordinary update into Runtime simulation commits and App presentation acknowledgements without changing update order.
  5. Replace direct streaming mutation with typed Runtime admission/withdrawal receipts.
  6. Remove App simulation mirrors and prove reset/two-instance isolation.

Each intermediate state must build and retain exact behavior. The production commit remains independently revertible as the single J5.5 ownership unit.

Acceptance evidence

  • existing flat-collision conformance corpus remains bit-identical;
  • reused versus fresh transition scratch stays equivalent and allocation-free;
  • local and remote position/cell/orientation fixtures remain exact;
  • crowd, doors, stairs, cell seams, Hidden, teleport, delete, and GUID-reuse fixtures pass;
  • two Runtime instances have distinct engine, cache, scratch, shadows, bodies, hosts, remote components, and worksets;
  • App production source cannot construct a PhysicsEngine, PhysicsDataCache, canonical remote component, or simulation workset;
  • Release build, focused Runtime/App suites, complete Release suite, connected lifecycle/reconnect, and the canonical movement route pass.

Automated gate on the J5.5 production tree:

  • Release solution build: zero warnings and zero errors.
  • Core collision/physics suite: 3,273 passed / 2 skipped.
  • Runtime suite: 314 passed.
  • App suite: 3,718 passed / 3 skipped.
  • Complete solution: 8,588 passed / 5 skipped.
  • Source ownership guards prove App does not construct a PhysicsEngine or production cache, does not contain the remote/ordinary transition solver, and cannot directly admit/remove streamed landblock collision.

Connected gates pass on exact production commit 7e6033d0adcd0b572c20e89dd275746fb442d52f:

  • logs/connected-world-gate-20260726-134107/report.json completed capped login and uncapped fresh-process reconnect, all 7 readiness checkpoints, graceful code-zero exits, and zero failures;
  • logs/connected-r6-soak-20260726-134638.report.json matched source and binary SHA, materialized all 9 destinations with render and collision ready, passed forward/jump/combat/authoritative movement exercises at Caul, Holtburg, and Caul return, and exited gracefully with code zero and zero failures.

Exact production rollback:

git revert 7e6033d0adcd0b572c20e89dd275746fb442d52f