acdream/docs/research/2026-07-25-slice-j3-entity-ownership-inventory.md
Erik e18df84437 docs(runtime): close J3.2 canonical identity gate
Record the exact f46ddb5c rollback, 8,441-test Release gate, and seven-checkpoint connected lifecycle/reconnect pass. Update the canonical project state and pin J3.3's exact-key App projection-store execution plan.

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

122 lines
6.2 KiB
Markdown

# Slice J3 entity ownership inventory
## Baseline
Production base: `9496c01b`.
The accepted J2 binary passes 8,428 Release tests with five skips and the
seven-checkpoint connected lifecycle/reconnect gate at
`logs/connected-world-gate-20260725-193936/report.json`.
## J3.2 ownership checkpoint
Commit `f46ddb5cdb1e145752bea49aeb1d62bfe71284d3` implements the first
canonical split:
- `RuntimeEntityDirectory` owns the only active GUID map, exact-incarnation
tombstones, reverse local-ID map, session lifetime epoch, per-GUID operation
versions, accepted inbound snapshot owner, and parent-relation owner;
- `RuntimeEntityRecord` owns the presentation-free canonical snapshot,
`INSTANCE_TS`, authoritative cell/state/timestamp versions, object clock,
PhysicsBody/physics-host facts carried for J5, and Runtime-issued local ID;
- App's `LiveEntityRecord` is now a projection sidecar around that canonical
record;
- the temporary `ActiveRecordView` is dictionary-shaped only to preserve the
large synchronous App call surface during J3.2. It stores no GUID map and
resolves every lookup through `RuntimeEntityDirectory`; J3.3 deletes it;
- Runtime-only ownership/lifetime tests and App source guards protect the
boundary.
The checkpoint passes 110 Runtime tests, 3,758 App tests with three skips, and
8,441 complete Release tests with five skips. Its exact-binary connected gate
also passes all seven checkpoints with graceful exits, zero render-shadow
mismatches, and zero pending deltas:
`logs/connected-world-gate-20260725-200749/report.json`.
At this baseline:
- `LiveEntityRuntime.cs` is 2,866 lines and is referenced by roughly 100 App
source/test files;
- it owns both canonical GUID/incarnation/timestamp state and graphical
projection/component state;
- `InboundPhysicsStateController` and `ParentAttachmentState` are already
presentation-free but still reside in App;
- `ClientObjectTable` is a presentation-free Core type, but its production
instance is publicly owned by `GameWindow`;
- the retained render scene is a derived projection and is not a second
gameplay/GUID authority.
## Existing retail oracle
J3 changes ownership, not behavior. It preserves the already cited ports:
- `CObjectMaint::CreateObject`
- `CObjectMaint::DeleteObject @ 0x00508460`
- `CPhysicsObj::set_description @ 0x00514F40`
- `CPhysicsObj::change_cell @ 0x00513390`
- `CPhysicsObj::exit_world @ 0x00514E60`
- `ACCWeenieObject::ServerSaysMoveItem @ 0x0058DBB0`
- the SmartBox CreateObject/event flow in
`docs/research/2026-07-13-retail-projectile-vfx-pseudocode.md`
No new AC algorithm or constant is introduced. Any later behavioral question
returns to named retail before implementation.
## Field ownership
| State | J3 owner | Notes |
|---|---|---|
| Server GUID and `INSTANCE_TS` | Runtime | One current incarnation only |
| Runtime local identity and reverse lookup | Runtime | Issued by Runtime; never inferred by App |
| Latest accepted immutable spawn | Runtime | Includes accepted raw properties and timestamps |
| Position/state/vector/movement/object-description authority versions | Runtime | Reentrant operation validation |
| Full cell and canonical landblock | Runtime | Authoritative object placement, not streaming residency |
| Raw/final physics state and object clock | Runtime | Existing behavior; later physics relocation is J5 |
| Parent candidates and accepted parent relation | Runtime | Exact arrival and generation order |
| Session lifetime version, GUID operation versions, tombstones | Runtime | Retryable replacement/delete/clear |
| `ClientObjectTable` and placement/container indices | Runtime | Existing Core type, same instance |
| `WorldEntity` and mesh/resource registration | App projection | Keyed by local identity + incarnation |
| Loaded/pending bucket and derived visibility | App projection | Streaming fact, not object identity |
| Animation/effect/light/projectile presentation | App projection | No references from Runtime |
| Hydration/recovery/appearance synchronization flags | App projection | Retryable graphical transaction |
| Selection geometry, radar and paperdoll | App projection | Borrow canonical object facts |
`HasPartArray`, `PhysicsBody`, and movement-manager/physics-host fields are
presentation-independent simulation facts. J3 must not push them into App just
to simplify the split. Their behavior and final lifetime-group relocation are
handled in J5.
## Current mixed-owner hazards
1. Local IDs are currently reserved when App materializes a `WorldEntity`.
Runtime must own the allocator while preserving that graphical allocation
order until parity is proven.
2. Logical tombstones currently retain App teardown plans on
`LiveEntityRecord`. J3 replaces this with a typed, exact, retryable
projection acknowledgement.
3. Active animation/remote/projectile worksets currently live beside the GUID
map. They move intact to the App projection store.
4. `GpuWorldState` and several presentation controllers accept server GUID as
their primary key. They must consume Runtime local identity plus incarnation
and treat GUID only as immutable payload metadata.
5. `GameWindow.Objects` makes the graphical shell appear to own the canonical
object table. J3 replaces it with a Runtime lifetime-group owner borrowed by
UI and presentation composition.
## Do not retry
| Dead direction | Why |
|---|---|
| Copy the GUID map into Runtime while keeping App's map | Creates two worlds and ambiguous teardown |
| Let App allocate an independent local ID | Breaks cross-host identity and stale-incarnation rejection |
| Put `WorldEntity` or App component interfaces in Runtime | Makes headless a hidden graphical host |
| Deliver projection updates through a later-frame queue | Changes accepted presentation and input timing |
| Move vitals/spells/combat opportunistically in J3 | Splits the J4/J5 lifetime groups |
| Re-key everything by GUID and call it a projection cache | Leaves App as a second identity authority |
## J3.1 first move
`InboundPhysicsStateController`, `ParentAttachmentState`, their immutable
result types, and dedicated tests move into `AcDream.Runtime.Entities`
unchanged. App temporarily composes these Runtime owners until the canonical
directory and projection store cut over in later J3 sub-slices.