#!/usr/bin/env bash
# tests/ledger-scan/run-tests.sh -- ledger-scan.sh against fixture docs.
# Verifies: PROPOSED/OPEN decisions surfaced (ADOPTED not), OPEN security rows
# surfaced (CLOSED not), next-free computed from highest, missing-ledger notice.
set -u
SD="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"; SCRIPT="$SD/../../scripts/ledger-scan.sh"
P=0; F=0; ok(){ echo "PASS: $1"; P=$((P+1)); }; no(){ echo "FAIL: $1"; F=$((F+1)); }
W="$(mktemp -d)"; trap 'rm -rf "$W"' EXIT; mkdir -p "$W/docs" "$W/runbooks"

cat > "$W/docs/design-decisions.md" <<'DD'
## D-001: Something adopted
**Status:** ADOPTED 2026-01-01.
## D-050: PROPOSED / OPEN -- keystone policyd override
**Status:** PROPOSED / OPEN (recorded 2026-06-17; no action taken).
## D-063: tighten SG
**Status:** RESOLVED / CLOSED (applied 2026-07-03).
## D-068: Vault substrate hardening
**Status:** PROPOSED / OPEN 2026-07-02.
## D-070: snapshots
**Status:** ADOPTED 2026-07-03.
## D-063b: reopened then closed via amendment
**Status:** PROPOSED / OPEN (recorded).
Some text.
**Status:** RESOLVED / CLOSED (amendment 2026-07-03).
DD
cat > "$W/docs/security-ledger.md" <<'SL'
| id | date | item | src | owner | status |
|---|---|---|---|---|---|
| SEC-001 | 2026-06-26 | libvirt cred | x | operator | OPEN -- rotate |
| SEC-002 | 2026-06-17 | token rule | x | operator | STANDING RULE |
| SEC-003 | 2026-07-03 | unseal custody | D-069 | operator | OPEN -- assign |
| SEC-004 | 2026-05-27 | repo public | x | operator | CLOSED -- flipped private |
SL
# next-free fixtures: mention up to DOCFIX-085, BUNDLEFIX-009 in a doc
printf 'refs: DOCFIX-084 DOCFIX-085 BUNDLEFIX-008 BUNDLEFIX-009 D-070\n' > "$W/runbooks/refs.md"
printf 'Next-free: D-071, DOCFIX-099, BUNDLEFIX-050\n' > "$W/docs/pointer.md"  # must NOT inflate

OUT="$(VR_REPO="$W" bash "$SCRIPT" 2>&1)"; RC=$?
chk(){ grep -q "$1" <<<"$OUT" && ok "$2" || no "$2 (missing: $1)"; }
nochk(){ grep -q "$1" <<<"$OUT" && no "$2 (should be absent: $1)" || ok "$2"; }
[ "$RC" = 0 ] && ok "exit 0" || no "exit 0 (got $RC)"
chk 'D-050' "surfaces D-050 PROPOSED"
chk 'D-068' "surfaces D-068 PROPOSED"
nochk 'D-001' "omits D-001 ADOPTED"
nochk 'D-063' "omits D-063 CLOSED"
nochk 'D-070' "omits D-070 ADOPTED (from decisions section)"
nochk 'D-063b' "omits amendment-CLOSED decision (last-status wins)"
chk 'SEC-001' "surfaces SEC-001 OPEN"
chk 'SEC-003' "surfaces SEC-003 OPEN"
nochk 'SEC-004' "omits SEC-004 CLOSED"
grep -q 'SEC-002' <<<"$OUT" && no "omits SEC-002 STANDING (not open)" || ok "omits SEC-002 STANDING"
chk 'next-free=071' "D next-free 071 (header-authoritative)"
chk 'next-free=086' "DOCFIX next-free 086 (next-free pointer 099 excluded)"
chk 'next-free=010' "BUNDLEFIX next-free 010"
# missing ledger notice
OUT2="$(VR_REPO="$W" bash "$SCRIPT" 2>&1)"; grep -q 'NO docs/session-ledger.md' <<<"$OUT2" && ok "flags missing session-ledger" || no "flags missing session-ledger"
# with a ledger present, notice changes
echo "ledger" > "$W/docs/session-ledger.md"
OUT3="$(VR_REPO="$W" bash "$SCRIPT" 2>&1)"; grep -q 'ledger present' <<<"$OUT3" && ok "detects present session-ledger" || no "detects present session-ledger"


# ---------------- --fences mode: fence integrity validation ----------------
ec(){ [ "$1" = "$2" ] && ok "$3" || no "$3 (rc=$1 want=$2)"; }
has(){ grep -q "$1" <<<"$2" && ok "$3" || no "$3 (missing: $1)"; }
FW="$(mktemp -d)"; mkdir -p "$FW/docs"
mkledgerf(){ printf '%s\n' "$1" > "$FW/docs/session-ledger.md"; }
runf(){ VR_REPO="$FW" bash "$SCRIPT" --fences 2>&1; }

mkledgerf '# Ledger
<!-- SECTION: main-chat | OWNER: main claude.ai chat stream only -->
stuff
<!-- END: main-chat -->
<!-- SECTION: jumphost | OWNER: Claude Code jumphost stream only -->
more
<!-- END: jumphost -->'
OUT="$(runf)"; ec "$?" 0 "fences well-formed exit0"; has 'FENCE VALIDATION: OK' "$OUT" "fences OK message"

mkledgerf '<!-- SECTION: jumphost | OWNER: x -->
no end'
OUT="$(runf)"; ec "$?" 1 "fences unclosed exit1"; has 'unclosed SECTION' "$OUT" "reports unclosed"

mkledgerf 'text
<!-- END: jumphost -->'
OUT="$(runf)"; ec "$?" 1 "fences orphan-END exit1"; has 'with no open SECTION' "$OUT" "reports orphan END"

mkledgerf '<!-- SECTION: main-chat | OWNER: x -->
<!-- END: jumphost -->'
OUT="$(runf)"; ec "$?" 1 "fences mismatch exit1"; has 'does not match open SECTION' "$OUT" "reports mismatch"

mkledgerf '<!-- SECTION: main-chat | OWNER: x -->
<!-- SECTION: jumphost | OWNER: y -->
<!-- END: jumphost -->
<!-- END: main-chat -->'
OUT="$(runf)"; ec "$?" 1 "fences nested exit1"; has 'no nesting' "$OUT" "reports nesting"

mkledgerf '<!-- SECTION: jumphost | OWNER: x -->
<!-- END: jumphost -->
<!-- SECTION: jumphost | OWNER: x -->
<!-- END: jumphost -->'
OUT="$(runf)"; ec "$?" 1 "fences duplicate exit1"; has 'duplicate SECTION name' "$OUT" "reports duplicate"

mkledgerf '<!-- SECTION: bogus | OWNER: x -->
<!-- END: bogus -->'
OUT="$(runf)"; ec "$?" 0 "fences unknown-name non-fatal exit0"; has 'unknown section name' "$OUT" "warns unknown name"

mkledgerf '# Ledger
prose only, no fences'
OUT="$(runf)"; ec "$?" 0 "fences none exit0"; has 'no fences yet' "$OUT" "transition-OK note"

mkledgerf '<!-- SECTION: shared | OWNER: -->
<!-- END: shared -->'
OUT="$(runf)"; ec "$?" 0 "fences missing-owner non-fatal exit0"; has 'missing/empty OWNER' "$OUT" "warns missing/empty owner"

OUT="$(VR_REPO="$W" bash "$SCRIPT" 2>&1)"; has 'next-free' "$OUT" "default mode intact (next-free present)"

echo; [ "$F" = 0 ] && { echo "ALL PASS ($P checks)"; exit 0; } || { echo "FAILURES: $F"; exit 1; }
