#!/usr/bin/env bash
# check-preload — is preload.scd warming the set we are actually going to play?
#
#     tools/check-preload.sh          # verify; exit 1 if stale
#     tools/check-preload.sh --fix    # regenerate it from the setlist
#
# WHY (2026-08-01, found by ear). PLN heard crackles moving do_it_right ->
# take_5_drops. Measured in that window: 0 SuperDirt lates, 0 pipewire xruns, and 17
# lazy soundfile reads — every one of them `take5:*`. Not CPU, not thermal: disk I/O,
# because SuperDirt was reading that track's samples for the first time mid-transition.
#
# The preload MECHANISM was healthy and said so:  === PRELOAD: 47/47 banks OK in 1.9 s ===
# It was warming the wrong list. preload.scd was dated Jul 28 and its own header said
# "10 track(s) scanned" while the set is 13 — because tools/setlist_samples.py reads
# setlist_opal2026.txt (10 tracks) while gig-up/cheat-sheet trust
# set-coherence.setlist_tracks() (13). See #120.
#
# TWO PROPERTIES MADE IT INVISIBLE, and both are the real lesson:
#   * preload.scd is GITIGNORED (correctly — it is generated), so nothing in the repo
#     could keep it fresh and no diff ever showed it drifting.
#   * NOTHING COMPARED IT TO THE SET. A generated artifact with no freshness check is a
#     stale artifact waiting for the worst possible moment. Its natural debut was a cold
#     boot at the venue — the first play of every track added since Jul 28.
# It only surfaced at a desk because SuperDirt had been up since Jul 28 and had cached
# those banks on first play weeks earlier; a restart cleared the cache and exposed it.

set -uo pipefail
cd "$(dirname "$0")/.." || exit 2

FIX=0
[ "${1:-}" = "--fix" ] && FIX=1

# The canonical setlist = whatever gig-up and cheat-sheet already trust. Borrowed, not
# re-implemented: a fourth parser for "what is the setlist" is how this bug happened.
tracks=$(python3 -c "
import importlib.util
spec = importlib.util.spec_from_file_location('sc','tools/set-coherence.py')
m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
print(' '.join(str(p) for p in m.setlist_tracks()))") || {
  echo "check-preload: could not read the setlist from set-coherence.py" >&2; exit 2; }

# Compare BANK SETS, not file bytes: the generator stamps a header and orders banks, and
# a diff on either would cry wolf on a rebuild that changed nothing that matters.
banks() { grep -oE '\[ \\[a-z0-9_]+' "$1" 2>/dev/null | sed 's/.*\\//' | sort -u; }

new=$(mktemp); trap 'rm -f "$new"' EXIT
# shellcheck disable=SC2086
python3 tools/setlist_samples.py $tracks --emit-sc > "$new" 2>/dev/null || {
  echo "check-preload: setlist_samples.py failed" >&2; exit 2; }

if [ ! -f preload.scd ]; then
  echo "check-preload: preload.scd does NOT EXIST — every sample will lazy-load on first play."
  missing=$(banks "$new" | wc -l); have=0
else
  missing=$(comm -13 <(banks preload.scd) <(banks "$new") | wc -l)
  have=$(banks preload.scd | wc -l)
fi
want=$(banks "$new" | wc -l)

if [ "$missing" -eq 0 ] && [ -f preload.scd ]; then
  echo "check-preload: ok — $have bank(s) warmed, covering all $(echo "$tracks" | wc -w) setlist track(s)."
  exit 0
fi

echo "check-preload: STALE — preload.scd warms $have bank(s), the set needs $want."
echo "  $missing bank(s) would be read from DISK on first play (crackle, mid-transition):"
if [ -f preload.scd ]; then
  comm -13 <(banks preload.scd) <(banks "$new") | head -20 | sed 's/^/    /'
fi

if (( FIX )); then
  cp "$new" preload.scd
  echo "  fixed: preload.scd regenerated ($want banks). Takes effect at the NEXT SuperDirt boot —"
  echo "         systemctl --user restart parvagues-sc   (~15s of silence, safe when not playing)"
  exit 0
fi

echo "  fix: tools/check-preload.sh --fix"
exit 1
