feat(runtime): publish dormant local physics ownership

This commit is contained in:
Erik 2026-08-01 10:01:30 +02:00
parent 442cb8f97b
commit 22651c823d
10 changed files with 1617 additions and 25 deletions

View file

@ -0,0 +1,126 @@
# Runtime local-player physics publication - 2026-08-01
## Scope
This is placement Slice 4B2 checkpoint 4. It adds the dormant,
presentation-independent transaction which prepares and assigns ownership of
one local-player `PhysicsBody` and `PlayerMovementController`. No App or
Headless production route invokes this transaction, so graphical and no-window
game behavior is unchanged and AP-1/AD-1 remain open.
The checkpoint deliberately stops before canonical SetPosition activation.
It does not consume the prepared placement operation, enter the body into the
physics engine, publish FullCell/world/host/shadow/workset state, or project a
presentation entity. Those effects belong to the next transaction and must all
use the same Runtime-owned dormant body.
## Ownership contract
`RuntimeLocalPlayerPhysicsPublicationState` is the sole owner of unpublished
local-player body/controller candidates. Each candidate is bound to a token
containing:
- The exact `RuntimeEntityKey` and authored SetPosition placement token.
- A monotonic publication ID.
- The nonzero canonical local-player server GUID and exact identity revision.
- The record's physics-body and object-clock ownership epochs.
- The movement state's controller ownership epoch.
- The entity directory's session-lifetime authority.
Preparation constructs a private controller, body, and object clock. It applies
the exact authored cell frame, orientation, Setup sphere list, scale, step
heights, and accepted final physics state without mutating the canonical entity,
shared object clock, engine/worksets, shadow registry, FullCell, host state, or
presentation. The candidate remains explicitly out of world and inactive. No
method exposes its controller, body, clock, or another mutable reference while
it is owned by the publication transaction.
This checkpoint accepts only a pristine initial graph: no canonical body,
movement controller, physics host, remote motion, projectile, acquisition or
binding operation, or remote-placement contract may exist. It cannot replace or
upgrade a live graph. The local-player identity must be live, nonzero, and name
the same server GUID as the exact entity incarnation.
Unpublished candidates and ownership-committed dormant controllers reject live
movement operations: update, public SetPosition, blip, outbound-position
capture, movement/position send tracking, and shared-engine position commit.
Only the subsequent activation transaction may promote `RuntimeOwnedDormant`
to `RuntimePublished`; this checkpoint never invokes that transition. Once a
Runtime-owned dormant or published controller is replaced, reset, or disposed,
its terminal retirement state rejects the same operations plus
body/configuration mutation and manager acquisition. Publicly constructed
legacy controllers keep their existing standalone behavior.
## Failure-atomic commit
Commit revalidates every authority after preparation:
- The entity record is the current incarnation and is not accepted for delete.
- The local-player identity still has the token's exact GUID and revision and
has not been disposed.
- The exact authored SetPosition operation and sealed command remain current.
- Session, body, object-clock, and controller ownership epochs still match.
- The body/controller/host/remote/projectile graph remains completely pristine,
with no acquisition, binding, or remote-placement operation in progress.
Only after validation completes does the callback-free update-thread tail:
1. Rebind the candidate controller from its private clock to the record's exact
canonical object clock and mark it Runtime-owned but dormant.
2. Store the candidate's exact body on the canonical record, advancing the
physics ownership epoch once.
3. Store the same controller in `RuntimeLocalPlayerMovementState`, advancing the
controller ownership epoch once.
The dormant controller rejects every live/configuration operation after these
stores; ownership commit alone cannot tick physics, mutate the canonical clock,
or publish an outbound frame. These stores allocate no new gameplay owner,
invoke no host or presentation callback, and cannot replay an older
incarnation. Replacing SetPosition,
changing any accepted physics authority, binding remote/projectile state,
replacing body/clock/controller ownership, delete plus GUID reuse, reset, or
disposal causes the token to reject. An identity switch away and back also
rejects because its revision changed. A rejected or superseded candidate is
discarded and cannot perform a later live operation. Reset and disposal converge
the publication ledger to zero candidates.
Repeated stores of the same body/controller do not advance their epochs; real
bind, replacement, and unbind edges do. This makes ABA-shaped reference changes
observable even if a later value happens to equal an earlier reference.
## Gates
- Candidate privacy and live-operation rejection.
- Pristine-only admission for body, controller, host, remote/projectile,
acquisition/binding, and remote-placement ownership.
- Exact local-player identity, identity-switch, and disposed-identity rejection.
- Exact same-body ownership in entity record and dormant movement controller.
- Dormant rejection after ownership commit plus the isolated controller-level
`dormant -> activated -> live` lifecycle contract for the next checkpoint.
- No mutation of SetPosition, FullCell, spatial roots, host projections,
shadows, worksets, world residence, or presentation during this checkpoint.
- Replacement by position, vector, final physics state, object description,
CreateObject, remote/projectile/body/clock/controller ownership, and explicit
placement cancellation.
- Delete plus same-GUID reincarnation.
- Candidate replacement, reset, disposal, and ownership convergence.
- Terminal stale-controller rejection after replacement, reset, and disposal.
- Body/controller epochs advance only on actual ownership changes.
Focused publication, controller, movement, and SetPosition tests pass 167/167.
The complete Runtime project passes 627/627 under invariant culture. The App
Runtime-ownership guard passes 4/4, the complete Release solution builds with
zero errors, and the complete Release solution test gate passes 10,374 tests
with 4 intentional skips. Under the machine's Swedish current culture, the
three previously known formatting assertions still fail (`0,5` versus `0.5`
and localized sky text); they are unrelated to this checkpoint.
## Next checkpoint
Add the canonical Runtime SetPosition activation transaction. It must evaluate
and commit the already-owned dormant body, consume the exact prepared placement,
and atomically establish physics-engine/workset/shadow/FullCell/world/host
ownership before presentation receives an acknowledgement, then invoke the sole
`ActivateRuntimePublication` transition. The activation must
roll back or leave the operation retryable on every pre-commit failure and must
not construct a second body or controller.