A replicant could not start walking between gait-change records. The port's
body case 4 (the task-#64 lockstep twin) is an INSERTION sitting between case 0
and the advance group; in the binary case 4 is a MEMBER of that group
(FUN_004a5678 @004a5678: case 2,3,4,5,8,... -- no turn block, no speed exit),
so case 0's fallthrough is meant to land on Advance(). The insertion caught it.
On a replicant that is not a race but an identity: case 0 arms walk iff
standSpeed < bodyTargetSpeed, and the inserted block resets iff standSpeed <
bspd -- where bspd IS bodyTargetSpeed for a replicant. Same expression, so arm
and reset fire on the same frame, forever, and a peer parked at Standing with a
live replicated demand never cycles. bodyCycleSpeed stays 0 while position
advances from dead reckoning: the skate.
This is the sequel to e91d447 (#82). Before it the replicant branch read the
dead local mapper cell (0 forever), the exit never fired, and the fallthrough
worked BY ACCIDENT. Fixing the dead cell closed the escape hatch.
Fix: case 0 -> goto advance_body_normally, the leg twin's own idiom, restoring
the binary's structure without touching the #64/#82 turn logic.
BT_NO_BODY_FALLTHRU=1 reverts.
Measured (2-node, scratchpad/night13/skatelock.sh):
legacy 336 consecutive locked seconds, bspd=39.2324 bts=39.2324 every line
fixed 0 locks, every pass
master body-Standing samples 52 -> 21 (it locked too, invisibly at mj=0)
turn-in-place intact: pivoter body state 4 x9 / leg state 4 x8, in lockstep
Diagnostics (both keepers): [skate] now carries bstate= -- the field lines
proved "both channels idle" but never named the state, which was the whole
answer; [bodySM]/[peergait] under BT_BODY_SM_LOG instrument the arm->reset pair
and a moving replicant's body channel.
NOT claimed: that this accounts for the night-13 field episodes. That link is
inference -- locked + translating IS the skate signature by construction, but no
bench caught the two together. bstate= settles it next playtest.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NCJQkvq6G2JNrpVbA75tVZ
84 lines
3.4 KiB
Bash
84 lines
3.4 KiB
Bash
#!/usr/bin/env bash
|
|
# =========================================================================
|
|
# #52 STANDING-LOCK -- A/B on the rig that is KNOWN to reproduce.
|
|
#
|
|
# Composition lifted verbatim from scratchpad/night12/skatebench.sh, which
|
|
# produced 6 skate episodes in one 260s run (sk_run.out) and 4 in another.
|
|
# A walks continuously (autodrive) and is killed every ~40s by B, so it
|
|
# respawns WHILE MOVING -- and that is the field correlation both nights:
|
|
# night 12's skating clustered in the deaths-heavy final drop, and all four
|
|
# of night 13's episodes were in the last, deaths-heavy session.
|
|
#
|
|
# My own rigs (skatelock.sh v1/v2/v3) each failed to reproduce the SYMPTOM:
|
|
# a wall-jammed mech locks but does not translate, and a freely-walking mech
|
|
# transitions gait constantly, so records keep rescuing its peer copy. The
|
|
# kill cycle gives both halves at once -- a steady post-respawn walk demand
|
|
# with no gait edges, on a mech that is actually moving.
|
|
#
|
|
# B is the OBSERVER: A's replicant lives on B, so B's log carries [skate],
|
|
# [bodySM] and [peergait] for A.
|
|
#
|
|
# MODE=legacy -> BT_NO_BODY_FALLTHRU=1 (pre-fix; expect episodes)
|
|
# MODE=fixed -> default (expect none)
|
|
# =========================================================================
|
|
set -x
|
|
MODE="${1:-fixed}"
|
|
DUR="${2:-260}"
|
|
. /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 s2_${MODE}_a.log s2_${MODE}_b.log s2_${MODE}_relay.log
|
|
|
|
bt_assert_player_env
|
|
bt_expert_egg MP.EGG S2.EGG
|
|
sed -i "s/^map=.*/map=grass/; s/^time=.*/time=day/; s/^vehicle=.*/vehicle=madcat/" S2.EGG
|
|
|
|
LEGACY=""
|
|
[ "$MODE" = "legacy" ] && LEGACY=1
|
|
|
|
# ---- node B: OBSERVER + killer (back window) ------------------------------
|
|
(
|
|
export BT_MP_FORCE_DMG=1
|
|
export BT_BODY_SM_LOG=1 BT_DEATH_LOG=1 BT_MP_LOG=1 BT_MATCHLOG=1
|
|
[ -n "$LEGACY" ] && export BT_NO_BODY_FALLTHRU=1
|
|
bt_launch s2_${MODE}_b.log S2.EGG 0x0C -net 1601
|
|
)
|
|
sleep 2
|
|
# ---- node A: the walking victim; autodrive persists across respawns -------
|
|
(
|
|
export BT_AUTODRIVE=0.8
|
|
export BT_BODY_SM_LOG=1 BT_DEATH_LOG=1 BT_MP_LOG=1 BT_MATCHLOG=1
|
|
[ -n "$LEGACY" ] && export BT_NO_BODY_FALLTHRU=1
|
|
bt_launch s2_${MODE}_a.log S2.EGG 0x03 -net 1501
|
|
)
|
|
sleep 5
|
|
python ../tools/btconsole.py S2.EGG 127.0.0.1:1501 127.0.0.1:1601 > s2_${MODE}_relay.log 2>&1 &
|
|
RELAY=$!
|
|
sleep "$DUR"
|
|
kill $RELAY 2>/dev/null
|
|
bt_kill_ours
|
|
sleep 2
|
|
taskkill //F //IM btl4.exe > /dev/null 2>&1
|
|
sleep 3
|
|
|
|
echo "=================== MODE=$MODE ==================="
|
|
echo -n "death cycles on A (the provocation actually ran): "
|
|
grep -acE "death cycle START" s2_${MODE}_a.log
|
|
echo
|
|
echo "--- THE SYMPTOM: [skate] episodes on B (A's replicant) ---"
|
|
echo -n "SKATING lines: "; grep -ac "SKATING" s2_${MODE}_b.log
|
|
grep -a "\[skate\]" s2_${MODE}_b.log | head -14
|
|
echo
|
|
echo "--- THE MECHANISM: [bodySM] arm->reset pairs (1 Hz throttled) ---"
|
|
echo -n "STANDING-LOCK on B: "; grep -ac "STANDING-LOCK" s2_${MODE}_b.log
|
|
grep -a "STANDING-LOCK" s2_${MODE}_b.log | grep -a REPLICANT | sort -u | head -3
|
|
echo
|
|
echo "--- THE POSITIVE: moving replicant's body state, 1 Hz ---"
|
|
grep -a "\[peergait\]" s2_${MODE}_b.log | grep -oaE "bstate=[0-9-]+" | sort | uniq -c | sort -rn | head -8
|
|
echo -n "samples flagged IDLE CHANNELS: "; grep -ac "IDLE CHANNELS" s2_${MODE}_b.log
|
|
echo
|
|
echo "--- control: skate on A (B stands still -- expect 0) ---"
|
|
grep -ac "SKATING" s2_${MODE}_a.log
|