#!/usr/bin/env bash
# Does the boot ANIMATE, or does it draw the same picture very fast?
#
#   tools/port/verify-motion            # assert
#   tools/port/verify-motion --control  # can it fail?
#
# 🔴 WHY THIS EXISTS. A human on a 140 fps GPU: *"the port does no blur
# animation at all, the logos just switch."* Three checks this port already had
# were green at the time, and all three were blind the same way:
#
#   frozen sweep (`--time=`)  proves the renderer CAN draw pose N. It drives the
#                             clock by hand and never runs the animation.
#   settled comparison        scored 0.01 % against the oracle. A screen frozen
#                             84 % of the time matches a settled reference
#                             PERFECTLY -- that is what frozen means.
#   achieved-fps counter      counts frames DRAWN. Drawing identical pixels 25
#                             times a second scores exactly like animating.
#
# Every one measured throughput or a pose. **None measured CHANGE.** Same shape
# as `InputEventAction` bypassing the input map: the instrument sat below the
# thing that was broken, so the breakage could not appear in it.
#
# This films a REAL boot -- no `--time`, no pinning -- and hands it to
# `tools/motion-census`, which measures change and nothing else.
#
# ⚠️ WHAT IT CANNOT DO. It is the liveness half only. A wrong ramp that moves
# every frame passes here. Correctness stays with `verify-capture` against the
# oracle, and the two are complementary: one screen can pass either alone.
set -euo pipefail
cd "${PROJECT_DIR:-/work}"
export DISPLAY="${DISPLAY:-:97}"
OUT="${OUT:-${TMPDIR:-/tmp}/verify-motion}"
INTERVAL=0.05

# The publisher splash declares its whole build-in over t=0..45 -- 0.75 s at
# 60 units/s -- and then holds. So the FIRST second of the boot is where a
# frozen build-in shows up, and it is the only window this asserts on.
#
# The bar is 60 % of adjacent frame-pairs moving in that window, and BOTH SIDES
# WERE MEASURED rather than one measured and one assumed -- the one operator in
# `ScreenView.pose_at` was reverted, this check run against the defect, and the
# operator restored:
#
#   broken (pose_at ASSIGNED the settle instant)   40 %   -- and it FAILED
#   fixed  (clamps to it)                          86 %   -- and it passed
#
# 60 sits mid-gap: 20 points above the defect, 26 below the fix. That is why it
# is a floor and not a tuned threshold, and it is deliberately NOT set near the
# passing value -- a check that only passes at exactly today's number fails on
# the next legitimate change and teaches people to edit the bar.
#
# 🔴 THE FIRST VERSION CLAIMED "~40 POINTS OF CLEARANCE ON BOTH SIDES" AND HAD
# NOT MEASURED THE BROKEN CASE. With a 1.0 s window the real clearance was 5
# points, because that window includes 0.25 s of legitimate hold and dilutes the
# signal. The window is now the DECLARED build-in -- publisher t=0..45, 0.75 s
# at 60 units/s -- so it asks about the interval the disc says is animating and
# nothing else. A bar justified by an unmeasured number is the same defect this
# whole check exists to catch, one level up.
WINDOW=0.75
BAR=60

films() {  # $1 = dir
  rm -rf "$1"; mkdir -p "$1"
  timeout 120 godot --path port -- --boot --skip-at=1 \
    --film="$1/f" --film-interval="$INTERVAL" >"$1/boot.log" 2>&1 || true
}

moving_pct_in_window() {  # $1 = dir -- % of adjacent pairs that MOVED, first $WINDOW seconds
  python3 - "$1" "$INTERVAL" "$WINDOW" <<'PY'
import sys, glob, os, importlib.util, importlib.machinery
d, interval, window = sys.argv[1], float(sys.argv[2]), float(sys.argv[3])
frames = sorted(glob.glob(os.path.join(d, "f_*.png")))
n = int(window / interval) + 1
frames = frames[:n]
if len(frames) < 3:
    print("0"); raise SystemExit
# Reuse motion-census's own loader and floor rather than re-deriving them: a
# second implementation of "did it move" is a second thing to be wrong.
sys.path.insert(0, os.path.join(os.environ.get("PROJECT_DIR", "/work"), "tools"))
spec = importlib.util.spec_from_loader(
    "mc", importlib.machinery.SourceFileLoader(
        "mc", os.path.join(os.environ.get("PROJECT_DIR", "/work"), "tools", "motion-census")))
mc = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mc)
from pathlib import Path
prev, moved, total = None, 0, 0
for f in frames:
    cur = mc.load(Path(f))
    if prev is not None:
        delta = sum(abs(a - b) for a, b in zip(cur, prev)) / len(cur)
        total += 1
        if delta > mc.MOVED:
            moved += 1
    prev = cur
print("%d" % (100 * moved / total if total else 0))
PY
}

echo "boot liveness: films a real boot and measures CHANGE, not throughput"

# 🔴 THE CONTROL RUNS FIRST AND IS NOT OPTIONAL. `motion-census --selftest`
# drives a synthetic fade, a switch and a frozen film through the same loader
# and the same floor this check uses. If it cannot separate those three, every
# number below is decoration.
if ! tools/motion-census --selftest >"$OUT.selftest.log" 2>&1; then
  echo "  🔴 motion-census --selftest FAILED -- the detector cannot tell a fade"
  echo "     from a switch, so nothing it reports about the boot means anything."
  sed 's/^/     /' "$OUT.selftest.log"
  exit 2
fi
echo "  census selftest           ok  (fade / switch / frozen separated)"

if [ "${1:-}" = "--control" ]; then
  # A frozen film must FAIL this check. Built by repeating one real boot frame,
  # so it has the port's own pixels and differs from a passing run in exactly
  # one property: nothing changes.
  films "$OUT/live"
  ctl="$OUT/frozen"; rm -rf "$ctl"; mkdir -p "$ctl"
  # NOT `ls | head`: under `set -o pipefail` head closes the pipe, ls takes
  # SIGPIPE and the script exits 141 before it ever asserts anything. Cost one
  # run to notice, and a check that dies before checking looks a lot like a
  # check that passed.
  local_frames=("$OUT"/live/f_*.png)
  src="${local_frames[0]}"
  for i in $(seq -w 0 24); do cp "$src" "$ctl/f_0$i.png"; done
  pct=$(moving_pct_in_window "$ctl")
  if [ "$pct" -lt "$BAR" ]; then
    echo "  frozen film is REJECTED     ok  ${pct}% moving, bar ${BAR}%"
    echo
    echo "the check fails on a film that does not move"
    exit 0
  fi
  echo "  frozen film is REJECTED     🔴 FAILED  ${pct}% moving -- it passed, so"
  echo "     this check cannot detect the defect it was written for."
  exit 1
fi

films "$OUT/live"
grep -m1 -E "fps achieved" "$OUT/live/boot.log" | sed 's/^ */  /' || true
pct=$(moving_pct_in_window "$OUT/live")
printf '  %-25s %s  %d%% of pairs moved in the first %.1fs, bar %d%%\n' \
  "build-in moves" "$([ "$pct" -ge "$BAR" ] && echo ok || echo '🔴 FAILED')" \
  "$pct" "$WINDOW" "$BAR"
[ "$pct" -ge "$BAR" ] || {
  echo
  echo "🔴 the boot draws its first second without changing. That is the"
  echo "   2026-09-02 defect: poses not advancing while the clock does."
  echo "   Films are in $OUT/live -- run tools/motion-census on them."
  exit 1
}
echo
echo "the boot's build-in animates"
