#!/usr/bin/env bash
# v0.68.0 GOLDEN r3 — the SEVEN acceptance criteria, read deterministically.
# deployah 2026-09-09. Run ONLY after the run is terminal (gh refuses job logs mid-run).
#
#   ./accept-r3.sh <run-id> <full-40-char-sha>
#
# Both args MANDATORY and validated: a stale/dead target passes liveness predicates HARDER
# than a live one, so there is no default here. The CASCADE's amended seven are authoritative;
# section 0's shorter list is a KNOWN GAP.
set -uo pipefail
REPO=BigscreenVR/spt-bs-core
RUN="${1:?usage: accept-r3.sh <run-id> <full-sha>}"
SHA="${2:?usage: accept-r3.sh <run-id> <full-sha>}"
[[ "$RUN" =~ ^[0-9]{6,}$ ]]   || { echo "BAD RUN ID: $RUN"; exit 2; }
[[ "$SHA" =~ ^[0-9a-f]{40}$ ]]|| { echo "BAD SHA (need full 40): $SHA"; exit 2; }

D="$(cd "$(dirname "$0")" && pwd)"
LOG="$D/r3-run-$RUN.log"
JOBS="$D/r3-jobs-$RUN.json"
PASS=0; FAIL=0
ok(){ echo "  PASS  $1"; PASS=$((PASS+1)); }
no(){ echo "  FAIL  $1"; FAIL=$((FAIL+1)); }

echo "=== target: run $RUN at sha $SHA ==="
gh api "repos/$REPO/actions/runs/$RUN" --jq '"run_attempt=\(.run_attempt) head_sha=\(.head_sha) status=\(.status) conclusion=\(.conclusion)"'
HEAD=$(gh api "repos/$REPO/actions/runs/$RUN" --jq .head_sha)
[ "$HEAD" = "$SHA" ] || { echo "HEAD SHA MISMATCH: run is $HEAD, expected $SHA — VERDICT VOID"; exit 3; }

# Job set, with every step, from the API (paginated: a job list can exceed one page).
gh api --paginate "repos/$REPO/actions/runs/$RUN/jobs?per_page=100" > "$JOBS"

echo
echo "=== C7: run terminal, EVERY job green, expect NINE ==="
RSTAT=$(gh api "repos/$REPO/actions/runs/$RUN" --jq .status)
RCONC=$(gh api "repos/$REPO/actions/runs/$RUN" --jq .conclusion)
NJOBS=$(jq '[.jobs[]]|length' "$JOBS")
echo "run status=$RSTAT conclusion=$RCONC jobs=$NJOBS"
jq -r '.jobs[]|"  job: \(.name) | \(.status) | \(.conclusion)"' "$JOBS"
NONTERM=$(jq '[.jobs[]|select(.status!="completed")]|length' "$JOBS")
NOTGREEN=$(jq -r '[.jobs[]|select(.conclusion!="success")]|length' "$JOBS")
[ "$RSTAT" = completed ] && ok "run terminal" || no "run not terminal (status=$RSTAT)"
[ "$NONTERM" = 0 ]       && ok "zero non-terminal jobs" || no "$NONTERM non-terminal jobs"
[ "$NOTGREEN" = 0 ]      && ok "every job success" || { no "$NOTGREEN job(s) not success"; jq -r '.jobs[]|select(.conclusion!="success")|"        RED: \(.name) -> \(.conclusion)"' "$JOBS"; }
[ "$NJOBS" -ge 9 ]       && ok "job count $NJOBS >= 9 (twohost legs + notify materialized)" \
                         || no "job count $NJOBS < 9 — an early job list is NOT the run's job set"

echo
echo "=== C2: the WINDOWS 'Docs drift gate' STEP conclusion (skip != pass) ==="
# Read the STEP, never the job: the step has SKIPPED FIVE TIMES while its job stayed green,
# and a green LINUX docs gate is not Windows evidence.
jq -r '.jobs[]|select(.name|test("Windows|hfenduleam"))|.name as $j|.steps[]?|select(.name|test("(?i)docs drift"))|"  \($j) :: \(.name) -> status=\(.status) conclusion=\(.conclusion)"' "$JOBS"
WDOCS=$(jq -r '[.jobs[]|select(.name|test("Windows|hfenduleam"))|.steps[]?|select(.name|test("(?i)docs drift"))|.conclusion]|join(",")' "$JOBS")
if [ -z "$WDOCS" ]; then no "no Windows 'Docs drift gate' STEP found at all — absence is not a pass"
elif echo "$WDOCS" | grep -q 'skipped'; then no "Windows docs drift STEP SKIPPED ($WDOCS) — a skip is NOT a pass"
elif [ "$WDOCS" = success ] || ! echo "$WDOCS" | grep -qv success; then ok "Windows docs drift STEP success ($WDOCS)"
else no "Windows docs drift STEP not success ($WDOCS)"; fi
echo "  (linux docs drift step, for contrast only — NOT evidence for the Windows criterion:)"
jq -r '.jobs[]|select(.name|test("Linux|kitsubito"))|.name as $j|.steps[]?|select(.name|test("(?i)docs drift"))|"    \($j) :: \(.conclusion)"' "$JOBS"

echo
echo "=== fetching run log (gh refuses this mid-run; run is terminal now) ==="
gh run view "$RUN" --repo "$REPO" --log > "$LOG" 2>"$LOG.err"
echo "log bytes: $(wc -c < "$LOG")  (stderr: $(wc -c < "$LOG.err") bytes)"
[ -s "$LOG" ] || { echo "EMPTY LOG — every log-based criterion below is VACUOUS, not passing"; exit 4; }

echo
echo "=== C1/C3: FLOOR_DOCS and FLOOR_END ==="
for F in FLOOR_DOCS FLOOR_END; do
  N=$(grep -c "$F" "$LOG"); RC=$?
  [ $RC -gt 1 ] && { no "$F grep BROKE (exit $RC) — reading is vacuous"; continue; }
  echo "  $F occurrences: $N"
  grep -o "$F[^ ]* *[A-Z]*" "$LOG" | sort | uniq -c | sed 's/^/    /'
  if [ "$N" -eq 0 ]; then no "$F absent — absence is not a pass"
  elif grep -q "$F.*FAIL" "$LOG"; then no "$F reports FAIL"
  elif grep -q "$F.*PASS" "$LOG"; then ok "$F PASS"
  else no "$F present but neither PASS nor FAIL matched — read it by hand"; fi
done

echo
echo "=== C4: Summary lines == 2 ==="
# Two nextest legs => exactly two Summary lines. More than two = a doubled run; the
# FAIL attribution would be forged. Fewer = a leg never summarised.
SUM=$(grep -c 'Summary \[' "$LOG")
echo "  Summary lines: $SUM"
grep -n 'Summary \[' "$LOG" | sed 's/^/    /'
[ "$SUM" -eq 2 ] && ok "Summary lines == 2" || no "Summary lines == $SUM, expected exactly 2"

echo
echo "=== C5/C6: twohost roles — B's verdict from B's OWN SERVED count ==="
grep -nE 'two_host_web_helper_role_a|two_host_web_role_b' "$LOG" | head -40 | sed 's/^/    /'
A_OK=$(jq -r '[.jobs[]|select(.name|test("(?i)twohost|role_a|helper"))|select(.conclusion=="success")]|length' "$JOBS")
echo "  --- role_b SERVED evidence (B's own count, never A's poll) ---"
grep -nE 'SERVED|served=|role_b .*serve' "$LOG" | head -30 | sed 's/^/    /'
echo "  ^ inspect the above by hand before ticking C5/C6; this script does not guess a served count."

echo
echo "=== TALLY (mechanical criteria only) ==="
echo "PASS=$PASS FAIL=$FAIL   — C5/C6 twohost roles are a HAND read against the lines above."
[ "$FAIL" -eq 0 ] && echo "MECHANICAL CRITERIA ALL GREEN" || echo "MECHANICAL CRITERIA RED -> RCA to doyle, no rate argument, no same-sha rerun"
exit $([ "$FAIL" -eq 0 ] && echo 0 || echo 1)
