acdream/docs/plans/2026-07-25-modern-runtime-slice-j3.md

323 lines
15 KiB
Markdown

# Modern runtime Slice J3 — canonical identity, properties, and object table
**Status:** COMPLETE 2026-07-26
**Parent:** `2026-07-25-modern-runtime-slice-j.md`, J3
**Production base:** `9496c01b`
**J2 production commit:** `75930787741db40a83eab8663e4464dce8d687ba`
## 0. Current checkpoint
| Slice | Status | Commit / evidence |
|---|---|---|
| J3.0 ownership inventory | complete | `b0fecc5f65ed26042c61a1651fb134aeb432c141`; `docs/research/2026-07-25-slice-j3-entity-ownership-inventory.md` |
| J3.1 accepted-wire owners | complete | `f7442d13e9ae7d5b077ffecb1f8a10899ad46edd`; 110 Runtime tests and complete Release parity remain green after J3.2 |
| J3.2 canonical Runtime entity directory | complete | `f46ddb5cdb1e145752bea49aeb1d62bfe71284d3`; 8,441 Release tests / 5 skips and `logs/connected-world-gate-20260725-200749/report.json` pass |
| J3.3 App projection store | complete | `420e5eea70fd2c29cf9c8614e6298a1f84d64045` + `e937cc36df39cf6ea1eaba2f9c0243d1929da702`; 8,444 Release tests / 5 skips and `logs/connected-world-gate-20260725-221008/report.json` pass |
| J3.4 canonical object-table ownership | complete | `5ef8b5371d8990f0380acd939e71cd711289d429`; 118 Runtime tests, 3,762 App tests / 3 skips, 8,453 complete Release tests / 5 skips, and `logs/connected-world-gate-20260726-055713/report.json` pass |
| J3.5 ordered deltas and borrowed views | complete | `ce3ac310d92722ffb637e81cb1957458874dd220`; 134 Runtime tests, 3,765 App tests / 3 skips, 8,472 complete Release tests / 5 skips, and `logs/connected-world-gate-20260726-064324/report.json` pass |
| J3.6 adversarial hardening and closeout | complete | `119b7c115107245546180b2f5cb3cb44c7d5476a`; 146 Runtime tests, 3,765 App tests / 3 skips, 8,484 complete Release tests / 5 skips, exact lifecycle/reconnect gate, and canonical nine-stop route pass |
J3.5 passes the Release solution build, 134 Runtime tests, 3,765 App tests with
three skips, and 8,472 complete tests with five expected skips. Its exact-
binary seven-checkpoint connected lifecycle/reconnect route also passes with
graceful exits, zero render-shadow mismatches, and zero pending deltas. Runtime
now issues canonical identity before graphical hydration, publishes entity and
inventory commits through one per-generation sequence, and exposes the same
direct borrowed views to graphical and no-window hosts. App no longer
reconstructs those views or events. No frame queue, backend dependency, or
gameplay behavior change was added. The exact rollback for J3.5 is:
```text
git revert ce3ac310d92722ffb637e81cb1957458874dd220
```
J3.6 closes the group under callback failure, re-entrancy, retained teardown,
reset, GUID reuse, and direct disposal. Its complete owner ledger converges to
zero and both exact-binary connected routes pass. Evidence:
[`../research/2026-07-26-slice-j3-6-lifetime-closeout.md`](../research/2026-07-26-slice-j3-6-lifetime-closeout.md).
The exact rollback for J3.6 is:
```text
git revert 119b7c115107245546180b2f5cb3cb44c7d5476a
```
## 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
**Detailed execution plan:**
[`2026-07-25-modern-runtime-slice-j3-object-table.md`](2026-07-25-modern-runtime-slice-j3-object-table.md).
- 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
**Detailed execution plan:**
[`2026-07-26-modern-runtime-slice-j3-delta-stream.md`](2026-07-26-modern-runtime-slice-j3-delta-stream.md).
- 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.
J3 sub-slices are independently reversible:
```text
git revert ce3ac310d92722ffb637e81cb1957458874dd220
git revert 5ef8b5371d8990f0380acd939e71cd711289d429
git revert e937cc36df39cf6ea1eaba2f9c0243d1929da702
git revert 420e5eea70fd2c29cf9c8614e6298a1f84d64045
git revert f46ddb5cdb1e145752bea49aeb1d62bfe71284d3
git revert f7442d13e9ae7d5b077ffecb1f8a10899ad46edd
```
Revert J3.6 before J3.5. Revert J3.5 before J3.4. Revert J3.4 before J3.3.
Revert J3.3's exact-spatial
correction before its main projection-store commit. Revert J3.3 before J3.2,
and J3.2 before J3.1, when rolling back more than one sub-slice.