/investigate deliverable for the inbound (remote-entity) animation+position
retail-parity effort. 10 deviations (DEV-1..10) mapped and adversarially
verified against the named retail decomp + ACE port + current code (9
confirmed, 1 refuted-and-corrected).
Headline: the #39-era UP-pace->cycle inference layer's premise ('wire goes
silent on Shift toggle') is refuted at both oracles — retail sends a fresh
MoveToState on HoldRun toggle while moving (0x006b37a8) and ACE rebroadcasts
every MoveToState unconditionally (GameActionMoveToState.cs:36); retail has
NO pace->animation adaptation anywhere (position error is absorbed solely by
the InterpolationManager chase, already ported verbatim in L.3).
Registers sub-lane L.2g in the roadmap: port the CMotionInterp inbound funnel
verbatim for all remote entity classes, slices S0-S6.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
92 lines
22 KiB
Markdown
92 lines
22 KiB
Markdown
# Claim map: inbound motion/animation research vs current code
|
||
|
||
Date: 2026-07-02. Repo (worktree): `C:/Users/erikn/source/repos/acdream/.claude/worktrees/vigorous-joliot-f0c3ad`
|
||
(branch `claude/vigorous-joliot-f0c3ad`, HEAD `b60b9b4a`).
|
||
|
||
**Path note:** `docs/research/2026-06-04-animation-sequencer-deep-dive.md` does NOT
|
||
exist in this worktree or in git history at all (it is an *untracked* file only
|
||
in the main checkout `C:/Users/erikn/source/repos/acdream/docs/research/...`).
|
||
It was never committed. Read directly from that absolute path for this audit.
|
||
The other two docs (`2026-06-26-movement-animation-retail-parity-audit.md`,
|
||
`2026-07-01-d6-motion-interp-pseudocode.md`) exist and are committed in this
|
||
worktree.
|
||
|
||
---
|
||
|
||
## Doc 1: 2026-06-04-animation-sequencer-deep-dive.md (8 ranked divergences)
|
||
|
||
| # | Claim (doc anchor) | Current-code check | Status | Evidence (file:line) |
|
||
|---|---|---|---|---|
|
||
| 1 | Missing `pending_motions`/`MotionDone` chain (MotionInterp, HIGH). `add_to_queue` + `CheckForCompletedMotions` unimplemented. Affects multi-step action sequences, combo attacks, `UpdateMotion Commands[]` action chains. (doc anchor: "Divergences ranked" #1, L1242-1247) | Grepped `MotionInterpreter.cs`/`AnimationSequencer.cs` for `pending_motions`/`MotionDone`/`CheckForCompletedMotions`/`add_to_queue` — only comment references (`FUN_00510900 — CheckForCompletedMotions (animation flush, not simulated here)`, `FUN_00528790(…) — add_to_queue`). No queue data structure, no `MotionDone` event. | **STILL-TRUE** | `src/AcDream.Core/Physics/MotionInterpreter.cs:399,412,558` (comments only, no impl) |
|
||
| 2 | `contact_allows_move` level mismatch (MotionInterp, HIGH). acdream blocks Fallen/Dead/Crouch-range inside `contact_allows_move` itself; retail does this at `DoMotion` level with distinct error codes. (doc anchor: "Divergences ranked" #2, L1249-1253) | Read `contact_allows_move` body: still explicitly checks `fwd == MotionCommand.Fallen \|\| fwd == MotionCommand.Dead` and the crouch/sit/sleep range, returning `false` (blocked) directly from this function — exactly the divergence described. | **STILL-TRUE** | `src/AcDream.Core/Physics/MotionInterpreter.cs:1081-1107` (see lines 1092-1099 for the Fallen/Dead/Crouch block) |
|
||
| 3 | `re_modify` not implemented after cycle rebuild (CSequence, MEDIUM). Stacked Modifier motions (combat stance overlays) lose velocity/omega contribution on cycle switch. (doc anchor: "Divergences ranked" #3, L1255-1260) | Grepped `AnimationSequencer.cs` for `re_modify`/`ReModify`/`ModifierList`/`_activeModifiers` — zero hits. | **STILL-TRUE** | `src/AcDream.Core/Physics/AnimationSequencer.cs` (no match found for the term at all) |
|
||
| 4 | `TransparentHook` fires as instant snap vs smooth lerp (anim-hooks, MEDIUM). No `FPHook` time-interpolation equivalent. (doc anchor: "Divergences ranked" #4, L1262-1266) | Not directly re-verified this session (out of scope for walk/run + stop-slide focus — this is a fade/translucency concern, not motion/position). | **COULD-NOT-VERIFY** (not checked; low relevance to task's (a)/(b)/(c) scope beyond "(c) inbound animation machinery generally") | n/a |
|
||
| 5 | `direction_` default `0xFFFFFFFE` vs `AnimationHookDir.Both` (anim-hooks, LOW). Dat-baked hooks with missing/zero direction may fire when retail would never fire them. (doc anchor: "Divergences ranked" #5, L1268-1272) | Not re-verified this session — orthogonal to motion/position, low priority. | **COULD-NOT-VERIFY** | n/a |
|
||
| 6 | Legacy entity path has no hook dispatch (anim-hooks, LOW-MEDIUM), at old `GameWindow.cs:8563-8573`. (doc anchor: "Divergences ranked" #6, L1274-1277) | Not re-verified — line numbers are 2026-06-04-vintage and GameWindow.cs has grown/shifted substantially (now 13,759 lines vs whatever it was then); the cited range is very likely stale. | **STALE-ANCHOR** (line numbers unverified/likely shifted; concept not re-checked) | n/a |
|
||
| 7 | `enter_default_state` not called on spawn (MotionInterp, LOW). No `InitializeMotionTables`/pending_motions Ready-node seeding at spawn. (doc anchor: "Divergences ranked" #7, L1279-1282) | Grepped `MotionInterpreter.cs` for `enter_default_state`/`EnterDefaultState`/`InitializeMotionTables` — zero hits. | **STILL-TRUE** | `src/AcDream.Core/Physics/MotionInterpreter.cs` (no match) |
|
||
| 8 | `StandingLongJump` path not called per-tick (MotionInterp, LOW). The standing-long-jump pre-jump pose sub-state exists as a flag but `apply_interpreted_movement`'s per-tick branch (Ready + StopSideStep) is not wired. (doc anchor: "Divergences ranked" #8, L1284-1287) | `StandingLongJump` field exists and is set/cleared in a few places (`MotionInterpreter.cs:328,941,1119,1146`) but no per-tick `apply_interpreted_movement`-style dispatch was found calling `DoInterpretedMotion(Ready)` + `StopInterpretedMotion(SideStepRight)` from the flag. Also confirmed D3 in doc 2 (MoveToState longjump bit) is now WIRED on the *outbound* wire side (`standingLongjump` param exists in `MoveToState.Build`), but that's the wire byte, not the per-tick animation branch this claim is about — those are different things. | **STILL-TRUE** (the per-tick animation branch is still not called; note the wire-side `standingLongjump` param now exists as an input but nothing sets it to true from a live per-tick standing-longjump detection) | `src/AcDream.Core/Physics/MotionInterpreter.cs:328,941,1119,1146` (flag only, no per-tick apply path); cf. `src/AcDream.Core.Net/Messages/MoveToState.cs:56-70` (wire param exists but is a pass-through, always `false` by default) |
|
||
| 9 (supporting) | Remote-entity path dispatches via direct `SetCycle` call from `GameWindow.OnLiveMotionUpdated`, NOT via `move_to_interpreted_state` (executive summary + divergence #5/#9 in the MotionInterp section, L303-317). | Confirmed: `move_to_interpreted_state`/`MoveToInterpretedState` still does not exist anywhere except one comment reference. `OnLiveMotionUpdated` still directly manipulates `ae.Sequencer` (`SetCycle`) and does a raw bulk-copy into `remoteMot.Motion.InterpretedState.ForwardCommand/ForwardSpeed` — bypassing `adjust_motion` for remotes entirely. This is THE central mechanism relevant to the walk<->run-lag symptom: the D6-ported `adjust_motion`/`apply_raw_movement`/`get_state_velocity` triad is **local-player-only** (see doc-3 cross-check below). | **STILL-TRUE** (confirmed, and directly load-bearing for the task's (a)/(c) focus) | `src/AcDream.App/Rendering/GameWindow.cs:4517` (comment only ref to move_to_interpreted_state); `GameWindow.cs:4590,4598` (direct bulk-copy into InterpretedState, bypassing adjust_motion); `GameWindow.cs:4327-4492` (SetCycle-direct dispatch) |
|
||
| 10 (supporting) | acdream's remote velocity path bypasses `apply_current_movement` gating differences: acdream calls `PhysicsObj.OnWalkable` gate directly rather than the full retail contact/gravity flow (MotionInterp section divergence #3, L305). | `apply_current_movement` (used by BOTH local and remote via `rm.Motion.apply_current_movement` calls) still gates on `PhysicsObj.OnWalkable` directly and calls `get_state_velocity()` — same shape as described. | **STILL-TRUE** | `src/AcDream.Core/Physics/MotionInterpreter.cs:890-910`; called for remotes at `GameWindow.cs:10042,10074` |
|
||
|
||
---
|
||
|
||
## Doc 2: 2026-06-26-movement-animation-retail-parity-audit.md (D1-D12)
|
||
|
||
| # | Claim (doc anchor) | Current-code check | Status | Evidence (file:line) |
|
||
|---|---|---|---|---|
|
||
| D1 | MoveToState raw flags not retail — presence-based instead of default-difference packing; overs-sends default values. (doc L118-130) | `MoveToState.cs` doc header now explicitly says "default-difference flags dword + conditional fields + actions" and `RawMotionState.Default` exists with retail defaults (`CurrentHoldKey=None`, `ForwardCommand=0x41000003`, `ForwardSpeed=1.0`, etc. matching doc's retail defaults table L60-72). Shipped as part of L.2b (`78e163a4`, 2026-06-30). | **CLOSED-SINCE** | `src/AcDream.Core.Net/Messages/MoveToState.cs:22`; `src/AcDream.Core/Physics/RawMotionState.cs:44-58` |
|
||
| D2 | RawMotionState action-list and style packing incomplete — no full action-list packing, current-style scenarios. (doc L132-136) | `RawMotionState` now has `Actions` (IReadOnlyList<RawMotionAction>) with a doc comment describing retail's `num_actions` bits 11-15 packing. Appears substantially addressed as part of L.2b, though full conformance vs the bitfield layout (11 one-bit flags + num_actions:5) was not independently re-verified byte-for-byte this session. | **CLOSED-SINCE** (structure now present; exact bit-packing not re-verified) | `src/AcDream.Core/Physics/RawMotionState.cs:57-63` |
|
||
| D3 | MoveToState longjump bit not modeled — only contact 0/1 passed, `standing_longjump` not wired as named state. (doc L138-147) | `MoveToState.Build` now has a `standingLongjump` parameter and packs `trailing = (byte)((standingLongjump ? 0x02 : 0) \| (contact ? 0x01 : 0))` — matches doc's described retail byte layout. NOTE: the parameter is wired as an INPUT but this session did not verify any call site sets it to `true` from a live per-tick standing-longjump detection (see doc-1 item #8 above — the per-tick animation branch driving this flag is still missing). So the WIRE FORMAT is fixed; whether it's ever populated correctly is a separate, still-open question. | **CLOSED-SINCE** (wire format only; upstream detection still absent) | `src/AcDream.Core.Net/Messages/MoveToState.cs:56-70,100-101` |
|
||
| D4 | JumpAction packet layout retail-incompatible — missing full Position, extra objectGuid/spellId fields, wrong order. (doc L149-161) | `JumpAction.cs` doc header now cites `Position::Pack (0x005a9640)` and explicitly notes the fix: "the pre-slice code had it backwards (two spurious trailing zero u32s, no Position at all)" — confirms this was found and fixed as part of L.2b. | **CLOSED-SINCE** | `src/AcDream.Core.Net/Messages/JumpAction.cs:21-31` |
|
||
| D5 | Position heartbeat close but not fully proven — `NotePositionSent` stamps all three (time/position/contact-plane) on BOTH MTS and AP paths, but retail's `SendMovementEvent` (MTS) only stamps `last_sent_position_time`; only `SendPositionEvent` (AP) stamps all three. (doc L163-169) | Confirmed STILL live and explicitly re-audited: a 2026-06-30 dated comment at the MTS send site says verbatim "this is a real, audit-confirmed divergence from retail... left UNCHANGED; reported to the lead engineer instead of fixed here." This is the most concrete, freshest confirmation in the whole audit — it was re-checked via Ghidra decompile-by-address and deliberately NOT fixed. | **STILL-TRUE** (explicitly re-confirmed and deliberately deferred, not a stale claim) | `src/AcDream.App/Rendering/GameWindow.cs:8320-8339` |
|
||
| D6 | MotionInterpreter lacks canonical retail raw→interpreted normalization (`adjust_motion`, `apply_run_to_command`, `apply_raw_movement` not ported); SideStepLeft/WalkBackward produce zero velocity; jump lateral velocity hand-patched. (doc L171-182) | **This is exactly what Doc 3 (D6 pseudocode doc) documents as SHIPPED** for the local player. Confirmed present: `adjust_motion` (`MotionInterpreter.cs:741`), `apply_run_to_command` (`:805`), `apply_raw_movement` (`:848`), `get_state_velocity` (`:639`) all exist and are called from `PlayerMovementController.cs:909,974,1014`. | **CLOSED-SINCE** (for LOCAL player only — see D7 below, this does NOT extend to remotes) | `src/AcDream.Core/Physics/MotionInterpreter.cs:639,741,805,848`; `src/AcDream.App/Input/PlayerMovementController.cs:880-1014` |
|
||
| D7 | Animation application split from retail motion flow — `AnimationSequencer` has useful pieces but `MotionInterpreter.apply_current_movement` is velocity-oriented and doesn't drive animation state through retail's order (style/forward/sidestep/turn/actions sequencing). (doc L184-188) | **THE central claim for the task's (a)/(c) focus.** Confirmed still true and now MORE precisely characterized: for remotes, `OnLiveMotionUpdated` bulk-copies `ForwardCommand`/`ForwardSpeed` directly into `InterpretedState` (bypassing `adjust_motion`), AND separately calls `ae.Sequencer.SetCycle(...)` directly for the visual cycle — two parallel, only loosely-coupled paths (one drives position/velocity via `apply_current_movement`→`get_state_velocity`, the other drives the visual cycle via `SetCycle`). Neither goes through `apply_interpreted_movement`'s full style/forward/sidestep/turn sequencing. Additionally there is a SEPARATE `ApplyServerControlledVelocityCycle`/`ApplyPlayerLocomotionRefinement` mechanism (UP-velocity-derived, with a 200ms UM grace window + 4.5/5.5 m/s hysteresis bucketing) that ALSO writes `SetCycle` for the local-player-observed-remotely case — this is a THIRD parallel path, not documented in either research doc, that is very likely a major contributor to "walk<->run reacts too slowly" (its grace window + hysteresis band means a walk<->run toggle needs velocity to cross a threshold via UpdatePosition samples before the visual cycle re-buckets, since a UM may not arrive for HoldKey-only toggles per the code's own comments). | **STILL-TRUE** (confirmed and refined — root mechanism now identified precisely, more detailed than the original doc knew) | `src/AcDream.App/Rendering/GameWindow.cs:4590,4598` (bulk-copy bypass); `GameWindow.cs:5112-5176` (`ApplyServerControlledVelocityCycle`); `GameWindow.cs:5178-5300+` (`ApplyPlayerLocomotionRefinement`, grace/hysteresis constants at `:5095,5104,5110`) |
|
||
| D8 | Force-walk and MoveTo are approximations — `ServerControlledLocomotion`, `RemoteMoveToDriver`, `PlayerMovementController.BeginServerAutoWalk` approximate steering/cycle selection vs retail's full `MoveToManager` queue (pre-turn, move, aux turn, final heading, sticky targeting, progress failure, `MovementParameters::get_command`). (doc L190-196) | `ServerControlledLocomotion.cs` is still only 87 lines (a `PlanMoveToStart`/`PlanFromVelocity` helper, not a queued state machine). No pre-turn/aux-turn/sticky-target/progress-failure machinery found. | **STILL-TRUE** | `src/AcDream.Core/Physics/ServerControlledLocomotion.cs` (87 lines total); `src/AcDream.Core/Physics/RemoteMoveToDriver.cs` (340 lines, still a simplified steering helper) |
|
||
| D9 | Inbound movement types 8 (TurnToObject) and 9 (TurnToHeading) dropped — `UpdateMotion` handles interpreted state and MoveTo 6/7 but not 8/9. (doc L198-207) | Confirmed: `UpdateMotion.TryParse` only branches on `movementType == 0` and `movementType is 6 or 7`; no `8`/`9` case anywhere. Grep for `TurnToObject`/`TurnToHeading` across `UpdateMotion.cs` and `GameWindow.cs` returns zero hits. The 2026-07-02 handoff doc explicitly reconfirms this live: "CONFIRMED live: mt=0x09 arrives and just SetCycle(Ready) instead of turning." | **STILL-TRUE** (independently re-confirmed via grep + corroborated by a live capture cited in the handoff doc) | `src/AcDream.Core.Net/Messages/UpdateMotion.cs:136-238` (no case 8/9) |
|
||
| D10 | Spawn-time movement state weaker than live — `CreateObject` detects movement types/flags but doesn't preserve full MoveTo target/origin/threshold data the way `UpdateMotion` does. (doc L209-213) | Confirmed with exact detail: `CreateObject.TryParseMoveToPayload` (private, 3-out-param overload: `movementParameters`, `speed`, `runRate`) SKIPS Origin/distanceToObject/minDistance/failDistance/walkRunThreshold/desiredHeading via `pos +=` advances with no output — so `CreateObject`'s returned `ServerMotionState.MoveToPath` is always `null`. By contrast `UpdateMotion.TryParseMoveToPayload` (a DIFFERENT, more complete overload) DOES populate `out CreateObject.MoveToPathData? path` with Origin/thresholds. Two parsers of the same wire shape, one materially weaker. | **STILL-TRUE** (confirmed with precise mechanism: two divergent parser overloads for the same MoveTo payload) | `src/AcDream.Core.Net/Messages/CreateObject.cs:1194-1226` (weak 3-field overload, spawn path) vs `src/AcDream.Core.Net/Messages/UpdateMotion.cs:255-331` (full path-populating overload, live-update path) |
|
||
| D11 | Sequence/autonomy data parsed then discarded — retail carries movement sequence, server-control sequence, autonomous state, motion flags, position sequence into movement application; acdream exposes only a subset. (doc L215-219) | Confirmed: `UpdateMotion.TryParse` still does a blind `pos += 6` skip over `movementSequence`(u16) + `serverControlSequence`(u16) + `isAutonomous`(u8) + align — none of these three fields are captured into the `Parsed` record or `ServerMotionState`. (Note: `WorldSession.cs` DOES track `_serverControlSequence`/`_instanceSequence`/etc., but those are the OUTBOUND sequence counters sourced from `UpdatePosition`, not the INBOUND per-entity `UpdateMotion` fields this claim is about — different mechanism entirely, do not conflate.) `_motionFlags` (byte) is read into a local var and never used beyond that line either. | **STILL-TRUE** (confirmed, and clarified that the WorldSession sequence counters some might assume closes this are unrelated) | `src/AcDream.Core.Net/Messages/UpdateMotion.cs:89-106` (skip), `:111` (`_motionFlags` read, unused past declaration) |
|
||
| D12 | Jump/falling/contact gates simplified — retail allows specific movement while falling/dead, has separate jump checks for posture/stamina/constraints/pending-motion/contact/leave-hit-ground reapplication; acdream blocks or simplifies several. (doc L221-225) | Not exhaustively re-verified line-by-line this session (large surface). Spot-checked `contact_allows_move`/`motion_allows_jump`-equivalent: the Fallen/Dead/Crouch block still lives inside `contact_allows_move` (see doc-1 item #2), which is itself evidence the gates remain simplified/misplaced relative to retail's `DoMotion`-level error codes. No `pending_motions`-driven jump eligibility check found (consistent with item #1). | **STILL-TRUE** (partially re-verified via the contact_allows_move overlap with doc-1 #2; full jump/posture/stamina gate audit not redone) | `src/AcDream.Core/Physics/MotionInterpreter.cs:1081-1107` (same evidence as doc-1 #2) |
|
||
|
||
---
|
||
|
||
## Doc 3: 2026-07-01-d6-motion-interp-pseudocode.md — cross-check of its own claims
|
||
|
||
| Claim | Current-code check | Status |
|
||
|---|---|---|
|
||
| "D6 ships `adjust_motion`/`apply_run_to_command`/`apply_raw_movement`/`get_state_velocity` in `MotionInterpreter.cs`, unifying LOCAL player velocity+turn+jump+wire onto one `RawMotionState` at `forward_speed=1.0`" | Confirmed via git log (`0f099bb6` D6.2a, `d34721fa` D6.2b) and via direct code read — all four functions exist and are wired into `PlayerMovementController.cs` only. | **STILL-TRUE (as scoped)** |
|
||
| "Out of scope for D6: RawMotionState unification — retail uses ONE raw state for both the wire and the velocity pipeline; D6 keeps the L.2b wire construction separate... unifying is a later slice" (doc L153-156) | This scoping statement is itself accurate and still holds: the wire-side `RawMotionState`/`MoveToState.Build` path and the local velocity-side `apply_raw_movement` input are DIFFERENT `RawMotionState` construction sites (confirmed by design decision #1 in the doc itself, "ONE `RawMotionState`... is built from `MovementInput`" — but this unification was the D6.2 GOAL for local-only; there is still no unification with the REMOTE/inbound path at all). | **STILL-TRUE (scoping honored, and the doc's own "later slice" is exactly the gap this task's handoff doc targets)** |
|
||
| "Out of scope for D6: turn ... acdream keeps direct-Yaw turn is replaced" / actually turn WAS ported per design decision #3 ("Turn ported to interpreted, feel unchanged... omega.Z = ±(π/2) × turn_speed... the fixed TurnRateFor direct-Yaw is replaced by the pipeline") — LOCAL only. | For remotes, `RemoteMoveToDriver.TurnRateFor` is still the mechanism (per doc's own "AP-9 stays" note) — confirmed no remote-side `adjust_motion`-sourced turn omega found; `RemoteMoveToDriver.cs` (340 lines) still exists with its own turn-rate logic, separate from `MotionInterpreter`. | **STILL-TRUE (remote turn is still the old direct-rate approximation; local turn was ported per D6 but that's a different code path)** |
|
||
|
||
---
|
||
|
||
## Synthesis: what this means for the walk<->run lag + stop-slide symptom (task focus a/b)
|
||
|
||
1. **D6 (the shipped port) does not touch the remote/inbound path at all.** Every function it
|
||
ported (`adjust_motion`, `apply_run_to_command`, `apply_raw_movement`, `get_state_velocity`)
|
||
is called exclusively from `PlayerMovementController.cs` (local player). Zero call sites
|
||
from `GameWindow.cs`'s remote-entity code (`OnLiveMotionUpdated`, `_remoteDeadReckon`,
|
||
`ApplyServerControlledVelocityCycle`) invoke these D6-ported functions.
|
||
2. **The remote path bulk-copies wire commands directly into `InterpretedState`**
|
||
(`GameWindow.cs:4590,4598`), bypassing `adjust_motion` — so backward/sidestep-left
|
||
normalization and run-rate scaling never happen for remotes the retail-faithful way.
|
||
This matches the retail `copy_movement_from` bulk-copy semantics for THAT ONE STEP, but the
|
||
surrounding `pending_motions`/queue/`move_to_interpreted_state` state machine around it
|
||
(doc-1 items #1, #9) is still entirely absent.
|
||
3. **A newly-identified (not named in either doc) mechanism likely explains "reacts too
|
||
slowly":** `ApplyPlayerLocomotionRefinement` (`GameWindow.cs:5178+`) only kicks in after a
|
||
`UmGraceSeconds = 0.2` (200ms) window since the last UM, and then applies **hysteresis**
|
||
bands (`PlayerRunPromoteSpeed = 5.5f`, `PlayerRunDemoteSpeed = 4.5f`) before re-bucketing
|
||
walk↔run from UpdatePosition-derived velocity — this is architecturally exactly the kind of
|
||
mechanism that would produce a visible lag on a walk↔run toggle, especially combined with
|
||
the code's own comment that retail may not broadcast a fresh MoveToState for HoldKey-only
|
||
toggles (Shift while W held), forcing reliance on this slower velocity-inference path.
|
||
4. **D9 (types 8/9 dropped)** means any server-driven turn command mid-locomotion is silently
|
||
turned into a `SetCycle(Ready)`, which would visibly interrupt/desync locomotion — a
|
||
plausible contributor to "compounding error... running around + turning."
|
||
5. **D11 (sequence numbers discarded)** means acdream has no way to detect/reject
|
||
out-of-order or duplicate `UpdateMotion` packets, which is a plausible contributor to the
|
||
"position errors once the entity stops" (a late/duplicate packet could re-apply a stale
|
||
state after a newer one, with no sequence check to catch it).
|
||
|
||
None of the above is a fix recommendation — this is a raw claim/verification map only, per
|
||
the report-only investigation mode.
|