#94: replicant un-wreck now rides the DEATH-STATE EXIT edge -- the zone

falling-edge latch was blind to zone-less (collision) deaths

The peer wreck lifecycle listened to two different signals: wreck ON came
from the replicated death explosion (unconditional), wreck OFF from a
damage-zone falling edge (wasWrecked latch, armed only when a zone crossed
>= 1.0 on the observer).  The #83 collision damage prices as internal
rattle and never moves a zone, so a fresh mech killed by ramming could
NEVER un-wreck on peers -- the live respawned mech drove around wearing
the hulk (night-7 field report: SAURON's Loki, screenshotted by both
observers at the exact minute the log analysis places the ram death).

MechDeathHandler::Tick now tracks prevMode and fires the rebuild + warp
when the replicated MovementMode leaves the death modes {2,9} -- only
Mech::Reset ever does that, and the state rides every record header, so
the trigger is cause-agnostic.  The zone falling edge just refreshes the
cache.  Side effect fixed for free: the peer respawn warp vortex now
plays for zone-less deaths too (same gate).

Bench (scratchpad/night7/mp_zoneless.sh + the new
BT_SELF_DAMAGE_TYPE=collision harness option, which dispatches type-0
through the real TakeDamage divert): 14/14 zone-less deaths un-wrecked
(mode 9->1) with zero zone rises on the observer; explosive regression
leg 12/12 with zone destruction active.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Zh7PTkFy4KwTzVighLR9J
This commit is contained in:
Joe DiPrima
2026-07-31 02:10:04 -05:00
co-authored by Claude Fable 5
parent e91d447405
commit 054c3f2eee
6 changed files with 132 additions and 36 deletions
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# #94 bench: ZONE-LESS death un-wreck on the replicant.
#
# Node A (master) kills itself with TYPE-0 (collision) self-damage: the
# TakeDamage hub's collision divert prices it as internal rattle -- armor and
# damage zones never move -- reproducing the night-7 field ram-death without
# a ram. Node B observes with BT_DEATH_LOG: the fix must print
# [respawn] replicant un-wrecked + warp (mode 9->...)
# after each of A's respawns. Pre-fix, the un-wreck rode a zone falling edge
# that a zone-less death never produces -- B kept drawing A as the wreck.
#
# usage: mp_zoneless.sh [explosive] (arg switches A to the default weapon-
# type harness -- the REGRESSION leg: zone deaths must still un-wreck)
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
sed "s/^map=.*/map=grass/; s/^time=.*/time=day/" MP.EGG > ZL.EGG
TYPE="${1:-collision}"
OBS=zl_${TYPE}_obs.log
MST=zl_${TYPE}_master.log
rm -f "$OBS" "$MST"
# observer first (B): death-log ON -- the un-wreck line is the verdict
BT_MP_LOG=1 BT_REPL_LOG=1 BT_DEATH_LOG=1 \
bt_launch "$OBS" ZL.EGG 0x0C -net 1601
sleep 2
# master (A): repeated self-kill of the requested damage type. Collision
# damage is priced down by ~5e-5 (the 100 km/h reference scale) so its dose
# is raw-kinetic-sized; the explosive regression leg uses the classic 60/s.
SD_TYPE=""; DOSE=60
[ "$TYPE" = "collision" ] && { SD_TYPE=collision; DOSE=250000; }
BT_MP_LOG=1 BT_DMG_LOG=1 BT_DEATH_LOG=1 \
BT_SELF_DAMAGE=$DOSE BT_SELF_DAMAGE_TYPE=$SD_TYPE \
BT_SELF_DAMAGE_DELAY=12 BT_SELF_DAMAGE_REPEAT=1 \
bt_launch "$MST" ZL.EGG 0x03 -net 1501
sleep 4
python ../tools/btconsole.py ZL.EGG 127.0.0.1:1501 127.0.0.1:1601 &
PC=$!
sleep 150
kill $PC 2>/dev/null
bt_kill_ours
rm -f ZL.EGG
echo "=== MASTER ($MST): deaths + rattle ==="
grep -c "DESTROYED" "$MST"
grep -m3 "colldmg\|selfdmg" "$MST"
echo "=== OBSERVER ($OBS): wreck swaps vs un-wrecks ==="
grep -c "wreck swap" "$OBS"
grep "un-wrecked" "$OBS"
echo "=== DONE ($TYPE) ==="