igneum/tools/scene/parity-remote.sh
igneum-labs a16e99063b Chain scene parity test: one recorded feed through the home fold, /live and the app's Inspect view, three frames each pixel-equal, in the gate (7 October 2026, 15:5x UK)
tools/scene/parity.mjs serves site/ (tools/site-serve.mjs) and the app's UI (tools/ui-mock/server.mjs) on a build box, answers
every page's /api/live from scene/fixtures/live-2026-10-07.json, freezes the clock at the fixture's instant (Date, timers,
requestAnimationFrame) and reads each scene canvas at 900 by 420 px at the first push and the next two polls: the read is the
push's own synchronous paint, so a frame depends on the fake time alone, never on how long a fetch took. Known-failed first: the
app with --included moved by one unit must differ from /live at every instant (it does: 1,549 / 1,282 / 1,157 px). Then home
fold = /live, app Inspect = /live, app with this machine's key = /live with the same key (the overlay is the same picture), and
the app's overlay frame differs from its base frame (the overlay is drawn). The compact card is rendered and reported, not
compared. A RED line names the differing pixels and their box. tools/scene/parity-remote.sh carries the files to the box
(~/.config/igneum/build-server-2 by default) under this lane's prefix and runs it there; a plain CI runner with no box and no
Playwright prints a skip line. One new line in tools/ci/pre-push.sh.

First run on build-2 at 15:4x UK, release-0.3.21 tree plus scene-parity: every comparison equal at T+0, T+2 and T+4 s.
Found on the way and fixed in the harness, not the renderer: lane order keeps the history of earlier layouts (the scene must be
at the compared size before its first layout); the app's recorded mock card is a real devnet key (cleared for the base case).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 13:52:19 +00:00

36 lines
3 KiB
Bash
Executable file

#!/usr/bin/env bash
# The scene parity test on a build box (the Mac runs no headless browser: standing rule, 7 October 2026). Carries the files the
# test needs to the box under this lane's prefix, runs tools/scene/parity.mjs there and prints its report; the box's own
# Playwright build and Chromium (root installed the libraries on 7 October 2026, 14:5x UK) do the rendering.
#
# tools/scene/parity-remote.sh [--box N] [--out <dir>] default box 2; --out fetches the frames and the report back
#
# Where it runs: a box named by ~/.config/igneum/build-server[-N] (build@<ip>); on a machine with no box file but a local
# Playwright (a CI runner that is itself a box) it runs parity.mjs in place; with neither it prints a skip line and exits 0,
# so a plain GitHub runner stays green while every box-side and Mac-side gate renders for real.
set -uo pipefail
cd "$(git rev-parse --show-toplevel)" || exit 1
BOX=2; OUT=""
while [ $# -gt 0 ]; do case "$1" in --box) BOX="$2"; shift 2 ;; --out) OUT="$2"; shift 2 ;; *) echo "unknown argument $1" >&2; exit 2 ;; esac; done
HOSTFILE="$HOME/.config/igneum/build-server"; [ "$BOX" = 1 ] || HOSTFILE="$HOSTFILE-$BOX"
if [ ! -s "$HOSTFILE" ]; then
if [ -n "${PLAYWRIGHT_CORE:-}" ] || [ -f /srv/builds/_bin/overlap/node_modules/playwright-core/package.json ]; then exec node tools/scene/parity.mjs ${OUT:+--out "$OUT"}; fi
echo "scene-parity: skipped, no build box file at $HOSTFILE and no Playwright here"; exit 0
fi
HOST="$(cat "$HOSTFILE")"; KEY="$HOME/.ssh/igneum_ed25519"
SSH=(ssh -i "$KEY" -o BatchMode=yes -o ConnectTimeout=10 "$HOST")
WT="$(basename "$(pwd)")"; DEST="/srv/builds/scene-parity/$WT"
"${SSH[@]}" "mkdir -p $DEST/site $DEST/tools/ui-mock $DEST/tools/scene $DEST/scene $DEST/app/igneum-app/ui" || { echo "scene-parity: box $HOST unreachable" >&2; exit 1; }
RS=(rsync -a --delete -e "ssh -i $KEY -o BatchMode=yes")
"${RS[@]}" --exclude img --exclude verify --exclude '*.png' --exclude '*.ico' site/ "$HOST:$DEST/site/"
"${RS[@]}" scene/ "$HOST:$DEST/scene/"
"${RS[@]}" tools/scene/ "$HOST:$DEST/tools/scene/"
"${RS[@]}" tools/ui-mock/ "$HOST:$DEST/tools/ui-mock/"
"${RS[@]}" tools/site-serve.mjs "$HOST:$DEST/tools/site-serve.mjs"
if [ -f app/igneum-app/ui/live-dag.js ]; then "${RS[@]}" --exclude '*.woff2' app/igneum-app/ui/ "$HOST:$DEST/app/igneum-app/ui/"; else "${SSH[@]}" "rm -rf $DEST/app"; fi
[ -f brand/igneum-coin-1024.png ] && "${SSH[@]}" "mkdir -p $DEST/brand" && "${RS[@]}" brand/igneum-coin-1024.png "$HOST:$DEST/brand/igneum-coin-1024.png"
# the copied-sources rule: re-stamped on the far side before anything runs (touch), so no stale mtime decides anything there
"${SSH[@]}" "cd $DEST && find . -type f -exec touch {} + && git init -q . 2>/dev/null; [ -f /srv/builds/_bin/overlap/env.sh ] && . /srv/builds/_bin/overlap/env.sh; cd $DEST && timeout 240 nice -n 10 node tools/scene/parity.mjs --out $DEST/_out"
RC=$?
if [ -n "$OUT" ]; then mkdir -p "$OUT"; rsync -a -e "ssh -i $KEY -o BatchMode=yes" "$HOST:$DEST/_out/" "$OUT/" 2>/dev/null; fi
exit $RC