acdream/docs/research/2026-07-02-inbound-motion-deviation-map.md
Erik a2f8104cbf feat(L.2g-S5): delete player pace-inference layer; close #39 (DEV-2)
S0 wire probe (live capture, retail actor via ACE) refuted the premise
the #39 machinery was built on: walk<->run Shift toggles arrive as
EXPLICIT UMs (0x0005 <-> 0x0007@runRate) because retail's default-
difference packing baselines forward_command against Ready — W-held is
always packed, and ACE re-emits it unconditionally with the holdKey
upgrade (MovementData.cs:104-119). The frequent flags=0 autonomous UMs
are genuine keys-released / heading-only states; retail applies them as
full stops (InterpretedMotionState ctor 0x0051e8d0 defaults Ready +
move_to_interpreted_state 0x005289c0 flat copy).

Retail has NO pace->animation adaptation anywhere in its inbound
pipeline (two decomp dives + ACE cross-check, deviation map DEV-2), and
the refinement layer's 0.2s-grace re-promotion after legitimate Ready
UMs was itself the observed Ready<->Run thrash / rubber-band component.

Deleted: ApplyPlayerLocomotionRefinement, UmGraceSeconds,
PlayerRunPromoteSpeed/PlayerRunDemoteSpeed, RemoteMotion.LastUMTime,
the synth-player refinement call in OnLivePositionUpdated. Player-remote
cycles are now UM-driven only, exactly like retail. NPC PlanFromVelocity
path untouched (S6 unifies).

S0 findings + S1 live validation (0 false UM_STALE drops across 280 UMs)
recorded in docs/research/2026-07-02-inbound-motion-deviation-map.md.

fix #39: closed — root-cause narrative corrected, machinery removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 16:10:28 +02:00

323 lines
22 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.

# Inbound motion deviation map — remote-entity animation + position vs retail
Date: 2026-07-02
Mode: **/investigate report — no code changes made.** This doc + the four mapper
reports under `2026-07-02-inbound-motion-maps/` are the only writes (uncommitted).
Branch: `claude/vigorous-joliot-f0c3ad`. Follows the handoff
`2026-07-02-inbound-motion-verbatim-port-handoff.md`.
## Symptom (acceptance oracle — user's live observation, axiom)
Watching a remote player in acdream: walk↔run transitions WITHOUT stopping react
too slowly in the motion interpreter, throwing animation + position off afterward
and compounding through continued running/turning; plus general sliding + position
errors on stop.
## Headline findings
1. **The premise behind acdream's current walk↔run mechanism is refuted.** The
#39-era UP-velocity refinement layer (`ApplyPlayerLocomotionRefinement`,
0.2 s UM-grace + 510 Hz UP cadence + 5.5/4.5 m/s hysteresis) was built on the
2026-05-06 finding "the wire goes silent on Shift-toggle." Both oracles now
contradict that finding:
- **Retail sends.** `CommandInterpreter`'s HoldRun command handler
(`0x85000001`, pseudo-C `acclient_2013_pseudo_c.txt:699322-699328`, addr
0x006b37a8→0x006b3852) calls `SetHoldRun` then `SendMovementEvent()`
**whenever the player is not standing still** — i.e. a Shift toggle while W
is held emits a fresh MoveToState. (Same for HoldSidestep `0x85000002`.)
- **ACE relays.** `GameActionMoveToState.cs:36` calls
`BroadcastMovement(moveToState)` **unconditionally** for every inbound
MoveToState (`Player_Networking.cs:364-365``GameMessageUpdateMotion`
broadcast, with the WalkForward+HoldKey.Run→RunForward upgrade and
run-skill speed recompute).
So an observer **should** receive a UM with ForwardCommand flipping
Walk↔Run on every Shift toggle. Why the 2026-05-06 clean test saw only
Ready↔Run `[FWD_WIRE]` transitions is the one open empirical question —
settle it with probe S0 below before touching the refinement layer.
2. **Retail never adapts animation from observed pace.** Three independent decomp
dives + the ACE port cross-check all converge: the inbound position path
(0xF748/0xF619 → `SmartBox::HandleReceivedPosition``MoveOrTeleport`
`InterpolationManager` chase) has **zero writes into `CMotionInterp`** — it
only *reads* `get_adjusted_max_speed()` (×2.0) as the chase-speed cap. The
wire's velocity field is a **dead parameter** in `MoveOrTeleport`
(pseudo-C:284304 — passed, never dereferenced). Animation changes come only
from motion events (0xF74C → `MovementManager::unpack_movement`).
acdream's pace→cycle inference layer has **no retail equivalent** (DEV-2)
and is an **unregistered deviation**.
3. **acdream's instant DR-velocity snap on walk↔run is retail-correct; the
pose hard-cut is the real deviation.** Adversarial verification refuted the
initial "retail paces velocity through the link clip" claim: in
`GetObjectSequence`'s link-transition branch, `add_motion(new cycle)` is the
LAST synchronous call and `CSequence::set_velocity` is a hard overwrite —
the sequence velocity snaps to the new cycle's value the same tick
(pseudo-C:298437-298468, 300798-300814; ACE `MotionTable.cs:144-168`,
`Sequence.cs:127-130`). What acdream's Fix B loses is only the link **pose**
(plus its authored root-motion frames): retail plays the authored
walk↔run link clip to completion before the new cycle's animation starts.
4. **Retail's remote pipeline is one atomic funnel; acdream's is three loosely
coupled writes.** That structural split (DEV-1) is what lets every gap
(DEV-2/3/5/6) desync pose from velocity with nothing to reconcile them.
## The retail inbound model (what "verbatim" means here)
Two decoupled inbound paths, meeting only at the per-tick frame combiner:
**Motion events (0xF74C / 0xF619-embedded)**
`ACSmartBox::DispatchSmartBoxEvent` (pseudo-C:357117) →
`CPhysics::SetObjectMovement` (271370, staleness-gated on `update_times[8]`) →
`MovementManager::unpack_movement` (300563, **10-way jump table**: case 0 =
InterpretedMotionState, 6/7 = MoveTo, 8/9 = TurnToObject/TurnToHeading) →
`CMotionInterp::move_to_interpreted_state` (305936: flat `copy_movement_from`
overwrite of `interpreted_state`, caches `my_run_rate` from RunForward's
forward_speed) → `apply_interpreted_movement` (305713: per-slot
`DoInterpretedMotion`/`StopInterpretedMotion` dispatch in retail order — style,
forward, sidestep-or-stop, turn-or-stop, idle-stop enqueue) →
`CMotionTable::GetObjectSequence` (298636), which decides:
- **same substate + same speed sign** → fast path: `change_cycle_speed`
(playback rate × newSpeed/oldSpeed) + `subtract_motion`/`combine_motion`
velocity swap — same node keeps playing, **no restart** (acdream's SCFAST
fast-path is the equivalent);
- **substate change (walk↔run!)** → link path: `get_link` (double-hop through
the style default when no direct link / sign flip), `clear_physics` +
`remove_cyclic_anims` (keeps a mid-playback link, drops the old loop),
`add_motion(link)` + `add_motion(cycle)`, `re_modify` re-applies active
modifiers. Velocity = the **cycle's** (last overwrite, instant); pose = link
first, then cycle.
Bookkeeping: `MotionTableManager::add_to_queue`/`remove_redundant_links`/
`CheckForCompletedMotions` (290645-290854) + `CMotionInterp::pending_motions`/
`MotionDone` (305032/305238) reconcile completed commands at anim boundaries.
**Position events (0xF748/0xF619)**`SmartBox::HandleReceivedPosition`
(92896): for remotes, `MoveOrTeleport` (284304) only — staleness-gated
(`POSITION_TS`/`TELEPORT_TS`), >96 units from player → plain snap, else
`InterpolationManager::InterpolateTo` node queue (cap 20). Per tick,
`adjust_offset` (353071) moves the full remaining distance capped at
`2 × get_adjusted_max_speed()` (fallback 7.5 m/s), stall detection (<30%
progress per 5 frames fail counter >3 → hard snap). **acdream's
`InterpolationManager` is already a verbatim port of this (L.3).**
**Per tick** (`UpdateObjectInternal` 283611): `CPartArray::Update`
`CSequence::update` fills the frame delta from **the animation frames' baked
per-frame deltas** (anim-node path) or `velocity×dt` (`apply_physics` fallback);
`PositionManager::adjust_offset` **overwrites** it when a chase node is active
(last-writer-wins, NOT additive — matches acdream's `ComputeOffset` REPLACE
dichotomy); then the **full collision sweep** (`transition`) runs for remotes
too (acdream deliberately skips it for grounded player remotes — DEV-10).
**Stop** — one path for every stop: `CMotionTable::StopSequenceMotion` (298954)
re-enters `GetObjectSequence` targeting the style default with force=1:
`clear_physics` zeroes velocity/omega **at transition start**, the idle-link's
authored deceleration plays, `add_to_queue(READY)` + `RemoveMotion` bookkeeping.
Modifier stop = `subtract_motion` only. No pace-derived stop inference.
## Ranked deviation map
All 10 deviations were adversarially verified through two lenses (refute vs
current acdream code / refute vs retail decomp+ACE). 9 CONFIRMED, 1 REFUTED
(DEV-4's velocity half — corrected below). Full verify evidence:
`…/tasks/waqdgyk0m.output` (session temp) — the load-bearing citations were
additionally re-read first-hand in this session.
| # | Sev | Deviation | Symptom link |
|---|-----|-----------|--------------|
| DEV-1 | HIGH | Remote inbound bypasses the CMotionInterp funnel: bulk-copy + direct `SetCycle` instead of `move_to_interpreted_state`/`apply_interpreted_movement` | Structural root: pose + DR velocity are separate writes; every gap desyncs them with no reconciliation |
| DEV-2 | HIGH | Non-retail grace-window + hysteresis pace→cycle inference for player remotes (`UmGraceSeconds=0.2`, promote 5.5 / demote 4.5 m/s) | The direct "reacts too slowly": ≥0.2 s + UP cadence + hysteresis-crossing before the gait flips; backlog builds meanwhile. **Unregistered deviation**; premise refuted (headline 1) |
| DEV-3 | HIGH | Stop is three unwired mechanisms (UM-Ready overwrite / dead UP-velocity StopCompletely / landing); no `StopSequenceMotion` path; nothing zeroes body velocity or reconciles the queue | Direct cause of stop-slide: pose goes Ready while the body drains pre-stop waypoints at up to 2× maxSpeed |
| DEV-4 | MED (corrected) | Fix B drops the authored walk↔run link **pose** (hard visual cut + lost link root motion). ~~Velocity snap~~ — REFUTED: retail snaps velocity instantly too | Visual-only hard cut at each toggle; NOT a position-error source |
| DEV-5 | HIGH | Inbound movement types 8/9 (TurnToObject/TurnToHeading) dropped → misapplied as `SetCycle(Ready)` | Mid-locomotion turn command becomes a spurious full stop — error injected exactly during "compounding through running/turning" |
| DEV-6 | MED | Sequence-number staleness gate missing (movementSequence/serverControlSequence/isAutonomous parsed-then-discarded; retail gates on `update_times[8]`) | A reordered stale UM re-applies the old gait or un-stops a stop (extends register TS-26 to UM) |
| DEV-7 | MED | `pending_motions`/`pending_animations`/`MotionDone`/`remove_redundant_links` lifecycle absent | Enabler: missing `remove_redundant_links` is what made rapid toggles restart links forever, forcing Fix B; without MotionDone nothing clears per-transition bookkeeping |
| DEV-8 | MED | Remote DR velocity synthesized from hardcoded gait constants at SetCycle time vs retail's MotionData-accumulated CSequence velocity (+ baked per-frame anim deltas) | Any per-gait speed mismatch vs ACE's integration = constant-rate error that fills the interp backlog → discharges as slide/snap |
| DEV-9 | MED | Modifier layer missing: no `re_modify`, single-cycle selection, omega formula-seeded instead of combine/subtract | Turn contribution approximated independently of the motion table → heading-rate error while running+turning |
| DEV-10 | LOW | Bifurcated position-drive paths; grounded player remotes skip the per-tick collision sweep (retail sweeps every entity) | None for this symptom directly; parity + pass-through-geometry hazard |
### Key anchors per deviation
- **DEV-1** — retail: pseudo-C 305936 (`move_to_interpreted_state` 0x005289c0),
305713 (`apply_interpreted_movement` 0x00528600), 298636 (`GetObjectSequence`
0x00522860), 293301 (`copy_movement_from` 0x0051e750). acdream:
`GameWindow.cs:4590/4598` (bulk-copy), `:4769` (separate SetCycle), `:4517`
(comment-only funnel ref); D6.2 raw-input funnel is local-player-only
(`PlayerMovementController.cs:761-1014`). Nuance (verify correction): the
sidestep/turn axes DO route through `DoInterpretedMotion`/`StopInterpretedMotion`
(`GameWindow.cs:4794-4857`); the forward axis — the crux — is the bulk-copy.
- **DEV-2** — acdream: `GameWindow.cs:5095/5104/5110` (constants),
`:5112-5300` (both methods), `:5128-5134` (the unconfirmed-premise comment).
Retail: no equivalent exists (searched: InterpolationManager/PositionManager
ranges 352000-353400 — zero `CMotionInterp` writes; `MoveOrTeleport` velocity
param dead at 284304).
- **DEV-3** — retail: 298954 (`StopSequenceMotion` 0x00522fc0), 305635
(`StopInterpretedMotion` 0x00528470), 301194 (`clear_physics` 0x00524d50).
acdream: `GameWindow.cs:4364-4367` (UM-Ready), `:5711-5731` (dead UP-velocity
stop — ACE player UPs carry velocity=null per `:5700-5710`), `:5527-5553`
(landing = only `Interp.Clear` site); plus the acdream-invented 300 ms
stop-detection window (`GameWindow.cs:4862-4890` + TickAnimations) — also
retail-less, part of this cluster.
- **DEV-4** — retail: 298636 link branch; 298552 (`get_link`); 301777
(`append_animation`); velocity-overwrite refutation: 298437-298468
(`add_motion` 0x005224b0) + 300798-300814 (`set_velocity`/`set_omega`
overwrites), ACE `MotionTable.cs:144-168` + `Sequence.cs:127-130/221-230`.
acdream: `AnimationSequencer.cs:585-635` (Fix B), `:686-754` (velocity
synthesis — retail-equivalent in timing).
- **DEV-5** — retail: 300563/300707 (jump table cases 8/9 →
`MoveToManager::TurnToObject/TurnToHeading`). acdream:
`UpdateMotion.cs:136-238` (no case 8/9), `GameWindow.cs:4364-4367`
(null-command → Ready misfire). Confirmed live earlier: `mt=0x09` arrives,
acdream plays Ready (2026-06-26 audit D9).
- **DEV-6** — retail: 271370 (`SetObjectMovement` staleness gate), 357224
(`update_times[8]` compare). acdream: `UpdateMotion.cs:89-106`,
`UpdatePosition.cs:29-31/156` (parsed-then-discarded).
- **DEV-7** — retail: 305238 (`MotionDone` 0x00527ec0), 290854
(`MotionTableManager::add_to_queue` 0x0051bfe0), 290771
(`remove_redundant_links` 0x0051bf20), 290645 (`CheckForCompletedMotions`).
acdream: `AnimationSequencer.cs:401` (always-synchronous SetCycle),
`:1128-1129` (`AnimationDoneSentinel` exists, unconsumed by any motion
bookkeeping).
- **DEV-8** — retail: 298437-298492 (`add_motion`/`combine_motion`/
`subtract_motion`), 302402 (`CSequence::update` — anim-frame deltas are the
primary drive), 305160 (`get_state_velocity` constants 3.12/4.0 — the
*logical* values acdream synthesizes). acdream: `AnimationSequencer.cs:686-754`.
- **DEV-9** — retail: 298636 (`re_modify` at rebuild tail), 298954 (modifier
`subtract_motion` branch), 305713 (per-slot dispatch). acdream:
`GameWindow.cs:4648-4683` (single-cycle pick), `:4841-4847` (ObservedOmega
formula seed), `:10097-10106` (manual omega integration).
- **DEV-10** — retail: 280817/283611 (sweep for all entities). acdream:
`GameWindow.cs:9717-9722` (fork), `:9883-9890` (sweep skipped, player-remote
path), `:10156-10181` (sweep present, NPC path), `:5657` (NPC UP hard-snap).
## Recommended port campaign (for approval — no code written yet)
Ordered so each slice is independently landable, tests-first, minimal-surgery
(no sequencer rewrite; `SetCycle` internals stay). Every slice updates
`docs/architecture/retail-divergence-register.md` in the same commit.
- **S0 — the wire probe (no code).** Live capture, acdream as observer,
actor driven from retail: `ACDREAM_DUMP_MOTION=1 ACDREAM_REMOTE_VEL_DIAG=1`,
structured protocol with the walk↔run Shift toggle as the centerpiece;
optionally WireMCP on loopback :9000 for the raw S→C bytes. Expected per the
oracles: a UM with ForwardCommand flipping Walk↔Run on every toggle
(`[UM_RAW]` is the arbiter — the 2026-05-06 test read `[FWD_WIRE]`, which
only fires on interpreted-command *change* after acdream's own resolution).
Outcome decides DEV-2's disposition. *(Needs the user driving the retail
client — this is the one stop-and-wait step.)*
- **S1 — DEV-6 staleness gate.** ~30 isolated lines: capture the two u16s into
`UpdateMotion.Parsed`, retail wraparound-newer compare per guid, drop stale.
Unit-testable against the 0x7fff wraparound rule. Safe first commit.
- **S2 — DEV-1 funnel (the centerpiece), absorbing DEV-3 + DEV-9 dispatch.**
Port `move_to_interpreted_state` + `apply_interpreted_movement` into
`MotionInterpreter`, with `DoInterpretedMotion` routing to the existing
`AnimationSequencer.SetCycle` as the `GetObjectSequence` backend.
`OnLiveMotionUpdated`'s remote SubState branch collapses to one
`move_to_interpreted_state(ims)` call; stop flows through
`StopInterpretedMotion` (no `Interp.Clear()` band-aid — the queue's final
waypoints ARE the true stop position); sidestep/turn become per-slot retail
dispatch. Parity test first: replay a captured UM stream through old + new
paths, assert identical SetCycle sequence + InterpretedState trace; then a
stop-slide acceptance case.
- **S3 — DEV-7 bookkeeping.** `MotionTableManager` companion (pending_animations,
`add_to_queue`, `remove_redundant_links`, `CheckForCompletedMotions`) wiring
the existing `AnimationDoneSentinel`; `pending_motions`/`MotionDone` in
`MotionInterpreter` second. Additive, decomp-semantics unit tests first.
- **S4 — DEV-4 corrected: retire Fix B.** Restore the link-pose enqueue for
locomotion↔locomotion now that S3's `remove_redundant_links` removes Fix B's
original justification (link-restart spam). Velocity stays instant
(retail-correct). Acceptance: user visual side-by-side.
- **S5 — DEV-2 disposition per S0.** If UMs arrive: delete the refinement layer
(dead weight + latency + feedback loop) and let the S2 funnel drive. If the
wire is genuinely silent: keep a minimal layer as an explicitly registered
ACE-adaptation row (a retail client on the same wire would show the stale
gait too — matching retail display means NOT inferring), and file the gap
against ACE. Either way DEV-2's machinery stops being an unregistered
deviation.
- **S6 — remainder.** DEV-5 (parse types 8/9 → heading target; cross-check field
order vs Chorizite + holtburger first), DEV-8 (evidence first: dump Humanoid
MotionTable Walk/Run `MotionData.Velocity`+Flags from the dat, diff synthesized
magnitudes vs ACE's integration), DEV-10 deferred (fold-in after S2; NPC
hard-snap replacement needs explicit user approval per the reverted-campaign
precedent).
## What we've ruled out
- "acdream lacks any transition machinery" — false; `SetCycle` resolves authored
links (`GetLink`) and has the retail same-substate fast path (SCFAST ≈
`change_cycle_speed`).
- "Retail paces the walk↔run *velocity* change through the link clip" — refuted
(headline 3); instant velocity snap is retail-correct.
- "Retail refines the remote's cycle from UP-derived velocity" (#39's premise)
— refuted; no such mechanism exists in the decomp (two independent dives +
ACE cross-check).
- The `InterpolationManager` chase itself — already a verbatim port (L.3);
constants re-verified this session (2× adjusted max speed, 0.05 desired
distance, 30%/5-frame stall, fail>3 blip, 20-node cap, 96-unit gate upstream).
## What this is NOT
This is NOT a "port the whole CSequence/CPartArray stack" campaign — the
sequencer's node/link/queue mechanics are close enough that the funnel (DEV-1),
bookkeeping (DEV-7), and stop path (DEV-3) can be ported around it surgically;
and it is NOT a dead-reckoning-tuning problem — the chase is already retail,
it's the inputs (cycle + velocity source + stop signal) that deviate.
## S0 wire-probe RESULTS (2026-07-02, post-S1 live capture)
Observer acdream (+Acdream), actor retail-driven (guid 0x5000000B), structured
protocol incl. Shift toggles. 280 UMs captured (`launch-s0-wireprobe.log`).
1. **The wire is NOT silent — DEV-2's premise is dead.** Walk↔run toggles
arrive explicitly: `fwd=0x0005 fwdSpd=null(=1.0)``fwd=0x0007
fwdSpd=2.85`. Root cause of the 2026-05-06 misreading: retail's
default-difference packing baselines `forward_command` against **Ready**
(`RawMotionState.Default`, our own D6.2b verbatim port) — W-held is
non-default and always packed, so ACE (`MovementData.cs:104-119`) always
re-emits it with the holdKey upgrade + run-skill speed.
2. **flags=0 "empty" autonomous UMs are frequent (127/209) and LEGITIMATE**
— they are genuine keys-released / heading-only MoveToState relays
(all-default raw state packs nothing; ACE `RawMotionState.Read` leaves
absent = Invalid; `MovementData` emits nothing). Retail semantics
(verified: `InterpretedMotionState` ctor 0x0051e8d0 defaults
`forward_command=Ready`; `MovementManager::unpack_movement` case 0
UnPacks into a default-constructed state;
`CMotionInterp::move_to_interpreted_state` 0x005289c0 does a FLAT
`copy_movement_from` + `apply_current_movement`): an empty UM = a real
full stop. acdream already maps it to Ready — but the DEV-2 refinement
then re-promotes the cycle from UP pace after the 0.2 s grace, producing
a Ready↔Run thrash against legitimate stop signals. That thrash is the
observed flicker/rubber-band component.
3. **S1 gate validated live**: 0 `[UM_STALE]` drops across 280 UMs;
movementSeq advances +1 per UM; byte-level layout confirmed
(`instanceSeq|movementSeq|serverControlSeq|isAutonomous` exactly where
the parser reads them).
4. Also confirmed in `unpack_movement` (0x00524440) for the S2 port: the
outer style u16 routes through `command_ids[]` and applies via
`DoMotion` ONLY when it differs from the current style; motionFlags
carries sticky-object (0x100 → `stick_to_object`) and standing_longjump
(0x200); the actions list is consumed under a 15-bit
`server_action_stamp` wraparound compare
(`move_to_interpreted_state` 0x005289c0, lines 305953-305989).
**Disposition: S5 = delete the player pace-inference layer** (executed in the
same session; NPC `PlanFromVelocity` path untouched — its unification is S6).
## Provenance
- Workflow `wf_b92a5670-283`: 4 read-only mappers (retail decomp / ACE port /
acdream code / prior-research claims — full reports preserved in
`2026-07-02-inbound-motion-maps/`) → synthesis → 2-lens adversarial verify
per deviation (25 agents, ~3.0 M tokens). The ACE-port mapper crashed on
structured output AFTER writing its report file; synthesis read all four
files. One verify lens (DEV-4 retail side) delivered the REFUTED verdict
incorporated above.
- Targeted agents: retail remote-anim adaptation dive (+2 children:
InterpolationManager decomp dump, ACE InterpolationManager cross-check).
- First-hand session reads: `OnLiveMotionUpdated` (GameWindow 4230-4930),
DR tick path (9700-9920), `AnimationSequencer.SetCycle` (340-790),
`ApplyServerControlledVelocityCycle`/`ApplyPlayerLocomotionRefinement`
(5077-5300), `ServerControlledLocomotion`, `PositionManager`,
`InterpolationManager`, `UpdatePosition` parser, ACE `Player_Tick.cs` /
`Player_Networking.cs` / `GameActionMoveToState.cs`, decomp
`SendMovementEvent`/HoldRun sites (699274-700312), 2026-06-04 deep-dive
divergence list, ISSUES #39, divergence register scan.
- Corrections applied to the raw workflow output: DEV-1 anchor fix
(`MotionInterpreter.cs:399/412/558` reference different retail functions —
the only funnel comment-refs are `GameWindow.cs:4517` +
`PlayerMovementController.cs:593`); DEV-4 rewritten per its refutation.