acdream/docs/research/2026-07-03-phase-r-session-handoff.md
2026-07-03 12:19:16 +02:00

144 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase R handoff — fresh-session entry point (2026-07-03)
**Read this first, then the plan of record**
(`docs/plans/2026-07-02-retail-motion-animation-rewrite.md`). This session
ran the R2→R4 arc of the Phase R mandate; the fresh session picks up at
**R4-V4 smoke verification → R4-V5**.
## The mandate (user, standing)
Total overhaul of movement + animation as a VERBATIM retail port — all
movement, inbound and outbound, all animation, for players/NPCs/monsters.
No guessing, no approximations, no bandaids. The user cancelled the /loop
self-scheduling near the end of this session — **work continues on user
prompts, not self-scheduled wakeups**, but the drive-autonomously rules in
CLAUDE.md still apply within a turn.
## State at handoff (worktree `vigorous-joliot-f0c3ad`, branch `claude/vigorous-joliot-f0c3ad`)
- Tree: CLEAN at `7016b26c` (only `v4-smoke.log` untracked — session
scratch, delete freely). Full suite green: **3,948 tests**
(385 Net + 425 UI + 713 App + 2,425 Core, +4 pre-existing skips).
- **R1 ✅ R2 ✅ R3 ✅ shipped** (trail + commit SHAs recorded in the plan
doc's stage entries). **R4: V0V4 shipped, V5+V6 remain.**
- A smoke client was launched with the V4 build (`ACDREAM_DUMP_MOTION=1`,
log `v4-smoke.log` in the worktree root, UTF-16) — **the user had NOT yet
reported an NPC-behavior verdict at handoff time.** First order of
business: get that verdict (or relaunch and ask). Watch items: NPC
chase/wander legs, turn-to-face, melee-range stop distance (arrival is
now retail cylinder distance — the old max() gate is gone).
## What just landed (this session, newest first)
| Commit | What |
|---|---|
| `7016b26c` | **R4-V4** remote cutover: per-remote MoveToManager; RemoteMoveToDriver + PlanMoveToStart DELETED; P4 TargetTracker adapter; retail unpack_movement dispatch (head-interrupt every UM; mt 69 never touch the interpreted funnel) |
| `a144e873` | **R4-V3** wire: mt 8/9 parsing (TurnToPathData), raw bitfield surfaced, mt-0 sticky trailer |
| `addc8e97` | **R4-V2** the verbatim MoveToManager (33 members, 101 tests; seams listed in its final report — ctor takes the interp + 14 providers; the identity-quaternion TDD catch) |
| `e0d2492c` | **R4-V1** command-selection family (GetCommand + CanCharge fast-path; MoveToMath incl. the Ghidra-confirmed heading_diff mirror) |
| `386b1ce5` | **R4-V0** pins P1P7 (see below) |
| `988304e1` | R4 research base (`docs/research/2026-07-03-r4-moveto/` — decomp, ACE cross-ref, port plan) |
| `30115d96` | **W6b fix** — the "press W and stop instantly" live regression (see gotchas) |
| `fb7beb70``8eff3978` | R3 W0W7 + R2 Q0Q6 (see the plan doc's stage trails) |
## NEXT: R4-V5 — LOCAL PLAYER cutover (the delicate one)
Spec: `docs/research/2026-07-03-r4-moveto/r4-port-plan.md` §3 V5.
**ONE commit, GameWindow + PlayerMovementController, do NOT fan out**
(feedback_dont_parallelize_coupled_plan_slices). Shape:
- The player gets a MoveToManager bound like remotes (the
EnsureRemoteMotionBindings block at GameWindow is the reference wiring;
the player's Motion/seams already exist from R3 — DefaultSink is bound,
`_playerController.Motion` exposed).
- **B.6 auto-walk DELETED**: `DriveServerAutoWalk` + `BeginServerAutoWalk`
+ the `_autoWalk*` fields + the local mt-6 branch in GameWindow
(`BeginServerAutoWalk` call site) + the two relocated constants
(`AutoWalkArrivalEpsilon`, `AutoWalkTurnRateFor` — marked V5-scope in the
controller).
- **P1 pin applies here**: port the missing tail of retail's
`CPhysics::SetObjectMovement` gate — DROP any 0xF74C event whose wire
`IsAutonomous` byte is set when guid == local player (parsed at
`UpdateMotion.cs` isAutonomous, relayed by WorldSession, consumed
NOWHERE yet). That's what makes retail's unconditional head-interrupt
safe against ACE's mt-0 echo. `V0-pins.md` P1 has the full adjudication +
the LoseControlToServer note. This RETIRES the informal
"don't cancel on non-MoveTo" comment block in the local UM branch.
- TS-36 retires (InterruptCurrentMovement bound for the player);
AD-26 retires; AD-27/AP-23 re-anchor.
- Movement keys auto-cancel a server MoveTo (retail: the CommandInterpreter
DoMotion's cancel bit → interrupt → CancelMoveTo — the edge-driven W6
input already calls DoMotion with ctor-default params whose CancelMoveTo
is TRUE, so this may fall out for free — verify, don't assume).
- Tests: the V2 harness pattern for the player-side bind; the W6
edge-driven regression suite (`W6EdgeDrivenMovementTests.cs`) is the
template for controller-level tests with a real sink.
- Then **V6**: register/roadmap/plan/memory sweep (V6 spec in the plan).
After V6, R4 is done → R5 (MovementSystem facade + StickyManager +
ConstraintManager + TargetManager full port), R6 (per-tick
UpdateObjectInternal order — retires the 300ms stop window, PlanFromVelocity
AP-80, ObservedOmega AP-76, AP-75/AP-77 velocity adaptations), R7
(outbound cadence TS-33), R8 (audit + final visual pass).
## Pending user verifications (visual passes)
1. **V4 smoke verdict** (see above — NPC movement).
2. **R2+R3 combined visual pass** (task #9): jump instant-Falling engage,
walk-off-ledge momentum (NEW behavior), running-in-circles blend, stop
settle, strafe pacing (EXPECTED-DIFF: #45's 1.248× factor retired —
local now matches remotes), retail-observer view (no rubber-band).
Partially confirmed ("works a lot better now") after the W6b fix.
## Load-bearing gotchas from this session (do not relearn these)
1. **BN hoisted-register artifact class** (caused the W6b live bug): the
pseudo-C renders pre-call register caches as post-call field reads.
`ApplyInterpretedMovement` must ENTRY-CACHE the axis values — the style
dispatch's `ApplyMotion(style)` resets forward to Ready (verbatim,
raw 0051ea6c) and retail self-heals via the cached fwd re-apply. The
183-case suite can NOT catch sink-result-dependent bugs: its
RecordingSink's bool return doesn't mirror the real
MotionTableDispatchSink (style dispatches return TRUE → the resetting
state-write runs). Regression suite: `W6EdgeDrivenMovementTests.cs`.
2. **The dispatch RESULT gates queue+state writes** (W5 discovery):
`IInterpretedMotionSink.ApplyMotion/StopMotion` return bool for this
reason — documented on the interface.
3. **Retail's echo discriminator is the wire autonomous byte** (V0 P1):
not a workaround — `CPhysics::SetObjectMovement` 0x00509690's final
branch. Port it in V5, don't invent gating.
4. **MoveToManager entry points never drain pending_actions** — re-issues
MUST route through `PerformMovement` (V2 finding, tested).
5. **`default(Quaternion)` is zero, not identity** — heading math reads
90° off a zero quat (V2 TDD catch; `IdentityPosition` constant).
6. **fail_progress_count is WRITE-ONLY in retail** — there is no MoveTo
give-up threshold; do not invent one.
7. **Delegation pattern that works**: sonnet implementers against
committed pinned specs (research → pins with adversarial verify →
implement → orchestrator independently verifies scope + suite +
spot-checks against the raw decomp → commit). GameWindow/controller
coupled surgery stays with the orchestrator. Workflow tool for
research fan-outs (r3/r4 extraction + pin workflows are the templates).
8. **py (not python) exists on this box**; logs from Tee-Object are
UTF-16; heredocs with quotes inside python strings break — write
scripts to the scratchpad with the Write tool and run `py file.py`.
9. **Ghidra MCP** (port 8080/8081, needs the user to open patchmem.gpr):
used live this session for heading_diff/get_desired_heading
(`ghidra-confirmations.md`). Ask the user to open it when a BN garble
blocks a pin.
10. **ACE session care**: graceful client close (CloseMainWindow) or ACE
holds the session ~3 min (exit 29 on relaunch). Don't kill clients
the user launched — ask.
## Key file map (R4 additions)
- `src/AcDream.Core/Physics/Motion/MoveToManager.cs` + `MoveToNode.cs`
the V2 port (seams doc'd on the ctor).
- `src/AcDream.Core/Physics/Motion/MoveToMath.cs` — heading/cylinder math
+ `OriginToWorld` (relocated from the deleted RemoteMoveToDriver).
- `src/AcDream.Core/Physics/Motion/MovementParameters.cs``GetCommand` /
`FromWire` / `FromWireTurnTo` / `GetDesiredHeading` / `TowardsAndAway`.
- `docs/research/2026-07-03-r4-moveto/` — decomp + ACE cross-ref +
port plan + `V0-pins.md` + `ghidra-confirmations.md`.
- GameWindow: `EnsureRemoteMotionBindings` (the full per-remote wiring
reference), the remote UM dispatch (mt 69 vs mt-0 funnel), the
per-tick tracker+UseTime block.