#82 FINAL LAYER: the peer body-channel trn-lock -- a circling limper skated because the peer's turn-arm had no walk-demand yield and the trn speed exit read a dead replicant mapper cell

The master limped clean (218x gimp-cycle records, zero trn) -- a _ReturnAddress
trap on SetAnimationState(4) proved ALL peer trn arming came from the port's own
mech4 turn-step block, not the type-3 reader.  Two dead ends, one root:
- mech4 peer arm: gated on !wantsWalk (standSpeed < bodyTargetSpeed), exits trn
  when walking demand appears -- the leg twin's authentic precedence
  (part_012.c:12013, the Standing speed test outranks the turn test).
- mech2 body case 4: bspd reads bodyTargetSpeed on ReplicantInstance; the local
  mapper's speedDemand is a dead cell on a peer (reads 0 forever -> no exit).
Verified 2-node timeline: arena circle replicant 218x state-24 / 0x state-4
(was 116x trn churn), grass circle 235-clean, knockdowns bounded, 0 deaths.
Diagnostics kept: BT_TRNTRAP ra-trap, BT_ANIMIND_CAP, [gimpfeed], [replgimp]
extension.  KB: locomotion.md trn-lock entry + the dead-mapper-cell lesson.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QRjrTQpJd6u9XyfnUbTB3v
This commit is contained in:
Joe DiPrima
2026-07-30 18:26:15 -05:00
co-authored by Claude Fable 5
parent 14ff3519ac
commit e91d447405
8 changed files with 231 additions and 15 deletions
+15 -3
View File
@@ -2436,10 +2436,19 @@ void
const int bs = (int)bodyStateAlarm.GetLevel();
const bool turning = (replMppr->turnDemand > 0.05f
|| replMppr->turnDemand < -0.05f);
if (turning && bs == 0) // standing + turning -> enter turn
// YIELD TO WALK DEMAND (#82 trn-lock): the master only sits in
// trn when its commanded speed is at stand (the leg Standing
// case's speed test wins first, part_012.c:12013). A circling
// LIMPER keeps full demand (bts~24) while its yaw rate reads as
// turning here -- ungated, this block pinned the peer in body
// case 4 (advance-only, no exit) forever = the skating. Mirror
// the leg twin's precedence: walking demand outranks the pivot.
const bool wantsWalk = (standSpeed < bodyTargetSpeed
|| bodyTargetSpeed < 0.0f /*reverse*/);
if (turning && bs == 0 && !wantsWalk) // standing pivot only
SetBodyAnimation(4);
else if (!turning && bs == 4) // turn stopped -> back to stand
SetBodyAnimation(0);
else if (bs == 4 && (!turning || wantsWalk))
SetBodyAnimation(0); // stand; case 0 walk-begins next tick
}
// GIMP routing (#78): a limping PEER runs the gimp machines too
// (the graphicAlarm level replicates with the damage state).
@@ -2456,6 +2465,9 @@ void
s_ga = 0.0f;
DEBUG_STREAM << "[replgimp] ent=" << (int)GetEntityID()
<< " gl=" << replGl
<< " bts=" << bodyTargetSpeed
<< " standSpeed=" << standSpeed
<< " bodyState=" << (int)bodyStateAlarm.GetLevel()
<< " sim=" << (int)GetSimulationState()
<< " hasClips=" << hasGimpClips << " zones:";
for (int zi = 0; zi < damageZoneCount; ++zi)