#!/usr/bin/env bash
# cpu-triage-run.sh — detached run harness for cpu-triage.sh.
#
# WHY THIS EXISTS
#
# cpu-triage.sh samples for at least 120 s (300 s by default) because anything
# shorter than the reconcile cycle produces contradictory readings — see that
# script's header. Every admin MCP tool completes inside 12 s. So the run has to
# be detached from the call that starts it, and the caller needs a readiness
# signal it can poll.
#
# THE ORDERING IS THE CONTRACT
#
# stdout is redirected to the result file, so that file exists from the FIRST
# BYTE of output and is half-written for the whole sampling window. It is
# therefore NOT a readiness signal. The `.status` marker is, and it is written
# strictly after the measurement process has exited and its output is closed.
# The completion log line is written after that again — a post-condition, never
# an intent. A reader that keys on the `.json` existing reports a half-written
# run as complete, which is the single failure this harness exists to prevent.
#
# EXIT CODES
#   The measurement script's own exit code is recorded in the status marker and
#   is what callers interpret (0 clean, 1 sustained hot core, 2 precondition
#   failure). This harness exits 2 only on its own usage errors.

set -uo pipefail

RUN_ID=""
OUT_DIR=""
LOG_FILE=""
SCRIPT=""

usage() {
  cat >&2 <<USAGE
usage: cpu-triage-run.sh --run-id ID --out-dir DIR --log FILE [--script PATH]
                        [-- <cpu-triage.sh args>...]

  --run-id   identifier for this run; names the output files
  --out-dir  directory receiving cpu-triage-<ID>.json and cpu-triage-<ID>.status
  --log      brand log to append the op=complete line to
  --script   measurement script (default: cpu-triage.sh beside this file)
USAGE
  exit 2
}

while [ $# -gt 0 ]; do
  case "$1" in
    --run-id)  RUN_ID="${2:-}"; shift 2 ;;
    --out-dir) OUT_DIR="${2:-}"; shift 2 ;;
    --log)     LOG_FILE="${2:-}"; shift 2 ;;
    --script)  SCRIPT="${2:-}"; shift 2 ;;
    --)        shift; break ;;
    -h|--help) usage ;;
    *) echo "cpu-triage-run: unknown argument '$1'" >&2; usage ;;
  esac
done

[ -n "$RUN_ID" ] || usage
[ -n "$OUT_DIR" ] || usage
[ -n "$LOG_FILE" ] || usage

case "$RUN_ID" in
  *[!A-Za-z0-9T_-]*) echo "cpu-triage-run: run-id must be [A-Za-z0-9T_-]" >&2; exit 2 ;;
esac

HERE=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
[ -n "$SCRIPT" ] || SCRIPT="$HERE/cpu-triage.sh"

mkdir -p "$OUT_DIR" || exit 2

RESULT="$OUT_DIR/cpu-triage-$RUN_ID.json"
STATUS="$OUT_DIR/cpu-triage-$RUN_ID.status"

# Publish a terminal state. EVERY exit path past this point goes through here.
#
# The caller has already written its meta file and logged op=start by the time
# this harness runs, so an exit that publishes nothing leaves the run readable
# as `running` forever — the no-event blind spot this whole design exists to
# close. The case that made this concrete: the measurement script shipping
# without its executable bit. The caller checks the script EXISTS, which passes,
# and the run then dies here in silence.
publish() {
  local code="$1" hot
  { echo "exit=$code"; [ -n "${2:-}" ] && printf '%s\n' "$2"; } > "$STATUS"

  # Report what is on disk. An absent or unparseable count is `unknown`, never
  # a fabricated 0 — reporting a clean count for a run that produced no report
  # is exactly the false-clean this tool exists to prevent.
  hot=$(grep -o '"sustainedHotCores"[[:space:]]*:[[:space:]]*[0-9]\{1,\}' "$RESULT" 2>/dev/null \
          | head -1 | grep -o '[0-9]\{1,\}$')
  [ -n "$hot" ] || hot="unknown"

  mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null
  printf '%s [cpu-triage] op=complete runId=%s exit=%s sustainedHotCores=%s\n' \
    "$(date -Is 2>/dev/null || date)" "$RUN_ID" "$code" "$hot" >> "$LOG_FILE"
}

if [ ! -x "$SCRIPT" ]; then
  MSG="cpu-triage-run: measurement script not executable: $SCRIPT"
  echo "$MSG" >&2
  publish 2 "$MSG"
  exit 0
fi

ERR=$(mktemp "${TMPDIR:-/tmp}/cpu-triage-err.XXXXXX") || exit 2
trap 'rm -f "$ERR"' EXIT INT TERM

# The measurement. stdout streams into the result file for the whole window.
"$SCRIPT" --json "$@" > "$RESULT" 2> "$ERR"
CODE=$?

# The result file is closed and the exit code is known. Only now does a
# readiness signal exist to publish.
publish "$CODE" "$(cat "$ERR")"

exit 0
