#!/usr/bin/env bash
# check-drift — has anything silently undone committed work in the tracks?
#
# WHY THIS EXISTS (2026-07-29)
#
# Pulsar saves the BUFFER, not the file. Its process had been running since
# Sun Jul 26; every track opened before an edit therefore held three-day-old text.
# When PLN commented two lines out in wap.tidal and hit ctrl+S, Pulsar wrote that
# whole stale buffer back and silently reverted EVERY CC the column migration had
# moved — ^31 back to ^52, ^32 to ^53, ^33 to ^34, ^17 to ^18, and it deleted a
# FIXME comment. No warning, no conflict, no error. He noticed because a knob was
# in the wrong place, an hour later.
#
# And "Window: Reload" does NOT fix it — that restores buffers from Pulsar's
# session cache, not from disk. The reliable action is to CLOSE THE TAB and reopen.
#
# PLN: "how can we trust each other with pulsar"
#
# The answer is not a rule either of us has to remember. Prevention is not
# available: Pulsar's application.json is 75 bytes of project roots, so there is no
# way to ask which files are open. So the answer is (1) commit immediately, which
# makes any clobber a `git diff` away instead of lost, and (2) DETECT it in seconds
# rather than in an hour. This is (2).
#
# Two independent questions, because they fail differently:
#   A. Does the working tree still contain what was committed?  -> git
#   B. Does the surface grid still hold?                        -> surface-columns
# A catches a stale-buffer clobber of ANY kind. B catches the specific regression
# that matters for playing, even if it arrived some other way.
#
# Usage:  tools/check-drift.sh            # the OPAL setlist
# Exit 0 = no drift. 1 = something reverted committed work.
set -uo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$DIR"

RED=$'\033[31m'; GRN=$'\033[32m'; YEL=$'\033[33m'; OFF=$'\033[0m'
fail=0

# --- THE GRID IS THE ARBITER, SO ASK IT FIRST -------------------------------
#
# The first version of this script counted changed ^NN lines and called any bulk
# change a clobber. It then immediately flagged my own REPAIR of the clobber as
# drift. That is crying wolf, and a gate that cries wolf gets ignored -- the exact
# principle already written into `gig-log preflight`.
#
# The fix is to define drift properly. Drift is not "control numbers changed", it
# is "control numbers moved AWAY FROM THE GRID". So measure the grid first; if it
# still holds, a bulk CC change moved TOWARD it and is a repair, not a regression.
#
# 5 is the agreed floor: the gSel overflows (#54) left in place on purpose.
echo "check-drift: does the column grid still hold?"
EXPECTED=5
grid_ok=0
got=$(python3 tools/surface-columns.py --knobs 2>/dev/null \
      | grep -oE 'total \^NN renumbers for full alignment: [0-9]+' \
      | grep -oE '[0-9]+$')
if [ -z "${got:-}" ]; then
  echo "  ${YEL}note${OFF}  could not read surface-columns — NOT treating that as a pass"
  fail=1
elif [ "$got" -le "$EXPECTED" ]; then
  echo "  ${GRN}ok${OFF}   $got knob(s) out of column (<= $EXPECTED expected gSel overflows)"
  grid_ok=1
else
  echo "  ${RED}DRIFT${OFF} $got knobs out of column, expected at most $EXPECTED."
  echo "        Knobs have moved back out of their orbit's column."
  echo "        See which:  python3 tools/surface-columns.py --knobs"
  pend=$(python3 tools/migrate-columns.py --plan 2>/dev/null | grep -oE '[0-9]+ move\(s\)' | grep -oE '^[0-9]+' || true)
  if [ -n "${pend:-}" ] && [ "$pend" -gt 0 ]; then
    echo "        NB migrate-columns reports $pend pending move(s): the grid is"
    echo "        UNALIGNED (migration incomplete), which is not the same as"
    echo "        REGRESSED. Uncommitted edits below are probably the repair."
  fi
  fail=1
fi

# --- and now the working tree, judged in that light -------------------------
echo
echo "check-drift: uncommitted .tidal changes"
mapfile -t changed < <(git diff --name-only -- 'live/**/*.tidal' 2>/dev/null)
if [ ${#changed[@]} -eq 0 ]; then
  echo "  ${GRN}ok${OFF}   none"
else
  for f in "${changed[@]}"; do
    moved=$(git diff -U0 -- "$f" | grep -cE '^[-+].*"\^[0-9]+"' || true)
    if [ "$moved" -ge 4 ] && [ "$grid_ok" -eq 0 ]; then
      echo "  ${RED}DRIFT${OFF} $f — $moved ^NN lines changed AND the grid is broken."
      echo "        TWO hypotheses fit this, and they have opposite remedies:"
      echo "        (a) a MIGRATION IN PROGRESS — the grid is unaligned because the"
      echo "            move is half-applied, and these edits are the repair."
      echo "        (b) a stale-buffer clobber — Pulsar wrote an old buffer back."
      echo "        Tell them apart by DIRECTION, not by volume:"
      echo "          python3 tools/migrate-columns.py --plan $f"
      echo "        0 moves => these edits ARE the alignment (hypothesis a, keep them)."
      echo "        Moves listed that UNDO your edits => clobber (hypothesis b)."
      fail=1
    elif [ "$moved" -ge 4 ]; then
      echo "  ${YEL}note${OFF}  $f — $moved ^NN lines changed, but the grid still holds"
      echo "        (a bulk change TOWARD the grid is a repair, not a regression)"
    elif [ "$moved" -gt 0 ]; then
      echo "  ${GRN}ok${OFF}   $f — $moved ^NN line(s) changed, grid intact"
    else
      echo "  ${GRN}ok${OFF}   $f — edited, no control numbers moved"
    fi
  done
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "check-drift: ${GRN}OK${OFF} — committed track work is intact."
else
  echo "check-drift: ${RED}DRIFT DETECTED${OFF}"
  echo "  DO NOT reach for git checkout until you have looked at the diff. On
  2026-08-21 all 13 flagged files were PLN's own work — the ^43/^44 -> ^41
  gMask-retirement migration plus real musical edits (new octersubbus/squizbus
  lines, sample and gain changes) — and `git checkout --` would have deleted a
  set the day before a gig. Volume of ^NN changes does not distinguish a repair
  from a clobber; only direction does, and migrate-columns --plan knows it.

  If the diff really is a stale-buffer clobber: CLOSE THE TAB in Pulsar and reopen"
  echo "  (Window: Reload restores the cached buffer, not the file), then"
  echo "    git checkout -- <file>          # take the committed version back"
  echo "  or re-run the migration:"
  echo "    python3 tools/migrate-columns.py --plan <file>"
fi
exit "$fail"
