#!/bin/sh
# Guard for the UserPromptSubmit hook's declared deadline.
#
# BACKGROUND. plugin/sptc/hooks/hooks.json declared no `timeout` on any event, so Claude Code's 5s
# UserPromptSubmit budget applied by default — against a hook whose own measured p99 was 4835ms
# (n=795 traces / 30.14h / 9 endpoints, 2026-09-10). The adapter shipped sitting ON the line, and
# operators saw "UserPromptSubmit hook timed out after 5s — output discarded" semi-often.
#
# WHY THIS IS A THRESHOLD TEST AND NOT A VALUE PIN. Pinning the literal 20 would go red the day the
# value legitimately rises, and a test that goes red for a correct change is one people learn to
# edit rather than read. The assertion is the property that actually matters:
#
#     a UserPromptSubmit timeout is declared  AND  it exceeds the worst total the hook has recorded
#
# so lowering it back under the measured tail fails, while raising it stays green.
#
# The floor below is the worst COMPLETED total observed on HFENDULEAM (11715ms — one `poll` stage
# stalling 10772ms). It is deliberately a recorded field number, not a guess: this hook's cost is
# ~99% three serial `spt` subprocess calls, so its tail is core-latency-shaped and not something the
# adapter can reason its way to.
# [unit->REQ-HOOK-DEADLINE-VISIBLE]
set -u
ROOT=$(CDPATH= cd "$(dirname "$0")/.." && pwd)
cd "$ROOT" || exit 2
rc=0
ok()   { printf 'ok   %s\n' "$1"; }
fail() { printf 'FAIL: %s\n' "$1"; rc=1; }

HOOKS="plugin/sptc/hooks/hooks.json"
WORST_OBSERVED_MS=11715   # field-measured; see header

[ -f "$HOOKS" ] || { fail "missing file: $HOOKS"; echo "rc=$rc"; exit $rc; }

# --- a timeout is declared on UserPromptSubmit ----------------------------------------------------
# Read the UserPromptSubmit block only: a timeout declared on some OTHER event would satisfy a naive
# whole-file grep while leaving this hook on the 5s default — the exact defect being closed.
ups_block=$(sed -n '/"UserPromptSubmit"/,/\]/p' "$HOOKS")
[ -n "$ups_block" ] || { fail "no UserPromptSubmit block in $HOOKS"; echo "rc=$rc"; exit $rc; }

timeout_s=$(printf '%s' "$ups_block" | sed -n 's/.*"timeout"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' | head -1)
if [ -z "$timeout_s" ]; then
  fail "UserPromptSubmit declares no \"timeout\" — CC's 5s default applies and the hook's p99 is 4835ms"
  echo "rc=$rc"; exit $rc
fi
ok "UserPromptSubmit declares a timeout (${timeout_s}s)"

# --- it exceeds the worst total ever recorded -----------------------------------------------------
timeout_ms=$((timeout_s * 1000))
if [ "$timeout_ms" -gt "$WORST_OBSERVED_MS" ]; then
  ok "declared timeout ${timeout_ms}ms exceeds the worst observed total ${WORST_OBSERVED_MS}ms"
else
  fail "declared timeout ${timeout_ms}ms does NOT exceed the worst observed total ${WORST_OBSERVED_MS}ms"
fi

# --- the BEGIN marker still exists ----------------------------------------------------------------
# The timeout raises the bar; the BEGIN line is what makes a breach VISIBLE. Shipping the first
# without the second would restore the original blindness at a higher threshold — the two are one
# requirement, so the guard refuses to let them separate.
if grep -q 'BEGIN {hook} id=' tools/claude-spt/src/hook.rs; then
  ok "the hook still emits a BEGIN marker (a killed hook stays observable)"
else
  fail "no BEGIN emission in hook.rs — a hook killed at the deadline would leave no evidence again"
fi

echo "rc=$rc"
exit $rc
