acdream/docs/research/2026-07-25-slice-j3-entity-ownership-inventory.md
Erik b0fecc5f65 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>
2026-07-25 19:51:50 +02:00

97 lines
4.9 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`.
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.