re-capture: a dead display must not look like a playing movie

skip_intro.sh compared two screenshots to detect the intro movie. When the X
server died 3 min into a run, `screenshot` failed silently and left both PNGs
at their previous contents — two stale files, whose RMSE is a constant non-zero
number, i.e. exactly the signature of a changing screen. The loop then reported
"movie -> skip A" every 5 s for the whole 600 s timeout with no emulator and no
display alive, and the session wasted 10 minutes before saying BOOT FAILED.

Both waiters now verify, every iteration, that the screenshot was actually
written, that the display answers xdpyinfo, and that a non-zombie xenia_canary
exists — with distinct exit codes (3 display, 4 emulator, 5 capture) so the
session log names the cause instead of timing out.

Also adds mission_state.py + escort_session.sh: read pos+0x154 against each
definition's HP for EVERY entity, to test whether the hull anchor is a property
of the entity class rather than of the player object (the escort question).
This commit is contained in:
claude-re
2026-07-30 17:06:08 +00:00
parent 93d6534efe
commit 91fb022caf
5 changed files with 247 additions and 3 deletions

View File

@@ -3,16 +3,37 @@
# - movie playing (two grabs 0.6s apart differ a lot) -> tap A to skip
# - static screen -> if the green "PRESS (A) BUTTON" glyph is there, tap A and stop
# Static logo screens are left alone, so a stray tap can never land on NEW GAME.
#
# LIVENESS IS CHECKED EVERY ITERATION, and that is not a nicety. When the
# display died 3 minutes into a run, `screenshot` started failing silently and
# left /tmp/f1.png and /tmp/f2.png at their last contents — two *stale* files,
# which compare to a constant non-zero RMSE, which reads exactly like "the
# screen is changing a lot". So the loop reported "movie -> skip A" every 5 s
# for the full 600 s timeout with no emulator and no X server running. A dead
# display and a playing movie must never be able to look the same.
set -u
export HOME=/sylph-home/re
DISP="${DISPLAY:-:98}"
alive(){ ps -o pid=,stat= -C xenia_canary 2>/dev/null | awk '$2 !~ /^Z/ {print $1}'; }
# The X root keeps the DEAD session's last frame, so a fresh launch would be
# detected as "already at the title". Blank it, and wait for the new window.
xsetroot -solid black 2>/dev/null || true
until xdotool search --name "Xenia-canary" >/dev/null 2>&1; do sleep 1; done
until xdotool search --name "Xenia-canary" >/dev/null 2>&1; do
xdpyinfo -display "$DISP" >/dev/null 2>&1 || { echo "DISPLAY LOST at ${SECONDS}s (before the window appeared)"; exit 3; }
[ -n "$(alive)" ] || { echo "EMULATOR GONE at ${SECONDS}s (before the window appeared)"; exit 4; }
sleep 1
done
deadline=$(( SECONDS + ${1:-900} ))
while [ $SECONDS -lt $deadline ]; do
rm -f /tmp/f1.png /tmp/f2.png
screenshot /tmp/f1.png >/dev/null 2>&1; sleep 0.6
screenshot /tmp/f2.png >/dev/null 2>&1
if [ ! -s /tmp/f1.png ] || [ ! -s /tmp/f2.png ]; then
xdpyinfo -display "$DISP" >/dev/null 2>&1 \
|| { echo "DISPLAY LOST at ${SECONDS}s"; exit 3; }
echo "SCREENSHOT FAILED at ${SECONDS}s with the display up"; exit 5
fi
[ -n "$(alive)" ] || { echo "EMULATOR GONE at ${SECONDS}s"; exit 4; }
d=$(compare -metric RMSE /tmp/f1.png /tmp/f2.png null: 2>&1 | sed 's/ .*//' | cut -d. -f1)
d=${d:-0}
read -r r g b < <(convert /tmp/f2.png -format "%[fx:int(255*p{625,618}.r)] %[fx:int(255*p{625,618}.g)] %[fx:int(255*p{625,618}.b)]" info:)