#!/bin/sh
# ATDD post-commit hook — blast-radius local validation.
# Installed by `atdd init`. Always exits 0 (info-only; cannot undo a commit).
#
# Behavior:
#   1. Determines which files were touched in HEAD via `git show --name-only HEAD`.
#   2. Maps file paths to validator phases (planner/tester/coder/coach/repo).
#   3. Runs only the matched phases in parallel via shell backgrounding + wait.
#   4. Exits 0 always — failures are surfaced via stderr but never block.
#   5. No-op when CI=true (CI runs full validate; double-run wastes minutes).
#
# Bypass flag retired (E026): this hook is advisory (always exits 0);
# a bypass of a non-blocking hook has no enforcement value.
#
# Path → phase mapping:
#   plan/**                       → atdd repo validate + atdd validate planner --local --skip-api
#   contracts/**                  → atdd repo validate + atdd validate tester
#   src/atdd/planner/**           → atdd validate planner
#   src/atdd/tester/**            → atdd validate tester
#   src/atdd/coder/**             → atdd validate coder
#   src/atdd/coach/**             → atdd validate coach
#   .atdd/manifest.yaml           → atdd validate coach
#   (anything else)               → no validators run, silent exit 0

set -u  # no `set -e` — we want to keep going even if a validator fails

# --- Agent session capture (#1540) ---
# Records WHICH agent session touched this work_item, read from ambient
# environment. Runs BEFORE the CI bypass and before any validator work:
#   * post-commit, not pre-commit, because this must survive `--no-verify`
#     (agents use it routinely) and can never cost anyone their commit;
#   * a no-op when no agent env var is set — a human commit records nothing
#     and, crucially, clears nothing;
#   * backgrounded and fully muted so it cannot slow or interrupt a commit.
# Always through the `atdd` binary: a bare `python3` cannot import a
# pipx-installed atdd.
( atdd state sessions capture >/dev/null 2>&1 & ) 2>/dev/null || true

# --- CI bypass ---
if [ "${CI:-}" = "true" ]; then
    exit 0
fi

# --- Resolve files in HEAD (works on first-ever commit, unlike HEAD~1..HEAD) ---
FILES=$(git show --pretty=format: --name-only HEAD 2>/dev/null | grep -v '^$' || true)

if [ -z "$FILES" ]; then
    exit 0
fi

# --- Map files to validator phases ---
RUN_REPO=0
RUN_PLANNER=0
RUN_TESTER=0
RUN_CODER=0
RUN_COACH=0

while IFS= read -r f; do
    case "$f" in
        plan/*)                       RUN_REPO=1; RUN_PLANNER=1 ;;
        contracts/*)                  RUN_REPO=1; RUN_TESTER=1 ;;
        src/atdd/planner/*)           RUN_PLANNER=1 ;;
        src/atdd/tester/*)            RUN_TESTER=1 ;;
        src/atdd/coder/*)             RUN_CODER=1 ;;
        src/atdd/coach/*)             RUN_COACH=1 ;;
        .atdd/manifest.yaml)          RUN_COACH=1 ;;
    esac
done <<EOF
$FILES
EOF

# --- Fast path: nothing to validate ---
if [ "$RUN_REPO" = "0" ] && [ "$RUN_PLANNER" = "0" ] && [ "$RUN_TESTER" = "0" ] \
        && [ "$RUN_CODER" = "0" ] && [ "$RUN_COACH" = "0" ]; then
    exit 0
fi

echo "ATDD post-commit: running blast-radius validators..." >&2

# --- core.bare snapshot + restore trap (E022) ---
# Prevents pytester-based SMOKE tests from leaving core.bare=true in the shared
# .git/config even if the pytest process is interrupted (SIGKILL, timeout, OOM).
BARE_BEFORE=$(git config core.bare 2>/dev/null || echo "")
trap '
    if [ -n "$BARE_BEFORE" ]; then
        git config core.bare "$BARE_BEFORE" 2>/dev/null || true
    else
        git config --unset core.bare 2>/dev/null || true
    fi
' EXIT

# --- Fire validators in parallel ---
# Each non-zero RUN_* triggers an async subprocess. We collect PIDs and wait
# on them so the hook only returns after every validator has reported.
PIDS=""

if [ "$RUN_REPO" = "1" ]; then
    ( atdd repo validate >&2 2>&1 ) &
    PIDS="$PIDS $!"
fi

if [ "$RUN_PLANNER" = "1" ]; then
    ( atdd validate planner --local --skip-api >&2 2>&1 ) &
    PIDS="$PIDS $!"
fi

if [ "$RUN_TESTER" = "1" ]; then
    ( atdd validate tester --local --skip-api >&2 2>&1 ) &
    PIDS="$PIDS $!"
fi

if [ "$RUN_CODER" = "1" ]; then
    ( atdd validate coder --local --skip-api >&2 2>&1 ) &
    PIDS="$PIDS $!"
fi

if [ "$RUN_COACH" = "1" ]; then
    ( PYTEST_ADDOPTS="-m 'not slow'" atdd validate coach --local --skip-api >&2 2>&1 ) &
    PIDS="$PIDS $!"
fi

# Wait for all to finish; we don't propagate their exit codes.
for pid in $PIDS; do
    wait "$pid" 2>/dev/null || true
done

# Always exit 0 — post-commit can't undo, only inform.
exit 0
