From 6a122f6cdf0c5ed6145e3a9755f6c19758ed8b8e Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Sun, 9 Aug 2026 12:18:59 -0500 Subject: [PATCH] #137: the post-respawn heat spike is VELOCITY-driven, not reset corruption Operator hypothesis tested: does something tick mid-reset and compute across half-reset values (the teleport discontinuity) and inject a heat slug? NOT SUPPORTED, measured. [myoheat] terms straddling a respawn: BEFORE (-334) v=10.7 kinetic= 21941 BEFORE (-116) v=18.8 kinetic= 59560 AFTER ( +17) v= 6.1 kinetic= 3517 <- SMALL at the discontinuity AFTER ( +129) v=46.7 kinetic=297349 AFTER ( +337) v=54.1 kinetic=399003 The sample immediately after the reset is small. Nothing computes across the teleport; there is no injected slug. WHAT IT ACTUALLY IS. work = mass * v^2 * 0.5, so heat is quadratic in speed. After a respawn the mech reaches v~50 against v~10-18 while fighting before it died -- roughly 9x the heat input -- because it comes back on open ground with nothing to fight and accelerates to top speed. That is why the earlier correlation looked like causation: temperature is highest just after a reset and decays with distance from it, but the driver is SPEED, not the reset. Reconciles both benches: 0.95-throttle runs overshoot, 0.50-throttle runs never approach failT, and the operator's point that ordinary gameplay feels fine holds -- at combat speeds the model behaves. It only runs away at sustained top speed. Term arithmetic checks out against the authored tuning: work = 75000 * 54^2 * 0.5 = 109.3e6 workComplement = 1 - VelocityEfficiency(0.995) = 0.005 termKinetic = 109.3e6 * 0.005 * (dt*28 = 0.728) = 398e3 (logged 399003) so the port is computing what it intends to. The open question is whether the INTENT is right -- i.e. whether (1 - 0.995) against the FULL kinetic energy is the authentic scaling, or whether the binary's dt-less per-frame add at the pod's fixed ~28 Hz means something different from our rate-normalised form at 100-170 fps. That is now a calibration question with a specific target, not a hunt. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018SgmXGNMXavXiafKXf9MDC --- scratchpad/night14/myofreeze_terms.sh | 88 +++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 scratchpad/night14/myofreeze_terms.sh diff --git a/scratchpad/night14/myofreeze_terms.sh b/scratchpad/night14/myofreeze_terms.sh new file mode 100644 index 0000000..3c95909 --- /dev/null +++ b/scratchpad/night14/myofreeze_terms.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# ========================================================================= +# #137 -- "respawns with the myomers overheated ... initially unable to move +# until it cools off" (Oracle, across several builds). +# +# WHY THE OLD BENCH PROVED NOTHING. heatrespawn.sh sampled AT the reset and +# found every heat-bearing subsystem at T == startingTemperature, so I closed +# #137 as not-a-bug. The field then measured the freeze at 5 of 61 respawns +# (~8%) across THREE machines -- throttle up, speedDemand pinned at 0. A +# bench that never reproduces the failure is not evidence the failure does not +# exist, which is the mistake that closed the ticket. +# +# WHAT THE DECOMP SAYS (re-read 2026-08-09): +# Mech::Reset @0049fb74 walks the roster from index 2 calling vtable +0x28 +# (slot 10 = ResetToInitialState) on each subsystem, then @0049f788. +# Myomers::RTIS @004b8aa4 -> PoweredSubsystem::RTIS @004b0e6c -> ALWAYS +# HeatSink::RTIS @004ad760, which does `param_1[0x45] = param_1[0x4f]` +# i.e. currentTemperature(@0x114) = startingTemperature(@0x13C). +# The freeze itself is the derating curve @004b8ac0: +# temp >= degradation(@0x118) -> falls off; temp >= FAILURE(@0x11C) -> 0.0 +# and 0.0 reaches the mover as the chain MAX -> speedDemand *= 0. +# CRUCIALLY: nothing in that reset chain touches Myomers::speedEffect +# (@0x31C). It keeps its pre-death value until the myomers next ticks. +# +# So three explanations survive, and only data separates them: +# (a) RESET DIDN'T TAKE -> post-reset T is high (>= fail) +# (b) STALE CACHE -> T is at start but speedEffect is still 0 +# ("<<<< STALE (cold but zero)" in the receipt) +# (c) INSTANT RE-HEAT -> T starts at start and climbs back immediately +# +# THE MEASUREMENT. Mech::Reset now arms a ~4 s post-reset trace sampled where +# the mover's multiplier is actually formed: +# [myofreeze] at-reset Myomers T=.. deg=.. fail=.. speedEffect=.. +# [myofreeze] post-reset Myomers T=.. deg=.. fail=.. speedEffect=.. +# [myofreeze] post-reset CHAIN MAX=0 <<<< FROZEN +# +# A drives hard (heat) and self-damages to death repeatedly, so deaths land on +# a HOT mech -- the field composition. Long run: at ~8% we need many respawns. +# ========================================================================= +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 mf137_a.log mf137_b.log mf137_relay.log +bt_expert_egg MP.EGG MF137.EGG +sed -i "s/^map=.*/map=grass/; s/^time=.*/time=day/; s/^vehicle=.*/vehicle=madcat/" MF137.EGG + +( export BT_DEATH_LOG=1 BT_MP_LOG=1 + bt_launch mf137_b.log MF137.EGG 0x0C -net 1601 ) +sleep 2 +# A: run hot (autodrive) + fire continuously (weapon heat) + die often. +( export BT_AUTODRIVE=0.95 BT_SELF_DAMAGE=7 + export BT_AUTOFIRE=1 BT_AF_MISSILE=1 BT_AF_PERIOD=4 + export BT_HEAT_LOG=1 BT_MYO_LOG=1 BT_DEATH_LOG=1 BT_MP_LOG=1 + bt_launch mf137_a.log MF137.EGG 0x03 -net 1501 ) +sleep 5 +python ../tools/btconsole.py MF137.EGG 127.0.0.1:1501 127.0.0.1:1601 > mf137_relay.log 2>&1 & +RELAY=$! +sleep 540 +kill $RELAY 2>/dev/null +sleep 3 +bt_kill_ours; sleep 2; taskkill //F //IM btl4.exe > /dev/null 2>&1; sleep 3 + +echo "=================== #137 MYOMER FREEZE ===================" +echo -n "respawns: "; grep -ac "Mech::Reset" mf137_a.log +echo -n "post-reset FROZEN samples: "; grep -ac "FROZEN" mf137_a.log +echo -n "STALE (cold but zero) samples: "; grep -ac "STALE (cold but zero)" mf137_a.log +echo +echo "--- any reset where the myomers came back AT or OVER the failure temp? ---" +python - <<'PY' +import re, io +bad = 0 +for ln in io.open(r"C:\git\bt411\content\mf137_a.log", encoding="latin-1", errors="replace"): + m = re.search(r"\[myofreeze\] (\S+)\s+(\S+)\s+T=([-\d.e+]+) deg=([-\d.e+]+) fail=([-\d.e+]+)\s+speedEffect=([-\d.e+]+)", ln) + if not m: + continue + when, name, t, deg, fail, se = m.group(1), m.group(2), float(m.group(3)), float(m.group(4)), float(m.group(5)), float(m.group(6)) + if se <= 1e-4: + bad += 1 + if bad <= 12: + why = "TEMP >= fail (reset did not take / re-heated)" if t >= fail else "STALE CACHE (temp fine, effect 0)" + print(" %-10s %-12s T=%8.1f fail=%8.1f effect=%.4f -> %s" % (when, name, t, fail, se, why)) +print(" zero-effect samples: %d" % bad) +PY +echo +echo "--- the first frozen episode in context ---" +grep -aE "Mech::Reset|myofreeze" mf137_a.log | grep -aB2 -A6 "FROZEN" | head -20