#!/usr/bin/env bash
# Stop hook: refuses to let the session end until verify-slate.sh actually passes.
#
# Contract: exit 2 + stderr => turn is blocked, stderr is fed back to Claude as the
# reason to keep working. exit 0 => stop is allowed.
#
# Two deliberate choices:
#  * We do NOT unconditionally succeed when stop_hook_active is true. The usual
#    guidance does that to avoid infinite loops, but it makes the gate one-shot --
#    Claude blocks once, then walks. Instead we bound the loop ourselves (MAX_BLOCKS)
#    and fail OPEN with a loud message, so a genuinely stuck run still terminates.
#  * The harness also caps consecutive blocks; raise it at launch with
#    CLAUDE_CODE_STOP_HOOK_BLOCK_CAP or this gate gets overridden early.
set -uo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VERIFY="${SLATE_VERIFY:-$HERE/../verify-slate.sh}"   # sibling of .claude/, not of SLATE_DIR
PORT="${SLATE_PORT:-8078}"
MAX_BLOCKS="${SLATE_MAX_BLOCKS:-60}"

input=$(cat)
sid=$(printf '%s' "$input" | python3 -c 'import json,sys;print(json.load(sys.stdin).get("session_id","nosession"))' 2>/dev/null || echo nosession)

state="${TMPDIR:-/tmp}/slate-gate-${sid}.count"
count=$(cat "$state" 2>/dev/null || echo 0)

if [ ! -x "$VERIFY" ]; then
  echo "slate-gate: verifier missing or not executable at $VERIFY -- allowing stop rather than trapping the session" >&2
  exit 0
fi

if reason=$("$VERIFY" 2>&1); then
  rm -f "$state"
  echo "$reason"
  exit 0
fi

count=$((count + 1))
echo "$count" > "$state"

if [ "$count" -ge "$MAX_BLOCKS" ]; then
  rm -f "$state"
  echo "slate-gate: FAILING OPEN after $count blocks. Slate is INCOMPLETE: $reason" >&2
  exit 0
fi

cat >&2 <<EOF
The slate is not finished yet. An objective check (verify-slate.sh) reports:

  $reason

Keep working until that check passes. It re-fetches http://127.0.0.1:${PORT} and
re-counts the concept directories itself, so stating that the work is done does not
satisfy it -- only the artifacts existing and serving does. (block $count/$MAX_BLOCKS)
EOF
exit 2
