acdream/docs/plans/2026-07-26-modern-runtime-slice-j5.md
Erik 0dc3bfdeff docs(runtime): close local movement ownership
Record the exact J5.4 automated, lifecycle/reconnect, and nine-stop movement evidence; advance the Modern Runtime program to J5.5; and synchronize architecture, roadmap, milestones, AGENTS/CLAUDE, rollback, and durable research pointers.

Co-authored-by: Codex <noreply@openai.com>
2026-07-26 12:53:41 +02:00

474 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Modern runtime Slice J5 — movement, physics, interaction, and combat
**Status:** ACTIVE — J5.1J5.4 complete; J5.5 next
**Parent:** `2026-07-25-modern-runtime-slice-j.md`, J5
**Production base:** `2c67a2c3`
**Authorization:** the user approved Slices FL, including the Slice J
gameplay-owner gates, on 2026-07-24
## Objective
Move the complete presentation-independent action and simulation graph into
`AcDream.Runtime` while preserving retail behavior and the accepted graphical
feel.
At completion:
- Runtime owns selection, interaction mode/transactions, combat and spell-cast
intent, local/remote movement, outbound cadence, per-session physics, and
projectile simulation;
- App converts physical input into typed commands and projects committed state
into cameras, retained UI, animation, sound, particles, markers, and meshes;
- graphical and future no-window hosts borrow the same owners and observe the
same ordered state;
- no render callback, UI element, or camera object is gameplay authority.
## Presentation boundary
### Moves to Runtime
- selected/previous object identity;
- temporary use/examine/use-item-on-target mode;
- appraisal/use/pickup/approach transaction identity;
- combat mode, attack build/request/repeat intent, target identity;
- spell-cast request intent;
- `PlayerMovementController` state, movement interpretation, canonical local
body, object clock, movement managers, and outbound cadence;
- per-session `PhysicsEngine`, transition scratch, shadow/collision gameplay
state;
- remote canonical body/movement state;
- projectile component state and simulation;
- typed views, commands, ordered events, reset, disposal, and ownership
ledgers for all of the above.
### Remains in App
- Silk input sources and configurable key/chord mapping;
- camera orbit, mouse cursor capture, and device-delta filtering;
- world ray construction/picking;
- selection lighting pulse, vivid markers, and selected-object HUD;
- combat/spell bars and retained target-mode cursor images;
- animated part/root pose composition;
- meshes, terrain/EnvCell streaming publication, sounds, particles, lights,
translucency, and debug drawing;
- UI text, toasts, drag/drop visuals, pending-slot mesh, and appraisals'
retained window.
The camera's instant mouse-look mode still emits typed retail turn/sidestep
commands to Runtime. The camera may not write the player heading directly.
## Fixed invariants
1. Retail algorithms and branch/order semantics do not change during the move.
2. One mutable owner exists for every state class.
3. Runtime has no App/UI/backend dependency.
4. `RuntimeEntityRecord` remains canonical entity identity and physics
authority; App `LiveEntityRecord` remains a projection sidecar.
5. `RuntimeInventoryState` remains the only busy/inventory-transaction owner.
6. Core flat collision data is immutable/shareable. Each runtime/session owns
its `PhysicsEngine`, transition scratch, bodies, shadows, interpolation, and
projectile state.
7. All mutation stays on the existing update thread. Network workers enqueue
immutable messages only.
8. App input-to-Runtime commands are synchronous; no extra frame, polling
mirror, or background queue is introduced.
9. App presentation callbacks may re-enter/delete/replace entities. Every
continuation revalidates exact record, incarnation, authority version, and
object-clock epoch before commit.
10. Reset/disposal executes every suffix after an observer failure and refuses
a new session until the complete ownership ledger converges.
11. Every sub-slice is independently buildable, tested, connected-gated where
behavior can change, documented, committed, and given an exact rollback.
## Execution ledger
| Sub-slice | Status | Result/evidence |
|---|---|---|
| J5.0 owner/retail inventory | complete | `docs/research/2026-07-26-slice-j5-owner-and-retail-order-inventory.md` |
| J5.1 canonical action state | complete | `b298f99f913249d299796e6a71f7a9b6b283ac1a`; one Runtime selection/combat/target-mode owner; 182 Runtime tests, 3,779 App tests / 3 skips, 8,550 complete Release tests / 5 skips, exact-binary connected lifecycle/reconnect pass |
| J5.2 interaction transactions | complete | `f5f7b4177f449ebcad9724bfea263ef73ab60255`; one Runtime transaction owner; 197 Runtime tests, 3,775 App tests / 3 skips, 8,561 complete Release tests / 5 skips, exact-binary connected lifecycle/reconnect pass |
| J5.3 combat and magic intent | complete | `20df9d155db50706a42420d60a9b15861cf4bfe7`; exact Runtime attack/mode/target/cast owners; 223 Runtime tests, 3,754 App tests / 3 skips, 8,566 complete Release tests / 5 skips, exact-binary connected lifecycle/reconnect pass |
| J5.4 local movement and outbound cadence | complete | `aa3f4a60f87f2cbebc3d8ecd5e33d779b7fb13c1`; one Runtime movement/controller/cadence owner; 303 Runtime tests, 3,716 App tests / 3 skips, 8,575 complete Release tests / 5 skips, exact-binary lifecycle/reconnect and nine-stop movement gates pass |
| J5.5 per-session physics and remote simulation | active | engine/scratch/shadows/remote canonical body |
| J5.6 projectile runtime | pending | canonical component/simulation plus App projection acknowledgements |
| J5.7 combined cleanup and closeout | pending | no mirrors, no-window parity, teardown, connected and visual gates |
## J5.1 — canonical action state
Create one Runtime owner for:
- `SelectionState`;
- `CombatState`;
- presentation-free interaction/target-mode state.
Actions:
1. Move interaction-mode types/state from App UI into Runtime gameplay.
2. Make Runtime construct all three exact owners.
3. Remove Program's selection construction and GameWindow's direct combat
construction.
4. Make App composition, session routing, retained UI, plugins, and current
Runtime commands/views borrow the exact Runtime instances.
5. Remove `ItemInteractionController`'s optional private
`InteractionState` fallback; production and tests must pass the exact owner.
6. Add a combined ownership/revision snapshot and failure-safe reset/disposal.
7. Add Runtime views for selection, combat mode/known health, and interaction
mode without exposing mutable collections.
Gate:
- named-retail selection order and deduplication;
- combat Begin/reset defaults;
- target-mode enter/acquire/cancel/reset;
- UI/plugin observer failure isolation;
- two Runtime instances in one process;
- exact graphical/direct owner identity;
- source guard proving App cannot construct a production owner;
- Runtime dependency and assembly-load closure;
- focused Runtime/App tests, Release build, full Release suite, connected
lifecycle/reconnect route.
Completed 2026-07-26 at
`b298f99f913249d299796e6a71f7a9b6b283ac1a`. `RuntimeActionState` now
constructs the exact selection, combat, and temporary interaction-mode
children. Program, plugins, retained UI, session routing, typed commands/views,
and terminal shutdown borrow those exact instances. The App-owned
`InteractionState` and `ItemInteractionController` fallback are deleted.
Failure-safe reset/disposal, two-instance isolation, normalized checkpoints,
dependency closure, and production source guards pass. The exact-binary
connected report is
`logs/connected-world-gate-20260726-104445/report.json`: 7/7 ready
checkpoints, two graceful code-zero exits, zero failures, and only the 25
expected world-edge landblock misses. Evidence:
[`../research/2026-07-26-slice-j5-1-canonical-action-state.md`](../research/2026-07-26-slice-j5-1-canonical-action-state.md).
## J5.2 — interaction transactions
Split App orchestration into:
- App `WorldSelectionQuery`/picker/lighting/drag presentation;
- Runtime interaction transaction owner;
- typed query, movement, inventory-policy, transport, and presentation
acknowledgement seams.
Runtime owns:
- use throttle and source/target identity;
- appraisal request/current identity;
- ordinary use reservation transfer to authoritative UseDone;
- pickup request and exact post-arrival identity/token;
- ordered outbound interaction queue;
- entity-hidden/deleted cancellation;
- reset/disposal convergence.
App retains:
- cursor position and world ray;
- lighting pulse;
- toasts/text rendering;
- retained drag/drop and pending-slot drawing.
Ordering:
- ordinary Use sends immediately, then transfers its busy reservation to
UseDone;
- targeted Use enters mode until a compatible target is acquired;
- pickup's same-frame send drains after local movement output and before
inbound dispatch;
- post-arrival pickup sends once only on natural completion;
- stale/replaced object identities never execute queued work.
Gate:
- current connected near/far door/NPC/corpse use;
- item-on-target, appraisal, pickup, pending-slot accept/failure;
- same-frame W-release plus R;
- delete/GUID reuse, hidden target, cancellation, transport failure, callback
reentrancy, reset/disposal;
- normalized graphical/direct ordered traces and no duplicate busy owner.
Completed 2026-07-26 at
`f5f7b4177f449ebcad9724bfea263ef73ab60255`.
`RuntimeInteractionTransactionState`, owned beneath `RuntimeActionState`, now
owns the retail 200-ms use gate, exact use source/target identity, pending and
current appraisal identity, typed ordered interactions, and the exact
post-arrival pickup token. It borrows—not duplicates—J4's
`InventoryTransactionState`, so ordinary Use transfers one busy reference to
authoritative UseDone and pickup retains the same one-request-at-a-time gate.
App retains world rays, lighting, movement installation, transport, toasts,
drag/drop, and pending-slot presentation. The old App delegate queue and App
transaction fields are deleted.
Identity-bound work is cancelled by exact local incarnation on delete and by
server GUID on Hidden. Re-entrant reset, disposal, transport failure, stale
approach completion, and GUID reuse cannot resurrect a transaction or strand
the busy gate. Focused near/far use, carried-use, appraisal, item-on-target,
pickup, pending-slot, hidden/delete, reset, and callback-order tests pass.
The exact-binary connected report is
`logs/connected-world-gate-20260726-111330/report.json`: 7/7 ready
checkpoints, two graceful code-zero exits, zero failures or invariant
violations, and only the 25 expected world-edge landblock misses. Evidence:
[`../research/2026-07-26-slice-j5-2-interaction-transactions.md`](../research/2026-07-26-slice-j5-2-interaction-transactions.md).
## J5.3 — combat and magic intent
Move:
- `CombatAttackController`'s presentation-free build/request/repeat state;
- combat-mode selection/default policy;
- target death/auto-target identity transitions;
- `SpellCastingController` intent and last-request state.
Replace `InputAction` dependencies with Runtime-specific typed commands.
App maps configured actions and bar/button presses onto those commands and
projects Runtime snapshots.
Keep App-only:
- combat/spell bar widgets;
- camera target tracking;
- animation, sound, particles, and response text layout;
- DAT catalog/icon/formula presentation.
Ordering:
- movement aborts repeat attack at the existing retail input boundary;
- targeted attack/cast turns through the shared movement owner before
release;
- cast stops movement, emits exactly one targeted/untargeted request, then
increments the shared busy reference;
- server attack/cast completion remains authoritative.
Gate:
- power-bar cadence and height selection;
- repeat start/abort/movement cancellation;
- combat-mode equipment defaults;
- 180-degree bow/spell target facing;
- hostile-only auto-target after death;
- self/untargeted/targeted spell requests, component failure, busy completion;
- graphical bar parity and direct typed-command parity.
**Completed 2026-07-26 at
`20df9d155db50706a42420d60a9b15861cf4bfe7`.** `RuntimeActionState`
constructs and owns the exact combat-attack, combat-target, combat-mode, and
spell-cast intent children. Retained attack/spell bars and graphical input
borrow those owners; direct Runtime combat/magic commands drive the same
operations and snapshots without a retained UI. App retains world/content
queries, transport, bars, animation, sound, particles, and response text.
Runtime tests pass 223/223, App tests pass 3,754/3 skips, and the complete
Release suite passes 8,566/5 skips. The exact-binary connected report
`logs/connected-world-gate-20260726-115752/report.json` passes two sessions,
7/7 checkpoints, graceful code-zero exits, and zero failures. Evidence:
[`../research/2026-07-26-slice-j5-3-combat-magic-intent.md`](../research/2026-07-26-slice-j5-3-combat-magic-intent.md).
## J5.4 — local movement and outbound cadence
Move `PlayerMovementController`, its data types, and
`LocalPlayerOutboundController` into Runtime. Replace test-era environment
reads with typed construction options and the Runtime character movement-skill
projection.
App provides:
- current typed movement snapshot from the input dispatcher;
- filtered mouse-look turn adjustment;
- animation root-motion frame and completion acknowledgements;
- optional diagnostic sink.
Runtime owns:
- canonical local `PhysicsBody`, `MotionInterpreter`, `MovementManager`,
`MoveToManager`, `PositionManager`, and object clock;
- local input edge interpretation;
- run lock, jump charge/launch, movement/contact state;
- target-facing movement;
- pre-inbound MTS/jump and post-inbound autonomous-position send cadence;
- complete canonical `Position`, contact-plane, timestamps, and sent baselines.
Gate:
- bit-exact `RawMotionState`, MTS, jump, and autonomous-position fixtures;
- strict cadence/equality boundaries;
- complete quaternion/cell-local frame;
- short-tap animation-owned start;
- run/walk/back/strafe/turn/mouse-look/jump/land;
- portal/focus/reset teardown;
- target-facing and movement-aborts-repeat ordering;
- zero added per-frame allocations after warmup.
**Completed 2026-07-26 at
`aa3f4a60f87f2cbebc3d8ecd5e33d779b7fb13c1`.**
`RuntimeLocalPlayerMovementState` constructs and owns the exact
`PlayerMovementController`, construction-time motion seam, autorun latch,
typed movement view, and terminal ledger. The movement controller and
`LocalPlayerOutboundController` now live in `AcDream.Runtime.Gameplay`.
Graphical input samples physical state and borrows that owner; direct Runtime
commands mutate the same state without an App/input detour. Character
run/jump skill projections enter through typed construction options rather
than process environment reads. Runtime tests pass 303/303, App tests pass
3,716/3 skips, and the complete Release suite passes 8,575/5 skips. The
exact-binary connected lifecycle/reconnect report
`logs/connected-world-gate-20260726-123425/report.json` passes both sessions,
7/7 readiness checkpoints, graceful code-zero exits, and zero failures. The
canonical route
`logs/connected-r6-soak-20260726-124049.report.json` passes all nine
destinations; forward, jump, combat, and authoritative movement-truth
exercises pass at Caul, Holtburg, and the Caul return before graceful
shutdown. Evidence:
[`../research/2026-07-26-slice-j5-4-local-movement-ownership.md`](../research/2026-07-26-slice-j5-4-local-movement-ownership.md).
## J5.5 — per-session physics and remote simulation
Add a Runtime physics owner that constructs one `PhysicsEngine` per runtime
instance. App streaming publishes immutable prepared collision assets through
typed admission/withdrawal acknowledgements.
Move canonical remote simulation state and component indexes from App sidecars
to `RuntimeEntityRecord`/Runtime owners:
- remote body/interpolation/movement-manager state;
- canonical cell/rebucket writes;
- physics-host lookup;
- shadow/collision gameplay membership;
- ordinary-object update workset.
App consumes committed snapshots/events to:
- update `WorldEntity`;
- rebucket render projections;
- publish current root/part/equipped-child poses;
- refresh graphical collision/debug views.
Gate:
- complete flat collision conformance corpus remains bit-identical;
- fresh/reused engine parity and zero-allocation resolve profiles;
- player and remote position/cell/orientation parity;
- crowd de-overlap, doors, stairs, dungeon/cell seams, login placement;
- hidden/pending/rehydration, teleport correction, delete/GUID reuse;
- two concurrent Runtime instances prove scratch/shadow isolation.
## J5.6 — projectile runtime
Move projectile component identity, prediction versions, and simulation into
Runtime. Store the canonical component on `RuntimeEntityRecord`, not the App
sidecar.
Runtime uses:
- existing Core `ProjectilePhysicsStepper`;
- canonical body/cell/state/timestamp authority;
- strict prepared collision shapes;
- existing split Begin/Complete prediction with exact-version revalidation.
App acknowledges successful commits by:
- updating/rebucketing the render projection;
- synchronizing graphical shadow representation;
- publishing effect root/pose.
App does not decide collision outcome, impact, damage, effect, or deletion.
Gate:
- existing clamp/gravity/AlignPath/angular/collision/thin-wall fixtures;
- designated-target exclusion semantics;
- loaded/pending/cross-landblock/correction/delete/GUID-reuse;
- 96-owner lifetime/effect stress;
- no duplicated mesh, effect, shadow, body, or script owner;
- arrow, bolt, and representative spell projectile connected route.
## J5.7 — combined cleanup and closeout
Delete:
- temporary App owner fields and construction fallbacks;
- App simulation component dictionaries;
- current-runtime adapters that reconstruct moved snapshots;
- reset/disposal branches replaced by Runtime;
- compatibility aliases after all consumers borrow Runtime.
Add:
- one J5 ownership ledger;
- failure injection at every construction, subscription, command, projection
acknowledgement, reset, and disposal boundary;
- graphical/direct normalized traces;
- Runtime-only movement/use/combat/cast/projectile fixture host;
- source/dependency guards against App/backend leakage and duplicate owners.
Run:
1. focused Core physics/selection/combat tests;
2. Runtime state/command/event/teardown tests;
3. App input/interaction/combat/magic/physics/projectile tests;
4. Release build and complete Release suite;
5. exact-binary lifecycle/reconnect route;
6. canonical nine-stop movement/combat/jump route;
7. connected interaction, casting, projectile, portal, and reconnect route;
8. user graphical feel gate for movement, facing, use, combat/cast bars, and
visible missiles;
9. architecture, divergence, issue, roadmap, AGENTS/CLAUDE, and durable-memory
reconciliation.
## Commit and rollback discipline
Each sub-slice lands as one independently reversible production commit followed
by a documentation/evidence checkpoint where needed.
Planned production commit sequence:
1. `refactor(runtime): own canonical action state`
(`b298f99f913249d299796e6a71f7a9b6b283ac1a`)
2. `refactor(runtime): own interaction transactions`
3. `refactor(runtime): own combat and magic intent`
4. `refactor(runtime): own local movement and outbound cadence`
5. `refactor(runtime): own per-session physics simulation`
6. `refactor(runtime): own projectile simulation`
7. `refactor(runtime): close simulation ownership`
Record each full SHA and exact `git revert <sha>` command in this file before
running its connected gate. Revert J5 groups in reverse order. Do not revert
J4 or the flat-collision Slice I cutover to mask a J5 ownership failure.
J5.1 rollback:
```text
git revert b298f99f913249d299796e6a71f7a9b6b283ac1a
```
J5.2 rollback:
```text
git revert f5f7b4177f449ebcad9724bfea263ef73ab60255
```
J5.3 rollback:
```text
git revert 20df9d155db50706a42420d60a9b15861cf4bfe7
```
J5.4 rollback:
```text
git revert aa3f4a60f87f2cbebc3d8ecd5e33d779b7fb13c1
```
## Acceptance
J5 is complete only when:
- every listed presentation-free owner is constructed by Runtime;
- App owns presentation only and borrows exact Runtime state;
- graphical and no-window commands produce the same ordered state and packets;
- collision and trajectory fixtures remain bit-identical;
- reset, reconnect, same-process multiple-instance, GUID reuse, and failure
injection converge every owner;
- no extra frame or per-frame allocation regression exists;
- complete Release and connected gates pass;
- the user accepts graphical movement, facing, interaction, combat/casting,
and projectile behavior;
- architecture, roadmap, milestones, issues/divergences, AGENTS/CLAUDE,
evidence, memory, and rollback instructions are synchronized.