#!/usr/bin/env bash
# gate-w2-f17.sh — doyle's TARGETED re-gate of todlando's F17 fixup on top of f3c8495b, run
# SEQUENTIALLY in his released pool from the gate worktree RE-POINTED (detached) at the fixup tip.
# Everything at f3c8495b (F1-F16, arms A/B1/B2/C, 2403+7+1+1 cells) already holds; this driver
# re-witnesses only what the fixup touches plus the one cell that never executed green:
#   claim . treqs . prebuild . xtask check . clippy -D warnings . nextest LIST (name-assert incl. the
#   NEW classify cell) . spt-daemon + spt-net libs . the three W2 e2e --no-capture (witnesses) .
#   XBOX pair none (helper cell PASS in BOTH raws, Summary==1 each) . mutation D = revert the classify
#   arm on THIS tree (unit cell red) AND on the OWNER tree (kitsubito, helper cell red) . revert.
# Arm D's OLD/NEW come from env (D_OLD / D_NEW, exact source lines of the fixup) — REFUSED if unset.
set -u
GW=/c/Users/decid/Documents/projects/spt-core/.worktrees/gate-w2-401a19ad
POOL='C:\Users\decid\Documents\projects\spt-core\.worktrees\ws272-w2\target'
KW=/home/reavus/spt-core-gate-w2
TIP=${TIP:?TIP=<fixup sha> required}
: "${D_OLD:?D_OLD required}"; : "${D_NEW:?D_NEW required}"; : "${CLASSIFY_CELL:?CLASSIFY_CELL=<new unit cell name> required}"
OUT=$GW/.spt/gate-f17; PAIR=$GW/.spt/twohost-web-xbox; mkdir -p "$OUT"; cd "$GW" || exit 9
if ! mkdir "$OUT/lock" 2>/dev/null; then echo "REFUSED: $OUT/lock exists — another battery owns this output dir" >&2; exit 9; fi
trap 'rmdir "$OUT/lock" 2>/dev/null' EXIT
export CARGO_TARGET_DIR="$POOL"
unset OWL_SESSION_ID SPT_AGENT_ID SPT_ENDPOINT_ID SPT_HOME SPT_POOL_UNCHECKED
LOG=$OUT/driver.log
leg() { local n=$1; shift; echo "[$(date -u +%H:%M:%SZ)] LEG $n START" >> "$LOG"; "$@" > "$OUT/$n.raw" 2>&1; local e=$?; echo "$e" > "$OUT/$n.exit"; echo "[$(date -u +%H:%M:%SZ)] LEG $n EXIT $e summaries=$(grep -c 'Summary \[' "$OUT/$n.raw") panics=$(grep -c 'panicked at' "$OUT/$n.raw") free_gb=$(df -BG --output=avail /c 2>/dev/null | tail -1 | tr -dc 0-9)" >> "$LOG"; }
pairline() {
  for r in a b; do
    echo "  xbox $1 $r: exit=$(cat "$PAIR/$1/$r.exit" 2>/dev/null) summaries=$(grep -c 'Summary \[' "$PAIR/$1/$r.raw" 2>/dev/null) serve_for=$(grep -c 'WEB_SERVE_FOR:' "$PAIR/$1/$r.raw" 2>/dev/null) web_stream=$(grep -c 'WEB_STREAM' "$PAIR/$1/$r.raw" 2>/dev/null) unknown=$(grep -c 'family=Unknown' "$PAIR/$1/$r.raw" 2>/dev/null) zero_s_cells=$(grep -cE 'PASS \[ +0\.0[0-9]s\]' "$PAIR/$1/$r.raw" 2>/dev/null)" >> "$LOG"
    grep -E 'PASS|FAIL|TIMEOUT' "$PAIR/$1/$r.raw" 2>/dev/null | grep two_host_web | sed 's/^/    /' >> "$LOG"
  done
}

# identity = the checked-out REF, never the dir name (ir57)
HEAD=$(git rev-parse HEAD)
[ "$HEAD" = "$TIP" ] || { echo "REFUSED: HEAD $HEAD != TIP $TIP — re-point the gate tree first" | tee -a "$LOG" >&2; exit 9; }
' ' ')" >> "$LOG"
echo "gate-w2-f17 at $HEAD dirty_tracked=$(git status --short -uno | wc -l) $(date -u +%FT%TZ) treqs=$(traceable-reqs --version) pool=$POOL" > "$LOG"
echo "frozen=${FROZEN:-UNFROZEN} $(sha256sum "${FROZEN:-.spt}"/gate-w2-f17.sh "${FROZEN:-.spt}"/twohost-web-xbox.sh "${FROZEN:-.spt}"/mutate.py 2>/dev/null | cut -c1-12 | tr '
echo "procs-before: cargo=$(tasklist | grep -ci '^cargo') nextest=$(tasklist | grep -ci nextest) rustc=$(tasklist | grep -ci '^rustc') env-leak: OWL=${OWL_SESSION_ID:-unset} AGENT=${SPT_AGENT_ID:-unset} EP=${SPT_ENDPOINT_ID:-unset} HATCH=${SPT_POOL_UNCHECKED:-unset}" >> "$LOG"
echo "kitsubito clone: $(ssh reavus@kitsubito "cd $KW && git rev-parse HEAD && git status --porcelain | wc -l" 2>&1 | tr '\n' ' ')" >> "$LOG"
echo "arm D sites on this tree: $(grep -cF -- "$D_OLD" crates/spt-daemon/src/dispatch.rs) (must be 1)" >> "$LOG"

leg 0-claim env SPT_POOL_UNCHECKED=1 cargo run -p xtask -- pool-claim --foreign-pool --pool "$POOL" --label "gate-w2-f17-${TIP:0:8}"
echo "claim verdict: $(grep -m1 -E 'CLAIM|claim|TAKEOVER|REFUS|POOL' "$OUT/0-claim.raw" | head -1)" >> "$LOG"
leg 1-treqs    traceable-reqs check
leg 2-prebuild cargo build -p spt -p mock-adapter --bins
leg 4-xtask    cargo run -p xtask -- check
leg 5-clippy   cargo clippy --workspace --all-targets -- -D warnings

FILTER='((package(spt-msg) | package(spt-store) | package(spt-daemon) | package(spt-net)) & kind(lib)) | (package(spt) & (kind(bin) | binary(io_events_undriven_kinds_e2e) | binary(webserve_attachment_e2e) | binary(webserve_cross_node_e2e)))'
leg 6-list cargo nextest list -E "$FILTER"
for want in "$CLASSIFY_CELL" a_reap_shaped_pass_cannot_clobber_a_concurrent_add a_msg_envelope_is_excerpted_by_its_text_and_other_envelopes_are_untouched \
            a_typed_msg_envelope_still_carries_the_recipients_monic a_typed_user_msg_envelope_is_still_verbatim_and_monicless \
            a_typed_msg_envelope_carries_the_trust_warning a_senders_own_monic_and_warning_are_stripped_before_ours_are_attached \
            the_one_short_id_names_the_message_on_both_edges an_attachment_is_snapshot_served_fetched_back_and_named_by_its_message \
            a_scoped_entry_is_still_served_on_loopback; do
  echo "list-has $want: $(grep -c "$want" "$OUT/6-list.raw")" >> "$LOG"
done
echo "list-has xnode binary: $(grep -c 'webserve_cross_node_e2e' "$OUT/6-list.raw")" >> "$LOG"

leg 7-libs     cargo nextest run --no-fail-fast -E '(package(spt-daemon) | package(spt-net)) & kind(lib)'
echo "classify cell in 7-libs: PASS=$(grep -E "$CLASSIFY_CELL" "$OUT/7-libs.raw" | grep -c PASS)" >> "$LOG"
leg 8-ioedges  cargo nextest run --no-fail-fast -p spt --test io_events_undriven_kinds_e2e --no-capture
leg 9-attach   cargo nextest run --no-fail-fast -p spt --test webserve_attachment_e2e --no-capture
leg 10-xnode   cargo nextest run --no-fail-fast -p spt --test webserve_cross_node_e2e --no-capture
for w in 'W2_ARM=one-short-id' 'W2_ARM=fetch-exit3' 'F1_ARM='; do echo "witness $w: ioedges=$(grep -c "$w" "$OUT/8-ioedges.raw") attach=$(grep -c "$w" "$OUT/9-attach.raw") xnode=$(grep -c "$w" "$OUT/10-xnode.raw")" >> "$LOG"; done

# (5) THE witness: cross-box pair on the real hosts, owner = kitsubito clone at TIP, no mutation.
LBL="f17-${TIP:0:8}"
WAIT=600 leg 11-xbox-none bash "${FROZEN:-.spt}/twohost-web-xbox.sh" "$GW" "$KW" "$LBL-none" none
pairline "$LBL-none"
B_SF=$(grep -c 'WEB_SERVE_FOR:' "$PAIR/$LBL-none/b.raw" 2>/dev/null); B_REG=$(grep -c 'WEB_SERVE_FOR:.*outcome=registered' "$PAIR/$LBL-none/b.raw" 2>/dev/null)
# a real round trip at f3c8495b took ~0.2 s (deny 0.195 s, fetch 0.203 s); only the 0.0x s shape is the env-never-arrived skip
A_HELP=$(grep -E 'two_host_web_helper_role_a' "$PAIR/$LBL-none/a.raw" 2>/dev/null | grep -E 'PASS \[ +[0-9]+\.[0-9]+s\]' | grep -vE 'PASS \[ +0\.0[0-9]s\]' | grep -c .)
A_ROLEB_SKIP=$(grep -E 'two_host_web_role_b' "$PAIR/$LBL-none/a.raw" 2>/dev/null | grep -cE 'PASS \[ +0\.0[0-9]s\]')
echo "[$(date -u +%H:%M:%SZ)] HELPER WITNESS verdict: owner WEB_SERVE_FOR lines=$B_SF registered=$B_REG, helper_role_a non-skip PASS=$A_HELP, role_b-on-A skipped-as-it-must=$A_ROLEB_SKIP -> $( [ "${B_REG:-0}" -gt 0 ] && [ "${A_HELP:-0}" -gt 0 ] && echo WITNESSED || echo NOT-A-WITNESS )" >> "$LOG"

# (6) mutation D on THIS tree -> the classify unit cell must red; revert; dirty==0
python "${FROZEN:-.spt}/mutate.py" apply D > "$OUT/mut-D.apply" 2>&1
if grep -q 'MUTATION LANDED' "$OUT/mut-D.apply"; then
  leg mD-libs cargo nextest run --no-fail-fast -E '(package(spt-daemon) | package(spt-net)) & kind(lib)'
  echo "mutation D unit: classify cell FAIL=$(grep -E "$CLASSIFY_CELL" "$OUT/mD-libs.raw" | grep -c FAIL) PASS=$(grep -E "$CLASSIFY_CELL" "$OUT/mD-libs.raw" | grep -c PASS)" >> "$LOG"
  python "${FROZEN:-.spt}/mutate.py" revert D > "$OUT/mut-D.revert" 2>&1; echo "[$(date -u +%H:%M:%SZ)] MUTATION D reverted: $(tail -1 "$OUT/mut-D.revert")" >> "$LOG"
else
  echo "[$(date -u +%H:%M:%SZ)] MUTATION D did not land locally (see mut-D.apply)" >> "$LOG"
fi

# (7) mutation D on the OWNER tree (kitsubito) -> the xbox helper cell must red (owner dispatcher drops ServeFor again)
D_OLD="$D_OLD" D_NEW="$D_NEW" WAIT=600 leg 12-xbox-D bash "${FROZEN:-.spt}/twohost-web-xbox.sh" "$GW" "$KW" "$LBL-D" D
pairline "$LBL-D"
echo "[$(date -u +%H:%M:%SZ)] GATE-F17 DONE dirty_tracked=$(git status --short -uno | wc -l) HEAD=$(git rev-parse --short HEAD) kitsubito_dirty=$(ssh reavus@kitsubito "cd $KW && git status --porcelain | wc -l" 2>&1)" >> "$LOG"
echo "procs-after: cargo=$(tasklist | grep -ci '^cargo') nextest=$(tasklist | grep -ci nextest) spt_from_pool=$(wmic process where "ExecutablePath like '%ws272-w2%'" get ProcessId 2>/dev/null | grep -c '[0-9]')" >> "$LOG"
