Four probes were written from a blank file and each re-learned the same lessons by losing a run: that a flat run cannot be told from a frozen guest without a stall witness, that results held to the end of a run are destroyed by a turn timeout, that a roster count which is not the stage's member count means a different stage loaded and must be discarded, and that a run's witness state has to be read before its numbers. Writing each lesson down did not stop the next probe repeating it, because each probe started from nothing. probeharness.py makes them structural. Probe(baseline=N) discovers the roster, rescans up to five times and refuses to start if the count never reaches the baseline. The witness is calibrated on construction, sampled by tick() and reported by status() and summary(), so a probe cannot forget it, and when no witness is found it reports UNVALIDATED rather than zero stalls. emit() flushes on every line. craft(), strengths(), alive() and heap() supply the roster-to-craft link, per-record liveness and the raw heap, so a new probe writes only its own logic. Verified rather than asserted: deploy_probe.py reimplements the per-record deployment watch on top of it in about forty lines against wave7_probe's hundred and fifty, and its first live run was clean -- 116 roster records, 32 witnesses at 10/s, zero stalled samples, seven losses tracked, and the TSV written incrementally. Nothing about the result is new, which is the point: the harness reproduces a known-good measurement. The existing probes are deliberately not ported. They work, and rewriting them would risk changing results other documents cite. New probes should use the harness; old ones should be ported when they next need a change.
32 lines
1.6 KiB
Bash
Executable File
32 lines
1.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -u
|
|
export HOME=/sylph-home/re SDL_AUDIODRIVER=dummy DISPLAY=:98
|
|
export PYTHONPATH=/sylph-home/.local/lib/python3.12/site-packages
|
|
SD="$(cd "$(dirname "$0")" && pwd)"
|
|
SECS="${1:-180}"; EVERY="${2:-10}"; HUNT="${3:-1}"
|
|
CFG=/tmp/nav-live.json
|
|
"$SD/launch_mission.sh" fly || { echo "BOOT FAILED"; exit 1; }
|
|
# The bind is intermittent and a failed bind means no pilot, no kills and a
|
|
# completely uninformative run. Retry before giving up, and abort if it never
|
|
# takes rather than silently flying an unattended craft.
|
|
# entities2 self finds the player by MOTION between two samples, so a craft that
|
|
# is sitting still at mission start is invisible and the bind fails -- three
|
|
# times in a row on the run that added this retry. Nudge the throttle first so
|
|
# there is something to see, then bind.
|
|
BOUND=0
|
|
for try in 1 2 3; do
|
|
python3 "$SD/pad.py" set "rt=1" >/dev/null 2>&1 || true
|
|
sleep 3
|
|
python3 "$SD/pad.py" clear >/dev/null 2>&1 || true
|
|
if python3 "$SD/entities2.py" self 0x130 "$CFG" >/dev/null 2>&1; then BOUND=1; break; fi
|
|
echo "--- bind attempt $try failed, retrying"; sleep 5
|
|
done
|
|
if [ "$BOUND" = 1 ]; then
|
|
SYLPH_HUNT="$HUNT" SYLPH_KILL_TURRETS=1 SYLPH_KEEPOUT="${SYLPH_KEEPOUT:-1400}" SYLPH_HZ="${SYLPH_HZ:-8.0}" SYLPH_PREFER="${SYLPH_PREFER:-}" nohup python3 "$SD/pilot.py" "$CFG" "$SECS" \
|
|
</dev/null >/tmp/live-pilot.log 2>&1 &
|
|
PILOT=$!; echo "--- pilot (SYLPH_HUNT=$HUNT)"
|
|
else echo "BIND FAILED after 3 attempts -- aborting, an unattended run tests nothing"; exit 4; fi
|
|
python3 "$SD/deploy_probe.py" "$SECS" "$EVERY"; rc=$?
|
|
[ -n "$PILOT" ] && kill "$PILOT" 2>/dev/null
|
|
echo "LIVENESS DONE rc=$rc"
|