MP: FIX walk+turn peer skip -- incremental heading integration + scalar yaw mirror (task #50)

The user-keyboard regime (steering WHILE walking) fired BOTH dense record streams
at once and exposed the last divergence: our peer heading used the engine
Mover::DeadReckon slerp-toward-projection, whose angular projection reads the
SHARED lastUpdate/nextUpdate timebase.  The dense type-0 pose stream resets that
timebase every frame while walking while RESTORING a stale orientation (the
authentic case-0 strip, verified against FUN_004a1232 case 0) -- so the angular
target barely advances from a stale base and the slerp DRAGS the heading back
every frame.  Measured: peer yaw advancing at ~40% rate with half the frames
stepping BACKWARD.  Pure-spin and pure-walk tests never showed it (single
stream) -- why autonomous looked smooth while keyboard play skipped.

AUTHENTIC FIX (decomp FUN_004ab1c8 -> FUN_004ab188/FUN_00409f58): the original
replicant integrates its heading INCREMENTALLY from the CURRENT pose -- exact
rotation of (replicated yaw rate * dt) composed on each frame -- and re-anchors
on type-4 receipt.  It never slerps toward a projected angular target.
 - mech4.cpp peer branch: save heading, let DeadReckon own LINEAR only, then
   integrate heading incrementally (ReconQuatIntegrate); on angSyncLatch (new
   type-4) re-anchor to updateOrigin.
 - mech.hpp/mech.cpp: angSyncLatch member (angular analog of poseSyncLatch),
   armed by ReadUpdateRecord case 4.
 - SCALAR peer-yaw mirror (angMirrorYaw/Rate/Time, re-based in the type-4
   writer): replaces the quaternion projectedOrigin mirror for the ANGLE
   deadband -- the old one was recomputed each frame by the master's own
   reckoner from timing it does not control and false-fired in pi-waves
   (measured maxAng~=pi bursts -> periodic resync floods).
 - Dense-rot type-4 send REMOVED (was masking the old crude projection; not
   authentic; churned the shared horizon).  Orientation now rides the sparse
   angle/velocity deadband resyncs exactly as the binary's.

Verified live-autonomous:
 - pure spin: 59/59 perfectly regular peer yaw steps; master resyncs 0/s with
   mirror drift ~5e-7 (records near-silent, authentic sparse model).
 - walk+turn circle (the user regime): peer sim yaw monotonic at exactly the
   master's rate (0.00556/frame @ 0.327 rad/s), no backward steps, no stalls.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-14 18:52:15 -05:00
co-authored by Claude Opus 4.8
parent b7be95b584
commit d78e77bf84
3 changed files with 83 additions and 47 deletions
+14
View File
@@ -618,6 +618,20 @@ public:
Scalar updatePositionDeadband; // binary @0x768 -- type-0 pose trigger
Scalar updateTurnVelocityDeadband; // binary @0x76c -- type-4 yaw-rate trigger
Scalar updateTurnAngleDeadband; // binary @0x770 -- type-4 orientation trigger (rad)
// SCALAR peer-yaw mirror (port addition, replicant-spin work): the master's
// estimate of the yaw the PEER is currently rendering -- re-based on every
// type-4 send (writer case 4), advanced analytically as base + rate*elapsed.
// Replaces the quaternion projectedOrigin mirror for the ANGLE deadband: that
// one is recomputed by the master's own reckoner each frame from lastUpdate
// timing it does not control, and its false pi-drift waves FLOODED type-4
// resyncs (measured maxAng~=pi bursts). Scalars, wrap-safe, self-timed.
Scalar angMirrorYaw; // yaw at the last type-4 send (rad)
Scalar angMirrorRate; // yaw rate sent with it (rad/s)
Time angMirrorTime; // lastPerformance at that send
int angMirrorValid; // 0 until the first type-4 send
int angSyncLatch; // peer: type-4 arrived -> re-anchor heading (the
// angular analog of poseSyncLatch; consumed by
// the replicant's incremental heading integrator)
// AUTHENTIC GROUND MODEL ctor products (task #15, ground-model-decode;
// binary part_012.c:9938-9940 + 9974-9975). By-name access only; declared
// after the layout-locked fields so nothing shifts.