497 lines
20 KiB
Markdown
497 lines
20 KiB
Markdown
# Remaining physics-divergence campaign handoff — 2026-07-31
|
|
|
|
> **Checkpoint 2 update:** Slice 4B2 prerequisite A, Runtime SetPosition
|
|
> collision-report ownership, is implemented in the next checkpoint. Continue
|
|
> with the dedicated
|
|
> [`runtime SetPosition collision-reporting handoff`](2026-07-31-runtime-set-position-collision-reporting-handoff.md),
|
|
> not the prerequisite-A instructions preserved below as historical context.
|
|
|
|
## Purpose and stopping point
|
|
|
|
This is the deliberate handoff boundary requested after placement Slice 4B2
|
|
checkpoint 1. The repository is stopped before any production graphical or
|
|
headless route submits to the canonical Runtime SetPosition owner.
|
|
|
|
The completed foundation is useful and tested, but the overall campaign is
|
|
**not complete**. AP-1 and AD-1 remain narrowed/open. AP-22 and AD-10 remain
|
|
open. Do not retire those rows until their exact automated and connected gates
|
|
pass.
|
|
|
|
### Exact workspace
|
|
|
|
- Worktree: `C:\Users\erikn\.codex\worktrees\af5e\acdream`
|
|
- Branch: `codex/port-claude-agents`
|
|
- Handoff code checkpoint: `270f5154`
|
|
(`feat(runtime): expose dormant placement receipts`)
|
|
- Immediately preceding residence-owner checkpoint: `4c02ac42`
|
|
(`feat(runtime): own deferred set-position residence`)
|
|
- Pure Core SetPosition checkpoint: `e84a388e`
|
|
(`feat(physics): port canonical retail set-position core`)
|
|
- No upstream is configured for this worktree branch.
|
|
- Remotes:
|
|
- `origin`: `https://git.snakedesert.se/erik/acdream.git`
|
|
- `github`: `git@github.com:eriknihlen/acdream.git`
|
|
|
|
The handoff was written in this same worktree. The next agent should continue
|
|
there rather than creating a different worktree unless the user explicitly
|
|
requests it.
|
|
|
|
## Worktree hygiene
|
|
|
|
The worktree intentionally reports unrelated modifications. Preserve them.
|
|
Never use `git add -A`, `git reset --hard`, or checkout/revert commands against
|
|
these paths.
|
|
|
|
At the checkpoint, `AGENTS.md` has a real unrelated content diff. The following
|
|
paths report modified due to existing line-ending/stat noise but have no
|
|
content diff against the index:
|
|
|
|
- `src/AcDream.App/Input/PlayerModeController.cs`
|
|
- `src/AcDream.App/Interaction/PlayerInteractionMovementSink.cs`
|
|
- `src/AcDream.App/Rendering/LiveAnimationPresentationContext.cs`
|
|
- `src/AcDream.App/World/LiveEntityRuntime.cs`
|
|
- `src/AcDream.Core/Physics/CellArray.cs`
|
|
- `src/AcDream.Core/Physics/PhysicsBody.cs`
|
|
- `src/AcDream.Headless/Hosting/HeadlessSessionWorldProjection.cs`
|
|
- `src/AcDream.Runtime/Gameplay/PlayerMovementController.cs`
|
|
- `src/AcDream.Runtime/Physics/RuntimePhysicsState.cs`
|
|
- `src/AcDream.Runtime/Physics/RuntimeRemotePhysicsUpdater.cs`
|
|
- `tests/AcDream.App.Tests/World/LiveEntityRuntimeTests.cs`
|
|
- `tests/AcDream.Core.Tests/Physics/CellTransitTests.cs`
|
|
- `tests/AcDream.Core.Tests/Physics/Issue133DungeonTeleportPrefixTests.cs`
|
|
- `tests/AcDream.Runtime.Tests/Gameplay/PlayerMovementControllerTests.cs`
|
|
- `tools/A8CellAudit/A8CellAudit.csproj`
|
|
|
|
Before every commit, stage exact paths and inspect:
|
|
|
|
```powershell
|
|
git diff --check
|
|
git diff --cached --check
|
|
git diff --cached --stat
|
|
git status --short
|
|
```
|
|
|
|
## What is complete
|
|
|
|
### Campaign baseline and issue #273
|
|
|
|
- `c24bc571` — retail StepDown support-radius behavior for tight gaps.
|
|
- `10b55d74` — tight-gap controls and diagnostics.
|
|
|
|
### Retail retry and edge/StepDown dispatcher
|
|
|
|
- `e5f855ac` — nested per-cell collision retries.
|
|
- `67d1e9b3` — refreshed-cell retry state.
|
|
- `4ca7230b` — retained cell across inner retries.
|
|
- `c559c48d` — retail edge-response ordering.
|
|
- `4fbd93ec` — edge-slide stop semantics.
|
|
- `1fd5da67` — StepDown placement validation.
|
|
- `acec33ec` — StepDown probe state.
|
|
- `75b6f6b6` — Path-6 collision response.
|
|
- `d3c0d9ec` — TS-4 production chronology gate.
|
|
|
|
These retire AP-3, AP-4, AP-5, AD-53, AD-54, and TS-4 under the tests and
|
|
research already recorded in the divergence register.
|
|
|
|
### Exact cell availability and atomic collision generations
|
|
|
|
- `7716c2ee` — retail cell-availability semantics.
|
|
- `3e0f3b62` — containment-root validation.
|
|
- `be94bc9b` — atomic collision-generation activation.
|
|
- `d94145e6` — seal before activation.
|
|
- `6b28ff99` — starvation-free activation.
|
|
|
|
These retire AD-3, AD-4, and AD-6. The active collision world remains visible
|
|
until a complete replacement generation is atomically committed.
|
|
|
|
### Canonical SetPosition Core and Runtime residence owner
|
|
|
|
- `e84a388e` ports the pure Core SetPosition transaction.
|
|
- `4c02ac42` adds `RuntimeSetPositionState`, including:
|
|
- exact accepted operation ownership;
|
|
- canonical body/contact/cell/shadow/workset commit;
|
|
- authored mover retention;
|
|
- exact-cell and collision-generation wake;
|
|
- 25-second root/direct-child lost-cell lifetime;
|
|
- bounded indexed deadline structures;
|
|
- revisioned ordered Withdraw/Place/Discard host receipts;
|
|
- cancellation/GUID-reuse/reset/disposal convergence;
|
|
- structural cell/quaternion validation and bounded scatter work.
|
|
- `270f5154` adds `RuntimePlacementProjectionChannel`, a public,
|
|
generation-gated host seam over the one existing receipt owner:
|
|
- subscribe to ordered immutable receipts;
|
|
- peek the exact FIFO head;
|
|
- retry pending receipts without recommitting Runtime state;
|
|
- acknowledge only the exact current FIFO-head token;
|
|
- observe pending receipt debt.
|
|
|
|
The channel owns no second queue and has no App or Headless production
|
|
consumer. A source guard pins that dormancy. This is intentional.
|
|
|
|
### Validation at the stopping point
|
|
|
|
The final channel-only checkpoint passed:
|
|
|
|
- Release solution build: 0 errors, 18 existing warnings.
|
|
- Complete Release suite: 10,279 passed, 4 skipped, 0 failed.
|
|
- Runtime SetPosition focused tests: 47/47.
|
|
- App dormancy/ownership guards: 3/3.
|
|
- `git diff --check`: clean.
|
|
- Retail-conformance re-review: clean.
|
|
- Architecture/adversarial re-review: clean.
|
|
|
|
## Rejected prototype — do not resurrect it
|
|
|
|
A prototype made graphical and headless `PlayerMovementController` instances
|
|
borrow the canonical `RuntimeEntityRecord.PhysicsBody` immediately and used a
|
|
snapshot/rollback lease to recover from late construction failures. It was
|
|
fully removed before `270f5154`.
|
|
|
|
The design was rejected because it was failure-atomic only without
|
|
reentrancy. While the lease was open, a nested SetPosition, remote/projectile
|
|
bind or update, deletion/GUID replacement, object-clock epoch change, or
|
|
disposal could establish newer authority. The outer rollback could then erase
|
|
that newer commit or detach a body already used by another canonical owner.
|
|
|
|
The next implementation must use one of these complete solutions:
|
|
|
|
1. A Runtime-owned exclusive/versioned controller/body publication
|
|
transaction respected by **every** canonical body writer, binding path,
|
|
SetPosition operation, clock epoch transition, deletion, reset, and
|
|
disposal; or
|
|
2. Off-canonical preparation followed by one validated atomic Runtime commit
|
|
that publishes the prepared controller/body relationship without copying
|
|
stale state over newer authority.
|
|
|
|
Because every writer must participate, this belongs to the atomic production
|
|
route cutover. Do not reintroduce a local snapshot lease or a Commit method
|
|
that merely checks the body reference at the end.
|
|
|
|
## What remains — required execution order
|
|
|
|
### Slice 4B2 prerequisite A — real collision-report ownership
|
|
|
|
`RuntimePhysicsState.HandleSetPositionCollisions` still returns `false`.
|
|
Retail `CPhysicsObj::SetPositionInternal` (`0x00515330`) returns the real
|
|
per-object report/tracking result. Establish the Runtime owner for that result
|
|
and return it exactly. Do not restore the former environment/object-presence
|
|
guess.
|
|
|
|
Required tests:
|
|
|
|
- report/no-report objects;
|
|
- collided object set ordering and lifetime;
|
|
- reentrant deletion/reset;
|
|
- graphical/headless equality;
|
|
- no report state surviving GUID reuse.
|
|
|
|
### Slice 4B2 prerequisite B — exact authored mover preparation
|
|
|
|
Every production preparation must pass the full SetPosition request using:
|
|
|
|
- Setup's exact ordered authored spheres;
|
|
- exact scale, including valid zero/presence semantics;
|
|
- exact StepUp and StepDown heights;
|
|
- exact flags;
|
|
- exact cell-local frame and orientation;
|
|
- current position/vector/state authority versions.
|
|
|
|
Do not reconstruct a cylinder from visual radius/height, clamp a positive
|
|
scale, use the projectile mover as a generic object fallback, or pre-mutate
|
|
`FullCellId`, `PhysicsBody`, `WorldEntity`, App buckets, or shadows.
|
|
|
|
### Slice 4B2 prerequisite C — atomic local controller/body publication
|
|
|
|
Implement the complete transaction described in the rejected-prototype note.
|
|
Graphical and no-window controllers must end with the exact same Runtime body,
|
|
but construction cannot expose or mutate canonical state before the validated
|
|
atomic commit.
|
|
|
|
Adversarial gates must include:
|
|
|
|
- nested construction;
|
|
- reentrant SetPosition;
|
|
- remote and projectile binding/update;
|
|
- deletion and same-GUID new incarnation;
|
|
- projection-owner replacement;
|
|
- object-clock epoch change;
|
|
- reset and disposal;
|
|
- commit and rollback after replacement;
|
|
- late graphical camera/shadow/host failure;
|
|
- late headless prepared-collision failure.
|
|
|
|
### Slice 4B2 prerequisite D — presentation-only host projection
|
|
|
|
Add one graphical and one headless `IRuntimePlacementObserver` using
|
|
`GameRuntime.Placements`.
|
|
|
|
Host receipt rules:
|
|
|
|
- `Withdraw`: remove render/spatial presentation, picking, radar, audio, and
|
|
targeting while retaining logical Runtime ownership.
|
|
- `Place`: project only the immutable Runtime-committed frame, then
|
|
acknowledge the exact token.
|
|
- `Discard`: discard the older projection revision, then acknowledge it.
|
|
- A host exception or unavailable backend does not roll Runtime back; retry
|
|
the same FIFO head.
|
|
|
|
`LiveEntityRuntime.RebucketLiveEntity` must become presentation-only. Its
|
|
current `CommitRebucket` call is a second spatial authority and must be removed
|
|
as part of the same cutover.
|
|
|
|
### Slice 4B2 prerequisite E — collision-prefix quiescence
|
|
|
|
Before landblock collision demotion, removal, or replacement:
|
|
|
|
1. quiesce the prefix;
|
|
2. drain/ack the existing placement receipt prefix;
|
|
3. call `RuntimeSetPositionState.ParkCollisionResidents`;
|
|
4. commit/withdraw the collision generation atomically;
|
|
5. wake only exact cell+generation residents.
|
|
|
|
Cover `LandblockPhysicsPublisher.DemoteToTerrain`, `RemoveLandblock`,
|
|
replacement commit, and the headless collision-retirement path. No partially
|
|
observable collision generation is allowed.
|
|
|
|
## Production route cutover
|
|
|
|
Cut routes only after all prerequisites above are present. The canonical chain
|
|
for every route is:
|
|
|
|
```text
|
|
wire acceptance
|
|
-> BeginAcceptedPlacement exact token
|
|
-> exact DAT/Setup preparation
|
|
-> Runtime SetPosition canonical commit or deferred residence
|
|
-> immutable host projection receipt
|
|
-> exact host acknowledgement
|
|
```
|
|
|
|
### 1. Initial login and CreateObject
|
|
|
|
Current duplicate authority:
|
|
|
|
- `DatLiveEntityProjectionMaterializer.MaterializeProjection` immediately
|
|
positions/rebuckets the world entity.
|
|
- `PlayerModeController.BuildControllerAndCamera` builds its own body and runs
|
|
`Resolve`/`ResolvePlacement`.
|
|
- Headless performs its own initial resolve/placement/body construction.
|
|
|
|
Required order:
|
|
|
|
1. register identity cellless;
|
|
2. begin initial/remote-create placement before hydration;
|
|
3. load exact Setup mover;
|
|
4. prepare the atomic Runtime controller/body relationship;
|
|
5. submit canonical SetPosition;
|
|
6. publish presentation only from `Place`;
|
|
7. acknowledge, then enable player mode/simulation.
|
|
|
|
Tests: outdoor/indoor login, unavailable destination then exact-generation
|
|
wake, malformed or delayed Setup, one body identity, one enter-world clock
|
|
reset, no early visible entity, graphical/headless identical snapshots.
|
|
|
|
### 2. Local ForcePosition
|
|
|
|
Delete the placement authority in `LocalForcePositionTransaction` and the
|
|
direct `BlipPosition`/pre-commit acknowledgement in
|
|
`LiveEntityNetworkUpdateController.OnPosition`.
|
|
|
|
Required order: accept timestamp and preserve heading; begin
|
|
`LocalAuthoritative`; canonical SetPosition; host `Place` acknowledgement;
|
|
then send the outbound Position acknowledgement. A missing destination cell
|
|
must not acknowledge ACE early.
|
|
|
|
Tests: same/cross cell, preserved heading/velocity, missing-cell wake,
|
|
reentrant newer Position, stale host ack, exactly one outbound ack.
|
|
|
|
### 3. Portal transit and materialization
|
|
|
|
Remove placement authority from `LocalPlayerTeleportPlacement.Place` and its
|
|
direct resolve/controller/world-entity/rebucket/spatial mutations.
|
|
|
|
Bind a Runtime portal-placement authority to the active
|
|
`RuntimeWorldTransitState` reveal generation, teleport sequence, exact
|
|
destination cell, and placement token. Readiness permits submission only.
|
|
Materialization and simulation release happen only after canonical commit,
|
|
host projection, and exact acknowledgement. Cancellation/replacement produces
|
|
`Discard`; a stale generation/sequence/cell/token can never reveal.
|
|
|
|
Tests: `/ls`, spell recall, ordinary portal, same-location revisit, missing
|
|
destination, cancelled/replaced reveal, host throw/retry, no early world reveal
|
|
or LoginComplete.
|
|
|
|
### 4. Remote CreateObject and Position
|
|
|
|
Delete `RemoteTeleportController`, `RemoteTeleportPlacement`, their pending
|
|
dictionary/rollback/lost-cell ownership, and pre-placement
|
|
`WorldEntity.SetPosition`/rebucket calls.
|
|
|
|
Preserve retail `MoveOrTeleport` classification:
|
|
|
|
- fresh Teleport timestamp or cellless body: teleport hook then SetPosition;
|
|
- ordinary nearby grounded update: interpolation remains;
|
|
- distant update: stop interpolation then SetPosition.
|
|
|
|
Accept the timestamp, begin the exact token before hydration/body/App changes,
|
|
unparent first, run the retail teleport hook when required, submit the exact
|
|
mover, project after Runtime commit, then re-arm constraints.
|
|
|
|
Tests: visible/hidden/parented CreateObject, first Position, Teleport timestamp,
|
|
near interpolation, >96 m far placement, unloaded indoor destination, racing
|
|
velocity, delete/GUID reuse during host callback.
|
|
|
|
### 5. Projectile authoritative create/corrections
|
|
|
|
Remove authoritative placement from App `ProjectileController` and the direct
|
|
SnapToCell/cell/shadow commit in `RuntimeProjectilePhysicsUpdater`.
|
|
|
|
Use `ProjectileAuthoritative` with the same Runtime body and exact projectile
|
|
Setup sphere for initial create and authoritative corrections. Preserve
|
|
prediction/component/effect identity. Do not route ordinary per-quantum
|
|
projectile integration through SetPosition.
|
|
|
|
Tests: arrow, bolt, spell projectile, mid-flight correction, unloaded cell,
|
|
landblock crossing, delete during ack, no duplicate body/projectile/effect.
|
|
|
|
### 6. Drops and unparent-to-world
|
|
|
|
`InventoryWorldDropProjectionController.TryRecoverUnknownPosition` may create
|
|
the logical object, but it must enter the same canonical create-placement
|
|
transaction. Do not expose a stale source position or replay create-time
|
|
effects.
|
|
|
|
Tests: whole item, split stack, new GUID, second drop position, attached child
|
|
becoming a world root, unavailable destination, newer Position while waiting.
|
|
|
|
### 7. Pickup, Parent, and Delete
|
|
|
|
Runtime hooks already exist in `RuntimeEntityObjectLifetime`, but the route
|
|
cutover must ensure pickup/parent/delete cancel the exact active
|
|
placement/lost-cell family first and publish `Discard`/`Withdraw` before the
|
|
later entity/inventory delta.
|
|
|
|
Tests: pickup during preparation/deferred residence, parent during pending
|
|
withdrawal, delete during host callback, GUID reuse, reset/disposal ownership
|
|
convergence.
|
|
|
|
### 8. Headless parity
|
|
|
|
Delete the independent resolve/placement/direct SetPosition and Blip logic in
|
|
`HeadlessSessionWorldProjection`. Headless must prepare/commit/ack through the
|
|
same Runtime operations as graphical presentation. Portal completion also
|
|
waits for the exact placement acknowledgement.
|
|
|
|
Tests: byte-identical login, ForcePosition, portal, missing-cell wake,
|
|
reconnect, and teardown snapshots.
|
|
|
|
## AP-22 — retail-authored collision shapes
|
|
|
|
After AP-1/AD-1 production cutover is stable:
|
|
|
|
- Make `ShadowShapeBuilder` the single Core authority for prepared Setup
|
|
primitives.
|
|
- Preserve authored cylinder order.
|
|
- If no cylinders exist, preserve authored spheres as spheres.
|
|
- Mixed data uses retail cylinder-first precedence.
|
|
- A truly shapeless Setup emits no world shadow.
|
|
- Remove `Setup.Radius/Height` collision synthesis, `Radius * 2` height guesses,
|
|
and sphere-to-cylinder coercion.
|
|
- Cut graphical static, headless static, and live-entity publication over
|
|
together.
|
|
- Do not alter transition dummy spheres, sticky/range radius, or projectile
|
|
mover shapes.
|
|
|
|
Automated gates: raw/prepared parity, cylinder order, sphere-only, mixed,
|
|
shapeless, scale, graphical/headless equality, representative installed DATs,
|
|
and dropped/portal/sign/door behavior.
|
|
|
|
## AD-10 — canonical remote slope projection
|
|
|
|
After AP-22:
|
|
|
|
- Prove remote movement uses the full `ResolveWithTransition` sweep.
|
|
- Remove terrain-normal preprojection from `RemoteMotionCombiner`.
|
|
- Remove Runtime terrain-normal sampling calls and delete the sampler if no
|
|
longer used.
|
|
- Let `CTransition::adjust_offset` project against the retained actual contact
|
|
plane.
|
|
- Preserve interpolation queues, correction replacement, Hidden behavior,
|
|
network cadence, and graphical/headless parity.
|
|
|
|
Tests must deliberately make terrain normals disagree with BSP/prop contact
|
|
normals, then cover uphill/downhill motion, seams, stairs, jumping, landing,
|
|
queue-empty/head-reached boundaries, and two-client observation.
|
|
|
|
## Closeout gates
|
|
|
|
Do not mark the campaign complete from narrow tests alone.
|
|
|
|
Automated:
|
|
|
|
```powershell
|
|
dotnet build AcDream.slnx -c Release
|
|
dotnet test AcDream.slnx -c Release --no-build --nologo
|
|
```
|
|
|
|
Also run every focused fixture named in the campaign plan: #273 tight gap,
|
|
#271 stair side, #269 slope, #265 landing, #185 stairs, #137 sliding normal,
|
|
#116 head collision, roof/cellar wedge, missing-cell, generation replacement,
|
|
GUID reuse, graphical/headless parity, and allocation/quiescence gates.
|
|
|
|
Connected/visual:
|
|
|
|
- login and portal arrival at outdoor, indoor, dungeon, stair-lip, and world
|
|
edge locations;
|
|
- repeated `/ls`, spell recall, ordinary portals, same-location revisit, and
|
|
reconnect;
|
|
- no early world reveal, outdoor demotion, floor snap, terrain-Z lift, or void;
|
|
- tight gaps, stairs, steep roofs, ledges, doors, crowds, shallow water, and
|
|
landblock seams;
|
|
- dropped objects, portals, signs, doors, and shapeless decorations;
|
|
- two-client uphill/downhill movement and sloped props;
|
|
- headless/graphical trace equality and graceful zero-residue teardown.
|
|
|
|
Only then retire AP-1, AD-1, AP-22, and AD-10, update the architecture,
|
|
divergence register, campaign/roadmap/milestones, research notes, durable
|
|
memory, `CLAUDE.md`, and `AGENTS.md`, and record final rollback SHAs.
|
|
|
|
## Review procedure for every remaining behavior commit
|
|
|
|
1. Implement one bisectable mechanism and run focused tests.
|
|
2. Run a retail-conformance reviewer against named retail symbols/addresses.
|
|
3. Run an architecture/adversarial reviewer against reentrancy, stale
|
|
sequences, malformed data, GUID reuse, streaming replacement, host failure,
|
|
reset, and disposal.
|
|
4. Fix every confirmed finding at its root cause.
|
|
5. Re-run the same reviewers until clean.
|
|
6. Run Release build plus the complete Release test suite.
|
|
7. Update the divergence/docs in the same behavior commit.
|
|
8. Stage exact paths only and commit.
|
|
|
|
## Rollback points
|
|
|
|
Newest first:
|
|
|
|
```powershell
|
|
git revert 270f5154 # dormant public placement receipt channel
|
|
git revert 4c02ac42 # Runtime SetPosition/lost-cell residence owner
|
|
git revert e84a388e # pure Core retail SetPosition transaction
|
|
```
|
|
|
|
Earlier campaign commits are individually bisectable and listed in the
|
|
completed sections above. Revert only the responsible mechanism; do not
|
|
restore the rejected snapshot lease or revive legacy compensation elsewhere.
|
|
|
|
## First action for the next agent
|
|
|
|
1. Read this file completely.
|
|
2. Read `docs/research/2026-07-31-canonical-set-position.md` and the AP-1/AD-1
|
|
rows in `docs/architecture/retail-divergence-register.md`.
|
|
3. Confirm `HEAD` contains `270f5154` in the exact worktree above.
|
|
4. Confirm only `AGENTS.md` has a real unrelated unstaged diff.
|
|
5. Implement prerequisite A (real Runtime collision-report ownership) as its
|
|
own reviewed commit.
|
|
6. Then design prerequisites B/C together so exact mover preparation and the
|
|
atomic controller/body transaction cannot create another partial ownership
|
|
state.
|