#!/usr/bin/env bash
# Rider clippy driver. Standing form ruled 2026-09-08 (doyle) after a killed chain
# left NO exit file and a watcher's own exit 0 read as a clean lint.
#
# THE RULE THIS ENCODES: an absence must never be able to render as a pass.
#   - the exit file is PRE-SEEDED with a VOID sentinel BEFORE the lint starts, so a
#     force-kill (TerminateProcess runs no trap) leaves VOID on disk, not nothing;
#   - it is overwritten with the real integer only when the lint actually returns;
#   - the watcher REFUSES to report a verdict unless that file holds a bare integer.
# Every guard below has a positive control in --selftest. Run it after any edit.
set -u

usage() { echo "usage: $0 <worktree> [outdir]   |   $0 --selftest   |   $0 --report <outdir>" >&2; exit 64; }

# The lint command is a seam so --selftest can drive every arm without invoking cargo
# (a guard exercisable only by the expensive real run never gets exercised).
: "${SPT_CLIPPY_CMD:=cargo clippy --workspace --all-targets -- -D warnings}"
: "${SPT_CLIPPY_POOL_TAG:=hertz-65s-rider}"

ps_join() { powershell.exe -NoProfile -Command "$1" 2>/dev/null | tr -d '\r\n'; }

holders() {
  ps_join "(Get-CimInstance Win32_Process | Where-Object { \$_.ExecutablePath -like '*${SPT_CLIPPY_POOL_TAG}*' } | Select-Object -ExpandProperty ProcessId) -join ','"
}

builders() {
  ps_join "(Get-CimInstance Win32_Process | Where-Object { \$_.Name -in @('cargo.exe','rustc.exe','clippy-driver.exe') } | Select-Object -ExpandProperty ProcessId) -join ','"
}

# THE THIRD VALUE. Measured 2026-09-08: WMI returns EMPTY STRINGS, not an error, for
# ExecutablePath/CommandLine on a process the querying user cannot fully open. On this
# box 219 of 632 processes are in that class, all SessionId 0 service-context, and the
# twohost-a job's own cargo (57412, GetOwner rv=2) is one of them.
# So `holders()` above is BLIND to a runner-session cargo holding this pool: it returns
# empty, which reads identically to "nothing is holding it".
# An unreadable process is NOT an absent process. These pids are reported as their own
# value and pool membership for them is UNDETERMINED — never folded into "no holders".
# We do NOT refuse on them: this box is the golden Windows runner and service-context
# builders are permanently present, so refusing would refuse always.
unreadable_builders() {
  if [ -n "${SPT_CLIPPY_FAKE_UNREADABLE:-}" ]; then printf '%s' "$SPT_CLIPPY_FAKE_UNREADABLE"; return; fi
  ps_join "(Get-CimInstance Win32_Process | Where-Object { \$_.Name -in @('cargo.exe','rustc.exe','clippy-driver.exe') -and -not \$_.ExecutablePath } | Select-Object -ExpandProperty ProcessId) -join ','"
}

# Tree state as a BREAKDOWN, never a single count. The old form counted '^ M' only,
# so a tree carrying staged or untracked changes reported dirty=0.
tree_state() {
  local st
  st=$(git status --porcelain)
  printf 'tracked_modified=%s staged=%s untracked=%s deleted=%s' \
    "$(printf '%s\n' "$st" | grep -c '^ M')" \
    "$(printf '%s\n' "$st" | grep -cE '^[MARC] ')" \
    "$(printf '%s\n' "$st" | grep -c '^??')" \
    "$(printf '%s\n' "$st" | grep -cE '^.D')"
}

run_lint() {
  local GW=$1 OUT=$2
  mkdir -p "$OUT" || { echo "REFUSE: cannot create $OUT" >&2; exit 4; }
  # Fresh dir per run: a stale exit file from a previous chain is exactly the
  # artifact this script exists to prevent.
  if [ -e "$OUT/clippy.exit" ] || [ -e "$OUT/clippy.raw" ]; then
    echo "REFUSE: $OUT already holds clippy artifacts - pass a FRESH outdir" >&2
    exit 4
  fi
  cd "$GW" || exit 9
  # A battery launched from a perch inherits the endpoint identity. Not needed for
  # clippy, kept for parity with the test drivers.
  unset OWL_SESSION_ID SPT_AGENT_ID SPT_ENDPOINT_ID SPT_HOME

  local H U
  H=$(holders)
  if [ -n "$H" ]; then
    echo "REFUSE: holders in pool (exe-in-pool, READABLE): [$H]" >&2
    echo "VOID:holders-in-pool" > "$OUT/clippy.exit"
    exit 5
  fi
  U=$(unreadable_builders)
  if [ -n "$U" ]; then
    echo "NOTE: builders I cannot read: [$U] - pool membership UNDETERMINED, not 'none'." >&2
  fi

  # PRE-SEED. From here the file EXISTS; a force-kill leaves the sentinel behind.
  echo "VOID:unfinished" > "$OUT/clippy.exit"

  {
    echo "started: $(date -u +%FT%TZ)"
    echo "head: $(git rev-parse HEAD)"
    echo "tree: $(tree_state)"
    echo "holders(exe-in-pool, READABLE, REFUSING GUARD - empty, or we would have exited 5): []"
    # Three-valued, never two. Empty here means "none I could read", not "none".
    echo "holders(UNREADABLE builders, pool membership UNDETERMINED, informational): [$U]"
    echo "builders box-wide (INFORMATIONAL - this box is the golden Windows runner, so"
    echo "  a refusal on any builder would be correct and unusable. If non-empty, wall"
    echo "  time is NOT a quiet-box number): [$(builders)]"
    echo "TOOLCHAIN cargo: $(cargo --version 2>&1)"
    echo "TOOLCHAIN clippy: $(cargo clippy --version 2>&1)"
    echo "LINT CMD: $SPT_CLIPPY_CMD"
  } > "$OUT/census.txt"

  local code=0
  # shellcheck disable=SC2086
  $SPT_CLIPPY_CMD > "$OUT/clippy.raw" 2>&1 || code=$?
  echo "$code" > "$OUT/clippy.exit"

  {
    echo "clippy.exit=$code"
    echo "raw_bytes=$(wc -c < "$OUT/clippy.raw")"
    # Counts are ORIENTATION only. The verdict is the exit code, never a line count:
    # under -D warnings a lint prints as 'error', and a needle that cannot match
    # reads as a clean result.
    echo "orientation_error_lines=$(grep -cE '^error' "$OUT/clippy.raw" || true)"
    echo "orientation_warning_lines=$(grep -cE '^warning' "$OUT/clippy.raw" || true)"
    echo "builders box-wide AFTER: [$(builders)]"
    echo "finished: $(date -u +%FT%TZ)"
  } >> "$OUT/census.txt"
  return "$code"
}

# The watcher. REFUSES to name a verdict unless the exit file holds a bare integer.
# Silence is never a pass; a missing or sentinel value reports VOID loudly.
report() {
  local OUT=$1
  if [ ! -f "$OUT/clippy.exit" ]; then
    echo "VERDICT: VOID - clippy.exit ABSENT. Nothing ran, or the chain died before it"
    echo "  could be written. This is NOT a pass. Claim nothing from clippy.raw."
    return 3
  fi
  local v
  v=$(tr -d ' \r\n' < "$OUT/clippy.exit")
  if ! printf '%s' "$v" | grep -qE '^[0-9]+$'; then
    echo "VERDICT: VOID - clippy.exit reads '$v', not an exit code. This is NOT a pass."
    if [ -f "$OUT/clippy.raw" ]; then
      echo "  raw stops at $(wc -c < "$OUT/clippy.raw") bytes, tail: $(tail -c 120 "$OUT/clippy.raw" | tr '\n' ' ')"
    fi
    return 3
  fi
  if [ "$v" = 0 ]; then
    echo "VERDICT: GREEN - from clippy.exit, an integer on disk."
  else
    echo "VERDICT: RED (exit $v) - from clippy.exit, an integer on disk."
    echo "=== diagnostics ==="
    grep -nE '^(error|warning)' "$OUT/clippy.raw" | head -40
  fi
  [ -f "$OUT/census.txt" ] && cat "$OUT/census.txt"
  return "$v"
}

selftest() {
  local T rc out pass fail kid
  T=$(mktemp -d); pass=0; fail=0
  ck() {
    if [ "$2" = "$3" ]; then
      echo "  PASS $1"; pass=$((pass+1))
    else
      echo "  FAIL $1: got '$2' want '$3'"; fail=$((fail+1))
    fi
  }

  echo "A1 absent exit file must report VOID, not silence:"
  mkdir -p "$T/a1"
  out=$(report "$T/a1"); rc=$?
  ck "reports VOID" "$(printf '%s' "$out" | grep -c 'VERDICT: VOID')" "1"
  ck "refuses with rc 3" "$rc" "3"

  echo "A2 sentinel (killed chain) must report VOID, not a pass:"
  mkdir -p "$T/a2"
  echo "VOID:unfinished" > "$T/a2/clippy.exit"
  printf 'Checking anstyle-wincon v3.0.11\n' > "$T/a2/clippy.raw"
  out=$(report "$T/a2"); rc=$?
  ck "reports VOID" "$(printf '%s' "$out" | grep -c 'VERDICT: VOID')" "1"
  ck "never says GREEN" "$(printf '%s' "$out" | grep -c 'GREEN')" "0"
  ck "refuses with rc 3" "$rc" "3"

  echo "A3 a real 0 must read GREEN (a guard that cannot say yes proves nothing):"
  mkdir -p "$T/a3"
  echo 0 > "$T/a3/clippy.exit"; : > "$T/a3/clippy.raw"; echo census > "$T/a3/census.txt"
  out=$(report "$T/a3"); rc=$?
  ck "reports GREEN" "$(printf '%s' "$out" | grep -c 'VERDICT: GREEN')" "1"
  ck "rc 0" "$rc" "0"

  echo "A4 a real non-zero must read RED:"
  mkdir -p "$T/a4"
  echo 101 > "$T/a4/clippy.exit"
  printf 'error: unused variable\n' > "$T/a4/clippy.raw"
  echo census > "$T/a4/census.txt"
  out=$(report "$T/a4"); rc=$?
  ck "reports RED" "$(printf '%s' "$out" | grep -c 'VERDICT: RED')" "1"
  ck "rc 101" "$rc" "101"

  echo "A5 PRE-SEED survives a force-kill (the defect that started all this):"
  SPT_CLIPPY_CMD="sleep 30" SPT_CLIPPY_POOL_TAG="__nomatch__" bash "$0" "$PWD" "$T/a5" >/dev/null 2>&1 &
  kid=$!
  for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
    [ -f "$T/a5/clippy.exit" ] && break
    sleep 1
  done
  pkill -P $kid >/dev/null 2>&1
  kill -9 $kid >/dev/null 2>&1
  wait $kid 2>/dev/null
  ck "exit file exists after kill" "$([ -f "$T/a5/clippy.exit" ] && echo yes || echo no)" "yes"
  ck "and holds the sentinel" "$(tr -d ' \r\n' < "$T/a5/clippy.exit" 2>/dev/null)" "VOID:unfinished"
  out=$(report "$T/a5")
  ck "watcher calls it VOID" "$(printf '%s' "$out" | grep -c 'VERDICT: VOID')" "1"

  echo "A6 holders guard REFUSES (it was labelled REFUSES and did nothing):"
  SPT_CLIPPY_CMD="true" SPT_CLIPPY_POOL_TAG="System32" bash "$0" "$PWD" "$T/a6" >/dev/null 2>&1
  ck "exits 5 on holders" "$?" "5"
  ck "and leaves a VOID sentinel" "$(tr -d ' \r\n' < "$T/a6/clippy.exit" 2>/dev/null)" "VOID:holders-in-pool"

  echo "A7 a stale outdir is REFUSED (a previous chain's exit file must never be reused):"
  SPT_CLIPPY_CMD="true" SPT_CLIPPY_POOL_TAG="__nomatch__" bash "$0" "$PWD" "$T/a4" >/dev/null 2>&1
  ck "exits 4 on stale artifacts" "$?" "4"

  echo "A8 an UNREADABLE builder is a THIRD VALUE - reported, not folded into 'no holders':"
  SPT_CLIPPY_CMD="true" SPT_CLIPPY_POOL_TAG="__nomatch__" SPT_CLIPPY_FAKE_UNREADABLE="111,222" \
    bash "$0" "$PWD" "$T/a8" >/dev/null 2>&1
  ck "does NOT refuse (golden runner always has service-context builders)" "$?" "0"
  ck "names the unreadable pids" \
    "$(grep -c 'UNDETERMINED, informational): \[111,222\]' "$T/a8/census.txt" 2>/dev/null)" "1"
  ck "and keeps them SEPARATE from the readable-holders line" \
    "$(grep -c 'READABLE, REFUSING GUARD.*: \[\]' "$T/a8/census.txt" 2>/dev/null)" "1"

  rm -rf "$T"
  echo "SELFTEST: $pass passed, $fail failed"
  [ "$fail" = 0 ]
}

case "${1:-}" in
  --selftest) selftest ;;
  --report)   [ $# -ge 2 ] || usage; report "$2" ;;
  "")         usage ;;
  *)          run_lint "$1" "${2:-$1/.spt-lint}" ;;
esac
