#!/usr/bin/env bash
# Box-side half of seat-recovery.test.sh. Never run this on the workstation: it fabricates
# ~/.rb state, and it only does so safely because HOME is redirected to a sandbox first.
set -uo pipefail

STAGE="${1:?stage dir required}"
REAL_HOME="$HOME"
export PATH="$REAL_HOME/.local/bin:$PATH"
RECONCILE="$STAGE/seat-reconcile.sh"
chmod +x "$RECONCILE"

PASS=0 FAIL=0
ok()   { PASS=$((PASS+1)); echo "PASS $1"; }
bad()  { FAIL=$((FAIL+1)); echo "FAIL $1"; }
check(){ [[ "$2" == "$3" ]] && ok "$1 ($2)" || bad "$1: expected [$3], got [$2]"; }

read -r BOOT_ID < /proc/sys/kernel/random/boot_id
STALE_BOOT="00000000-0000-0000-0000-00000000dead"

# HOME is the whole blast radius. Everything below writes only under it.
export HOME="$STAGE/home"
mkdir -p "$HOME/.rb/jobs" "$HOME/.rb/seats" "$HOME/.local/share" "$HOME/.config"
# podman keys its storage off HOME. Left alone it would build a second image store inside the
# sandbox — and the reap assertion would then be testing a container the real podman never saw.
for d in .local/share/containers .config/containers; do
  mkdir -p "$REAL_HOME/$d"; ln -sfn "$REAL_HOME/$d" "$HOME/$d"
done

# --- fixture: a mirror with a seat's uncommitted work in it -----------------------------------
MIRROR="$HOME/builds/recovery-mirror"
mkdir -p "$MIRROR"
git -C "$MIRROR" init -q
printf 'committed\n' > "$MIRROR/tracked.txt"
git -C "$MIRROR" add -A
git -C "$MIRROR" -c user.name=t -c user.email=t@t commit -q -m base
BASE_SHA="$(git -C "$MIRROR" rev-parse HEAD)"
# what an agent had in flight when the power went: one edit, one new file, neither committed
printf 'edited by the seat\n' > "$MIRROR/tracked.txt"
printf 'agent work in progress\n' > "$MIRROR/untracked.txt"

# the exact single-line shape seat-run.sh writes, so the reconciler is tested against the real one
seat() { # seat <runId> <jobId> <bootId> <phase> [mirror]
  mkdir -p "$HOME/.rb/seats/$1"
  printf '{"runId":"%s","jobId":"%s","mirrorPath":"%s","workspaceRel":".","wrapper":"codex.sh","taskSlug":"t","host":"h","bootId":"%s","phase":"%s","rc":null,"at":"now"}\n' \
    "$1" "$2" "${5:-$MIRROR}" "$3" "$4" > "$HOME/.rb/seats/$1/state.json"
}
job() { # job <jobId> [mtimeEpoch]
  mkdir -p "$HOME/.rb/jobs/$1"
  printf '{"key":"x"}\n' > "$HOME/.rb/jobs/$1/meta.json"
  printf 'log line\n' > "$HOME/.rb/jobs/$1/log"
  [[ -n "${2:-}" ]] && touch -d "@$2" "$HOME/.rb/jobs/$1"
  true
}

seat SEATOLD  JOBOLD  "$STALE_BOOT" running
seat SEATLIVE JOBLIVE "$BOOT_ID"    running
seat SEATDONE JOBDONE "$STALE_BOOT" done
job JOBOLD; job JOBLIVE; job JOBDONE
# a plain build job from a previous boot: dir mtime predates this boot
job JOBORPHAN 1000000000
# a plain build job from THIS boot that is merely between create and start
job JOBFRESH

# a container that must be reaped, and one from another project that must not be
FIXTURE_IMAGE=docker.io/library/alpine:3.20
podman run -d --name harness-seat-SEATOLD --entrypoint /bin/sleep "$FIXTURE_IMAGE" 300 >/dev/null 2>&1
BYSTANDER="seat-recovery-bystander-$$"
podman run -d --name "$BYSTANDER" --entrypoint /bin/sleep "$FIXTURE_IMAGE" 300 >/dev/null 2>&1

# --- the pass ----------------------------------------------------------------------------------
"$RECONCILE" boot 2>"$STAGE/boot.err"
check "boot pass exits clean" "$?" 0

RESCUE="refs/harness-seat/SEATOLD"
git -C "$MIRROR" rev-parse -q --verify "$RESCUE" >/dev/null
check "the interrupted seat's work is rescued to a ref" "$?" 0
check "the rescued ref carries the seat's EDIT to a tracked file" \
  "$(git -C "$MIRROR" show "$RESCUE:tracked.txt" 2>/dev/null)" "edited by the seat"
check "the rescued ref carries the seat's UNTRACKED file" \
  "$(git -C "$MIRROR" show "$RESCUE:untracked.txt" 2>/dev/null)" "agent work in progress"
check "the rescue does not move the mirror's HEAD" "$(git -C "$MIRROR" rev-parse HEAD)" "$BASE_SHA"
check "the rescue leaves the mirror's own index alone" \
  "$(git -C "$MIRROR" diff --cached --name-only | wc -l)" "0"

# THE point of the whole mechanism: the transport's destroy step can no longer lose the work
git -C "$MIRROR" checkout -qf "$BASE_SHA" && git -C "$MIRROR" clean -qffd
check "the seat's work survives the checkout+clean that destroys the mirror tree" \
  "$(git -C "$MIRROR" show "$RESCUE:untracked.txt" 2>/dev/null)" "agent work in progress"

check "the interrupted seat's rb job is finalized 124 (dispatched, outcome unknown)" \
  "$(< "$HOME/.rb/jobs/JOBOLD/rc")" "124"
grep -q 'rebooted while this job was in flight' "$HOME/.rb/jobs/JOBOLD/log"
check "the job log says why it ended" "$?" 0
check "the seat record is settled" \
  "$(sed -n 's/.*"phase":"\([^"]*\)".*/\1/p' "$HOME/.rb/seats/SEATOLD/state.json")" "rebooted"
check "the settled record carries the reported rc" \
  "$(sed -n 's/.*"rc":\([^,}]*\).*/\1/p' "$HOME/.rb/seats/SEATOLD/state.json")" "124"

# --- the reconciler must not invent outcomes for live work --------------------------------------
[[ -f "$HOME/.rb/jobs/JOBLIVE/rc" ]]
check "a seat from THIS boot is left running" "$?" 1
[[ -f "$HOME/.rb/jobs/JOBFRESH/rc" ]]
check "a job dir created since boot is left alone" "$?" 1
[[ -f "$HOME/.rb/jobs/JOBDONE/rc" ]]
check "an already-settled seat is not touched" "$?" 1
check "a plain build job orphaned by the reboot is finalized 254" \
  "$(< "$HOME/.rb/jobs/JOBORPHAN/rc")" "254"

# --- containers ---------------------------------------------------------------------------------
check "the dead seat container is reaped" \
  "$(podman ps -a --filter 'name=harness-seat-SEATOLD' -q | grep -c .)" "0"
check "another project's container is NOT touched" \
  "$(podman ps -a --filter "name=$BYSTANDER" -q | grep -c .)" "1"
podman rm -f "$BYSTANDER" >/dev/null 2>&1

# --- the stamp and the guard --------------------------------------------------------------------
check "the pass stamps this boot as reconciled" "$(< "$HOME/.rb/seats/.reconciled")" "$BOOT_ID"
seat SEATLATE JOBLATE "$STALE_BOOT" running; job JOBLATE
"$RECONCILE" guard "$MIRROR" 2>/dev/null
[[ -f "$HOME/.rb/jobs/JOBLATE/rc" ]]
check "guard is a no-op once this boot is stamped" "$?" 1

# fail-closed: no stamp for this boot means reconcile now, whatever else is true
rm -f "$HOME/.rb/seats/.reconciled"
printf 'late seat work\n' > "$MIRROR/late.txt"
"$RECONCILE" guard "$MIRROR" 2>/dev/null
check "an unstamped boot makes guard reconcile before the mirror is rewritten" \
  "$(< "$HOME/.rb/jobs/JOBLATE/rc")" "124"
check "guard rescued the late seat's work too" \
  "$(git -C "$MIRROR" show refs/harness-seat/SEATLATE:late.txt 2>/dev/null)" "late seat work"

# guard runs INSIDE the caller's mirror lock — taking it again would hang the transport forever
rm -f "$HOME/.rb/seats/.reconciled"
seat SEATLOCK JOBLOCK "$STALE_BOOT" running; job JOBLOCK
printf 'locked seat work\n' > "$MIRROR/locked.txt"
( exec {fd}>"$HOME/.rb/mat-$(basename "$MIRROR").lock"; flock "$fd"; \
  timeout 30 "$RECONCILE" guard "$MIRROR" 2>/dev/null )
check "guard does not deadlock on the mirror lock its caller already holds" "$?" 0
check "and it still rescued that mirror's seat" \
  "$(git -C "$MIRROR" show refs/harness-seat/SEATLOCK:locked.txt 2>/dev/null)" "locked seat work"

# a mirror locked by SOMEONE ELSE must be left to that holder, and the boot must stay unstamped
rm -f "$HOME/.rb/seats/.reconciled"
OTHER="$HOME/builds/other-mirror"
mkdir -p "$OTHER"; git -C "$OTHER" init -q
printf 'x\n' > "$OTHER/f"; git -C "$OTHER" add -A
git -C "$OTHER" -c user.name=t -c user.email=t@t commit -q -m base
printf 'other seat work\n' > "$OTHER/wip.txt"
seat SEATOTHER JOBOTHER "$STALE_BOOT" running "$OTHER"; job JOBOTHER
exec {hold}>"$HOME/.rb/mat-$(basename "$OTHER").lock"
flock "$hold"
timeout 60 "$RECONCILE" boot 2>/dev/null
check "a mirror held by a peer does not block the pass" "$?" 0
[[ -f "$HOME/.rb/seats/.reconciled" ]]
check "a skipped rescue withholds the stamp so the peer's guard redoes it" "$?" 1
[[ -f "$HOME/.rb/jobs/JOBOTHER/rc" ]]
check "a skipped seat is not settled behind the peer's back" "$?" 1
exec {hold}>&-
"$RECONCILE" boot 2>/dev/null
check "once the peer lets go, the skipped seat's work is rescued" \
  "$(git -C "$OTHER" show refs/harness-seat/SEATOTHER:wip.txt 2>/dev/null)" "other seat work"
check "and the boot is stamped now that nothing was skipped" "$(< "$HOME/.rb/seats/.reconciled")" "$BOOT_ID"

# --- idempotence --------------------------------------------------------------------------------
BEFORE="$(git -C "$MIRROR" rev-parse "$RESCUE")"
"$RECONCILE" boot 2>/dev/null; "$RECONCILE" boot 2>/dev/null
check "repeated passes do not rewrite a rescue ref" "$(git -C "$MIRROR" rev-parse "$RESCUE")" "$BEFORE"

HOME="$REAL_HOME"
echo "---- seat-recovery: $PASS passed, $FAIL failed"
[[ "$FAIL" -eq 0 ]]
