#137 ("respawn came back with MYOMERS heat MAXED", Oracle; "overheating generator D", Sauron) sent us through a full two-sided audit of Mech::Reset and the whole RTIS chain. Both sides were correct. The answer was in the field log all along, one line after the reset: [respawn] Mech::Reset 3:30 healed+moved to (...) alive=1 [techstat] ... every live condition CLEARED [techstat] Myomers condition 3 SET <- Overheating, immediately [mppr] in thr=1 -> ... [gaitSM] cycleSpeed=14.6 state=12 <- already RUNNING [techstat] Condenser5 condition 3 SET <- "dumping into coolant loop 5" [techstat] GeneratorD condition 3 SET <- Sauron's generator D The mech respawns STILL UNDER POWER and earns the heat honestly. Two facts close it: 1. condition 3 is an OPERATING flag, not an alarm. Census over one match: LLaser_2 33 SET / 33 CLEARED, LLaser_1 31/31, SRM4 26/26, PPC_2 18/18 -- every volley trips it and clears it. EVERY subsystem is balanced (GeneratorD 5/4, Myomers 5/4, Condenser5 1/1; the extra SET is only the log ending mid-heat). cond 6 BadPower behaves the same (Myomers 8/8). Nothing latches. A post-respawn SET is not evidence of anything. 2. Mech::Reset's subsystem loop starts at index 2 and the ControlsMapper is index 0, so the throttle is never reset -- and the BINARY does the same. That is right for a pod: the throttle is a PHYSICAL lever still under the pilot's hand. Respawning under power is authentic and stays. Oracle's read that the myomer heat rate "felt right" was correct. WHAT IS a real defect (#146), desktop only: the glass bridge merely EMULATES that lever, with the static ramp accumulator sLever (mech4.cpp:3250) zeroed ONLY by the X all-stop and a direction-crossing snap. A pad/keyboard pilot is physically holding nothing and cannot see the lever, so they respawned at speed for no reason they could perceive -- and ate the heat load above. The Thrustmaster/RIO path was never affected: InterpretControls (@004d2150) rebuilds throttlePosition every frame from the databound throttleForward. Fix: queue the existing all-stop at Mech::Reset, reusing the proven path (it already clears the zero-crossing detent too). LOCAL VIEWPOINT MECH ONLY -- gBTDrive is the local bridge's state and Reset also runs for replicants, so an ungated write would all-stop the player whenever a REMOTE mech respawned. Pod-safe besides: with a RIO present the key bridge is off and gBTDrive.throttle is never read. BT_NO_RESPAWN_THROTTLE_RELEASE=1 reverts. Benched 2-node (scratchpad/night13/throttlerespawn.sh): the release fires 1:1 with local respawns on both nodes independently (A 2/2, B 1/1) and never spuriously. HONEST LIMIT: the viewpoint gate was NOT stressed -- B ran Mech::Reset 0 times for A's mech, so the remote-respawn path never fired. The gate is correct by construction (the isPlayerMech idiom), not proven. BT_AUTODRIVE cannot test the lever itself (forced mode reads forcedThrottle, never sLever), and the zeroing path is the X button, proven in the field. Also keeps BTReportHeatAtReset (heat.cpp, BT_HEAT_LOG): the [heat-t] census runs on a 5s timer, far too coarse to sample AT the reset. It is what proved every roster subsystem including all six Condensers sits at T=77 start=77, and it corrected an earlier false negative from filtering on IsDerivedFrom(HeatSink). KB: context/decomp-reference.md gains the routine/self-clearing condition semantics + this post-mortem, so it is not re-chased; cross-ref in context/gauges-hud.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SgmXGNMXavXiafKXf9MDC
69 lines
3.2 KiB
Bash
69 lines
3.2 KiB
Bash
#!/usr/bin/env bash
|
|
# =========================================================================
|
|
# #146 -- desktop virtual throttle must be RELEASED on respawn.
|
|
#
|
|
# The pod's throttle is a physical lever and Mech::Reset deliberately leaves
|
|
# it alone (subsystem loop starts at index 2; ControlsMapper is index 0) --
|
|
# authentic, kept. The desktop bridge only EMULATES that lever with the
|
|
# static ramp accumulator sLever, so a pad/keyboard pilot respawned at speed
|
|
# while holding nothing. Fix: queue the existing all-stop at Mech::Reset,
|
|
# LOCAL VIEWPOINT MECH ONLY.
|
|
#
|
|
# WHAT THIS BENCH ACTUALLY TESTS. It does NOT test "does zeroing sLever
|
|
# stop the mech" -- that path is the X all-stop button, proven in the field
|
|
# every day, and BT_AUTODRIVE cannot exercise it anyway (forced mode reads
|
|
# gBTDrive.forcedThrottle, never sLever -- mechmppr.cpp:677).
|
|
#
|
|
# It tests the one thing the fix could genuinely get WRONG: the viewpoint
|
|
# gate. Mech::Reset also runs for REPLICANTS, so an ungated write to the
|
|
# global gBTDrive would all-stop the local player every time a REMOTE mech
|
|
# respawned -- a far worse bug than the one being fixed.
|
|
#
|
|
# PASS: A (who dies) logs "[respawn] desktop throttle released" once per
|
|
# Mech::Reset, and B logs it ZERO times while A is respawning.
|
|
# FAIL: any occurrence in B's log -> the gate leaks and remote respawns
|
|
# stop the local pilot.
|
|
#
|
|
# A self-damages to death on a timer; B just flies and watches.
|
|
# =========================================================================
|
|
set -x
|
|
. /c/git/bt411/scratchpad/night6/bench_common.sh
|
|
cd /c/git/bt411/content || exit 1
|
|
taskkill //F //IM btl4.exe > /dev/null 2>&1
|
|
sleep 2
|
|
rm -f tr_a.log tr_b.log tr_relay.log
|
|
bt_expert_egg MP.EGG TR.EGG
|
|
sed -i "s/^map=.*/map=grass/; s/^time=.*/time=day/; s/^vehicle=.*/vehicle=madcat/" TR.EGG
|
|
|
|
# B: the OBSERVER. Also driving, so a leaked all-stop would be doubly visible.
|
|
( export BT_AUTODRIVE=0.6
|
|
export BT_DEATH_LOG=1 BT_MP_LOG=1 BT_KEY_LOG=1
|
|
bt_launch tr_b.log TR.EGG 0x0C -net 1601 )
|
|
sleep 2
|
|
# A: drives, dies repeatedly, respawns.
|
|
( export BT_AUTODRIVE=0.8 BT_SELF_DAMAGE=8
|
|
export BT_DEATH_LOG=1 BT_MP_LOG=1 BT_KEY_LOG=1
|
|
bt_launch tr_a.log TR.EGG 0x03 -net 1501 )
|
|
sleep 5
|
|
python ../tools/btconsole.py TR.EGG 127.0.0.1:1501 127.0.0.1:1601 > tr_relay.log 2>&1 &
|
|
RELAY=$!
|
|
sleep 280
|
|
kill $RELAY 2>/dev/null
|
|
sleep 3
|
|
bt_kill_ours; sleep 2; taskkill //F //IM btl4.exe > /dev/null 2>&1; sleep 3
|
|
|
|
echo "=================== #146 THROTTLE RELEASE ON RESPAWN ==================="
|
|
echo "--- A: how many respawns, how many releases? (must be 1:1) ---"
|
|
echo -n " A Mech::Reset .......... "; grep -ac "Mech::Reset" tr_a.log
|
|
echo -n " A throttle released .... "; grep -ac "desktop throttle released" tr_a.log
|
|
echo
|
|
echo "--- B: the VIEWPOINT GATE. Must be 0 releases despite seeing A respawn. ---"
|
|
echo -n " B Mech::Reset (incl. replicant) .... "; grep -ac "Mech::Reset" tr_b.log
|
|
echo -n " B throttle released (MUST BE 0) .... "; grep -ac "desktop throttle released" tr_b.log
|
|
echo
|
|
echo "--- A: the release must sit INSIDE the reset block ---"
|
|
grep -aE "Mech::Reset|desktop throttle released" tr_a.log | head -8
|
|
echo
|
|
echo "--- B: same window, to show B saw the respawn and still did not release ---"
|
|
grep -aE "Mech::Reset|desktop throttle released" tr_b.log | head -8
|