acdream/docs/plans/2026-07-25-modern-runtime-slice-j3-projection-store.md
Erik d9bf4c4960 docs(runtime): close J3.3 and hand off J3.4
Record exact projection-store ownership, automated and connected evidence, rollback chain, and the executor-ready canonical object-table plan. Reconcile milestones, roadmap, architecture, divergence pointers, AGENTS/CLAUDE, and durable handoff state.

Co-authored-by: Codex <codex@openai.com>
2026-07-25 22:29:34 +02:00

180 lines
7.6 KiB
Markdown

# Modern runtime J3.3 — exact-key App projection store
**Status:** COMPLETE 2026-07-25
**Parent:** `2026-07-25-modern-runtime-slice-j3.md`
**Required base:** `f46ddb5cdb1e145752bea49aeb1d62bfe71284d3`
**Production commits:** `420e5eea70fd2c29cf9c8614e6298a1f84d64045`,
then exact-spatial correction
`e937cc36df39cf6ea1eaba2f9c0243d1929da702`
**Closeout:** `docs/research/2026-07-25-slice-j3-3-exact-projection-store.md`
## Objective
Make every materialized App-side live-object owner use the exact
`RuntimeEntityKey` (`Runtime local ID + INSTANCE_TS`) issued by
`RuntimeEntityDirectory`.
Runtime remains the only server-GUID authority. App may carry GUID as immutable
metadata for diagnostics and outbound commands, but no App dictionary may use
GUID to decide which incarnation is current.
No asynchronous projection queue, extra input frame, renderer behavior change,
or local-ID allocation-order change is permitted.
## Fixed model
There are three distinct states:
1. **Canonical-only registration** — Runtime accepted an incarnation, but no
graphical host has claimed a local ID. No materialized projection exists.
2. **Materialized projection** — Runtime has claimed the local ID and App owns
exactly one sidecar under the resulting `RuntimeEntityKey`.
3. **Retryable teardown** — Runtime retains the exact canonical tombstone while
App retains only the unfinished teardown suffix for that exact key. A
registration that failed before local-ID claim has no graphical tombstone.
A small synchronous construction context may carry a canonical record between
registration and materialization. It is not a retained App identity map.
## Execution
### 1. Introduce `LiveEntityProjectionStore`
- Store materialized sidecars in
`Dictionary<RuntimeEntityKey, LiveEntityRecord>`.
- Resolve GUID only by asking `RuntimeEntityDirectory` for the current
canonical record, reading its exact key, then querying the store.
- Reject key reuse, local-ID mismatch, incarnation mismatch, and stale
canonical records.
- Preserve insertion order and allocation-free borrowed enumeration.
- Retain teardown progress under the exact key; use canonical-reference storage
only for the exceptional pre-materialization registration rollback which has
no key.
### 2. Move sidecar creation to local-ID claim
- `RegisterLiveEntity` returns canonical registration facts without allocating
a graphical sidecar.
- `MaterializeLiveEntity` claims the Runtime local ID at the same point as
today, creates the exact-key sidecar, then calls the projection factory.
- Same-incarnation refresh before materialization mutates only Runtime state.
- Same-incarnation refresh after materialization resolves the existing sidecar
through its exact key.
- Factory, resource-registration, and rollback failures retain exactly the
currently unfinished ownership suffix.
### 3. Re-key every presentation workset
Convert the following from GUID/local-ID-only maps to exact-key maps:
- materialized and visible `WorldEntity` projections;
- animation and spatial-animation owners;
- remote-motion and spatial-remote-motion owners;
- projectile and spatial-projectile owners;
- ordinary root object workset;
- effect profile, visibility publication, hydration, and teardown lookups.
Local-ID-only iteration views validate the incarnation through the projection
store before yielding. No stale entry can match a replacement that reused the
same numeric local ID after wraparound.
### 4. Cut consumers over to borrowed queries
- Replace direct GUID dictionary access in selection, radar, combat targeting,
local-player animation/mode, teleport, physics update, diagnostics, and
composition with typed `TryGet...`, exact-key, or borrowed-enumeration
methods.
- Keep synchronous press-time reads; do not publish a copied frame snapshot.
- Preserve server GUID in yielded metadata where outbound commands need it.
- Remove `MaterializedWorldEntities`, `WorldEntities`, and component
dictionaries once all consumers use the focused queries.
### 5. Delete the J3.2 compatibility view
- Delete `ActiveRecordView`.
- Delete `_activeRecords` and every App GUID-keyed live-object/component map.
- Remove the detached `LiveEntityRecord(EntitySpawn)` fixture constructor;
component tests construct exact Runtime identities through a shared fixture.
- Add source guards rejecting:
- App `Dictionary<uint, LiveEntityRecord>`;
- App live-object/component maps keyed by server GUID;
- an App reverse GUID/local-ID map;
- a projection store key other than `RuntimeEntityKey`.
### 6. Failure and parity gate
Exercise:
- create without materialization;
- same-incarnation refresh before and after materialization;
- factory throw before sidecar publication;
- resource register failure with successful and failed rollback;
- loaded/pending rebucket and visibility reentrancy;
- delete/recreate with the same GUID;
- local-ID wraparound and stale-key rejection;
- parent/pickup/Hidden transitions;
- session clear during every projection callback;
- retryable teardown with a live replacement.
Run:
- focused Runtime and App identity/projection tests;
- all App tests;
- Release solution build;
- complete Release tests;
- exact-binary connected lifecycle/reconnect;
- render-scene identity/digest referee at every checkpoint.
## Acceptance
- Runtime owns the only GUID/incarnation/local-ID authority.
- Every materialized App owner is keyed by exact `RuntimeEntityKey`.
- App retains no GUID identity dictionary or reverse local-ID authority.
- A stale key cannot query, update, withdraw, or tear down a replacement.
- Local-ID allocation order is unchanged.
- No new allocation appears in steady-state live-object traversal.
- No callback is delayed to another frame.
- All automated and connected gates pass on the exact commit.
## Completion result
All acceptance conditions pass on final exact binary `e937cc36`.
- `LiveEntityProjectionStore` is the only materialized App sidecar store and is
keyed by exact `RuntimeEntityKey`.
- The temporary `ActiveRecordView`, `_activeRecords`, detached App record
constructor, and broad materialized/visible `WorldEntity` collection
surfaces are deleted. Borrowed exact-key record views remain for hot
traversal and tests.
- Hydration, animation, effects, lights, equipped children, remote teleport,
render journal, liveness, movement observations, teardown, spatial
residence, and visibility transitions carry the exact key.
- `GpuWorldState` retains the exact key through loaded/pending rebucketing,
landblock retirement, origin recentering, quiescence, and reentrant
visibility delivery. DAT-static entities remain outside live Runtime
identity.
- Runtime remains the only current-GUID/incarnation/local-ID authority. App
resolves GUID through Runtime and never decides which incarnation is current.
- Synchronous callbacks, allocation order, render ordering, and frame timing
are unchanged.
Evidence:
- 104 focused App ownership/streaming tests passed.
- 3,761 App tests passed / 3 skipped.
- 8,444 complete Release tests passed / 5 skipped.
- Release solution build passed.
- `logs/connected-world-gate-20260725-221008/report.json` passed on exact commit
`e937cc36`: two sessions, seven checkpoints, two graceful zero-code exits,
zero failures, zero render-shadow mismatches, and zero pending deltas.
Exact rollback, newest commit first:
```text
git revert e937cc36df39cf6ea1eaba2f9c0243d1929da702
git revert 420e5eea70fd2c29cf9c8614e6298a1f84d64045
```
J3.4 is the next clean slice. It moves canonical `ClientObjectTable` ownership
under the Runtime entity/object lifetime group without moving retained UI,
icons, paperdolls, grids, cooldown drawing, or interaction presentation.