docs(runtime): pin J3 entity ownership migration

Reconcile J3 with later gameplay lifetime groups, inventory the current mixed entity/object ownership, and define the staged canonical identity, projection, object-table, delta, teardown, and no-window gates.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-25 19:51:50 +02:00
parent 9496c01be1
commit b0fecc5f65
3 changed files with 365 additions and 0 deletions

View file

@ -179,6 +179,9 @@ git revert 75930787741db40a83eab8663e4464dce8d687ba
### J3 — canonical identity, properties, and object-table group
**Detailed execution plan:**
[`2026-07-25-modern-runtime-slice-j3.md`](2026-07-25-modern-runtime-slice-j3.md).
- Strip renderer, particle, Wb, and streaming components from the canonical
record into an App projection store keyed only by local identity/incarnation.
- Move `LiveEntityRuntime`, accepted spawn/state/property timestamps,

View file

@ -0,0 +1,265 @@
# Modern runtime Slice J3 — canonical identity, properties, and object table
**Status:** ACTIVE
**Parent:** `2026-07-25-modern-runtime-slice-j.md`, J3
**Production base:** `9496c01b`
**J2 production commit:** `75930787741db40a83eab8663e4464dce8d687ba`
## 1. Objective
Move the one canonical server-object identity/incarnation owner, accepted
CreateObject/property/timestamp state, parent relation state, and
`ClientObjectTable` lifetime into `AcDream.Runtime`.
App becomes a projection host. Its world entity, animation, effect, light,
selection, paperdoll, spatial bucket, and hydration state is keyed by a
Runtime-issued local identity plus exact incarnation. App must not retain a
second server-GUID map or decide whether a packet belongs to the current
incarnation.
This is a structural move. Existing named-retail CreateObject, timestamp,
parenting, pickup, Hidden, delete, and generation-replacement behavior remains
unchanged. No renderer, particle, streaming, GL, or retained-UI type may enter
Runtime.
## 2. Scope reconciliation
The umbrella J3 text overlaps later lifetime groups. This detailed plan is the
authoritative split:
- J3 moves raw accepted entity identity, immutable spawn/property snapshots,
timestamp gates, parent relations, and the canonical client object/container
table.
- J4 moves higher-level inventory transactions, vitals, enchantments,
spell/component state, cooldown services, chat, and their ViewModel-facing
revisions.
- J5 moves movement/physics/interaction/combat authority.
J3 may retain existing Core physics references already stored on the entity
record while separating presentation, but it does not redesign or relocate
their behavior. That coherent move remains J5.
## 3. Fixed ownership after J3
`AcDream.Runtime` owns:
- server GUID to current incarnation;
- exact Runtime local identity allocation and reverse lookup;
- accepted `INSTANCE_TS` and every retail packet-channel timestamp;
- the latest accepted immutable `WorldSession.EntitySpawn`;
- logical create, same-incarnation refresh, pickup, parent, Hidden/state,
delete, generation replacement, tombstone, and session-clear state;
- unresolved/staged/committed parent relations;
- `ClientObjectTable`, containers, placement indices, pending authoritative
property state, and generation-aware removal;
- ordered immutable entity/object deltas;
- retryable logical teardown state and the acknowledgement from an attached
projection host.
`AcDream.App` owns:
- `WorldEntity` and render-scene projection;
- loaded/pending spatial buckets and visibility derived from streaming;
- animation, remote-motion presentation, projectile presentation, effects,
lights, selection geometry, radar presentation, and private paperdolls;
- projection hydration/recovery transaction state;
- render/resource registration and its exact retryable teardown suffix.
App projection keys are:
```text
RuntimeLocalEntityId + INSTANCE_TS
```
Server GUID may be carried as immutable metadata for diagnostics and outbound
commands, but it is not an App lookup authority.
## 4. Runtime contracts
Introduce or finish contracts equivalent to:
```csharp
public readonly record struct RuntimeEntityKey(
uint LocalEntityId,
ushort Incarnation);
public readonly record struct RuntimeEntityDelta(
ulong Sequence,
RuntimeGenerationToken SessionGeneration,
RuntimeEntityKey Entity,
RuntimeEntityDeltaKind Kind,
RuntimeEntitySnapshot Snapshot);
public interface IRuntimeEntityProjectionHost
{
RuntimeProjectionAcknowledgement Register(RuntimeEntitySnapshot entity);
RuntimeProjectionAcknowledgement Update(RuntimeEntityDelta delta);
RuntimeProjectionAcknowledgement Withdraw(RuntimeEntityKey entity);
RuntimeProjectionAcknowledgement TearDown(RuntimeEntityKey entity);
}
```
The concrete names may follow existing project vocabulary, but these
invariants are mandatory:
- Runtime issues identity before App creates a projection.
- Every App callback carries the exact local identity and incarnation.
- Callback acknowledgement is exact and retryable.
- Completed teardown work never replays.
- App cannot query or mutate Runtime by a stale local identity/incarnation.
- Runtime emits deltas only after canonical state commits.
- Callback reentrancy may supersede the outer operation; the outer operation
must revalidate generation/incarnation/operation version before continuing.
## 5. Execution slices
### J3.0 — oracle and ownership inventory
- Pin the current field/method ownership table for `LiveEntityRecord`,
`LiveEntityRuntime`, `InboundPhysicsStateController`,
`ParentAttachmentState`, `ClientObjectTable`, `GpuWorldState`, hydration,
and teardown owners.
- Reuse the existing retail pseudocode and citations; no behavior is being
invented. Add research only where a current branch lacks a cited oracle.
- Capture normalized existing traces for create, same-generation refresh,
parent/unparent, pickup, Hidden, delete/recreate, GUID reuse, container
placement, and session clear.
- Record baseline render-scene identity/digest at deterministic fixtures.
### J3.1 — move narrow accepted-wire owners
- Move `InboundPhysicsStateController`, `ParentAttachmentState`, their result
types, and their complete tests into Runtime.
- Preserve timestamp cursor/order behavior and parent candidate ordering
line-for-line.
- App's existing `LiveEntityRuntime` temporarily composes those Runtime owners;
no second state is introduced.
- Add Runtime dependency/load guards around the moved types.
Gate: all timestamp, malformed, wraparound, parent-generation, and packet-order
tests pass in Runtime; App behavior and complete suite remain unchanged.
### J3.2 — canonical Runtime entity directory
- Extract current GUID/incarnation maps, accepted snapshot state, session
lifetime version, operation versions, tombstones, delete/generation
replacement, and local-ID allocation into one Runtime owner.
- Split `LiveEntityRecord` into canonical Runtime state and an App projection
sidecar. Canonical fields never reference App interfaces or `WorldEntity`.
- Preserve current local-ID allocation order during graphical hydration for
parity; Runtime owns the allocator and claim, while a no-window host may
claim immediately.
- Retain exact reentrant supersession and retryable tombstone behavior.
- Keep physics/movement fields structurally in place where required for J5,
but remove every renderer/effect/hydration reference from the canonical
record.
Gate: the complete existing `LiveEntityRuntimeTests` identity/timestamp/
teardown subset moves to Runtime and produces the same normalized trace.
### J3.3 — App projection store and cutover
- Add one App projection store keyed only by Runtime local identity plus
incarnation.
- Move `WorldEntity`, spatial visibility, hydration/recovery flags, animation,
remote-motion presentation, projectile presentation, effect profiles,
resource flags, and active presentation worksets into that store.
- Convert `GpuWorldState`, hydration, equipped children, render journal,
animation/effect/light owners, selection/radar queries, and teardown to the
exact projection key.
- Replace App's mixed `LiveEntityRuntime` facade with focused Runtime directory
and App projection-store dependencies; delete its GUID maps and mixed record.
- Preserve current register-once, rebucket-only, withdraw-without-destroy,
Hidden, and retryable logical teardown order.
Gate: projection identity/digest and all existing hydration, rebucket,
visibility, effect, animation, projectile, selection, and teardown tests match.
Source guards reject any App server-GUID authority map.
### J3.4 — canonical object-table ownership
- Add a Runtime entity/object lifetime-group root that owns the canonical
entity directory and the existing Core `ClientObjectTable`.
- Construct it before either graphical UI or live presentation; both borrow
the same instances.
- Remove the public `ClientObjectTable` owner field from `GameWindow`.
- Route J2 inbound object/property/container updates directly to the Runtime
group.
- Keep UI controllers, item icons, paperdoll, grids, cooldown drawing, and
interaction presentation as App borrowers.
- Preserve synchronous press-time reads and current event ordering; add no
queue or copied inventory model.
Gate: object add/update/remove, placement, container replacement, optimistic
move rollback, stack response, GUID reuse, and session-clear traces match.
### J3.5 — ordered deltas and borrowed views
- Publish one monotonic per-session Runtime entity/object delta stream.
- Make J1 `IGameRuntimeView.Entities` and inventory snapshots read the Runtime
owners directly rather than App adapters.
- Feed App projection mutation from the same committed deltas/acknowledgements;
do not create a second queue or frame delay.
- Remove superseded App entity/object event mirroring and source adapters.
- Assert same-thread graphical input and inbound presentation remain
synchronous.
Gate: direct-host and graphical-host normalized traces are identical, including
sequence, generation, identity, properties, placement, and teardown edges.
### J3.6 — hardening and closeout
- Failure-inject every projection registration/update/withdraw/teardown stage.
- Exercise callback reentrancy, duplicate CreateObject, stale/equal/wrapped
timestamps, delete/recreate with the same GUID, pending-to-loaded movement,
parent events before either object, malformed property packets, and session
reset during callbacks.
- Prove zero leaked canonical records, tombstones, App projections, resources,
container entries, parent candidates, queued deltas, or subscriptions.
- Add a Runtime-only entity/object fixture that performs create, property
updates, parent/container moves, Hidden, delete/recreate, clear, and teardown
without loading presentation/backend assemblies.
- Run Release build, focused suites, complete tests, exact-binary connected
lifecycle/reconnect, and the canonical world route.
- Because J3 changes projection identity plumbing, run the existing automated
render digest/referee at every checkpoint. Pause for user visual verification
only if the referee or connected client exposes a pixel/interaction symptom.
## 6. Commit order
1. `refactor(runtime): move accepted entity wire state`
2. `refactor(runtime): own canonical entity identity and incarnations`
3. `refactor(app): key live projections by runtime identity`
4. `refactor(runtime): own canonical object table`
5. `feat(runtime): publish ordered entity and object deltas`
6. `test(runtime): close J3 entity ownership parity`
Each commit is independently buildable and bisectable. The exact rollback for
each lands in this document before that commit's connected or visual gate.
## 7. Acceptance
J3 is complete only when:
- Runtime owns the only server-GUID/incarnation map and object table;
- App projections are keyed by local identity plus incarnation;
- Runtime has no App/UI/backend dependency;
- App has no authoritative GUID map or accepted timestamp gate;
- no mirrored collection, asynchronous seam, or added input frame exists;
- normalized direct/graphical traces match;
- deterministic render identity/digests match;
- Runtime-only no-window entity/object lifecycle passes;
- Release build and complete tests pass;
- exact-binary connected login/travel/logout/reconnect passes gracefully;
- every teardown owner converges to zero.
## 8. Current rollback chain
```text
git revert 75930787741db40a83eab8663e4464dce8d687ba
git revert 854d9e9cd13092bd5aaa3cf025d73eeb4600e9f8
git revert b632672e5ccabfb44c551e08f1c411ab2669c44a
```
These are J2, J1, and J0 respectively. Do not use them for a J3 sub-slice
failure; record and revert only the exact failing J3 commit.