← back to Govarbitrage

apps/mobile/device-proof-evidence/readiness-probe.sh

74 lines

#!/bin/bash
# TK-10279 — consolidated submit-readiness probe. Read-only, $0 local.
# Emits one JSON object of every gate GovArbitrage's 2.1 response depends on.
# PASS overall == everything but the physical recording + the (gated) Apple send is ready.
# Usage: ./readiness-probe.sh [path-to-recording.mov]   (recording arg optional)
set -uo pipefail
cd "$(dirname "$0")"
REC="${1:-}"
BASE="https://auctions.agentabrams.com"

json_bool(){ [ "$1" = "1" ] && echo true || echo false; }

# --- GATE: backend (reviewer hits this) ---
b_root=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 "$BASE" 2>/dev/null)
b_priv=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 "$BASE/privacy" 2>/dev/null)
b_list_code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 20 "$BASE/api/listings" 2>/dev/null)
b_total=$(curl -s --max-time 20 "$BASE/api/listings" 2>/dev/null | sed -n 's/.*"total":\([0-9]*\).*/\1/p' | head -1)
backend_ok=0; [ "$b_root" = 200 ] && [ "$b_priv" = 200 ] && [ "$b_list_code" = 200 ] && [ "${b_total:-0}" -gt 0 ] 2>/dev/null && backend_ok=1

# --- GATE: reply-text source accuracy (must name every live source enum) ---
reply_ok=1
for s in GovDeals GovPlanet "GSA Auctions" "Public Surplus" GoIndustry; do
  grep -qi "$s" ../ASC-PASTE-KIT.md || reply_ok=0
done

# --- GATE: verifier tooling present + executable ---
tool_ok=0; [ -x ./verify-recording.sh ] && tool_ok=1

# --- GATE: physical recording + manual privacy review ---
rec_status="ABSENT"; rec_file=""; privacy_status="ABSENT"
[ -z "$REC" ] && REC=$(ls -t ./govarbitrage-DEVICE-*.mov ./govarbitrage-DEVICE-*.mp4 2>/dev/null | head -1)
if [ -n "$REC" ] && [ -f "$REC" ] && [[ "$(basename "$REC")" == govarbitrage-DEVICE-* ]]; then
  rec_file="$REC"
  if [ -x ./verify-recording.sh ] && ./verify-recording.sh "$REC" >/dev/null 2>&1; then
    rec_status="TECH_PASS_PRIVACY_PENDING"
    if [ -f "$REC.privacy-reviewed.sha256" ] && (cd "$(dirname "$REC")" && shasum -a 256 -c "$(basename "$REC").privacy-reviewed.sha256") >/dev/null 2>&1; then
      privacy_status="PASS"
      rec_status="PASS"
    fi
  else
    rec_status="FAIL"
  fi
elif [ -n "$REC" ] && [ -f "$REC" ]; then
  rec_file="$REC"
  rec_status="REJECTED_NOT_DEVICE_NAMED"
fi
rec_ok=0; [ "$rec_status" = PASS ] && rec_ok=1

# --- GATE: ASC artifact state (read-only; best-effort) ---
asc_line=$(ASC_KEY_PATH="${ASC_KEY_PATH:-$HOME/.appstoreconnect/private_keys/AuthKey_72Y2TZT54R.p8}" \
  ASC_KEY_ID="${ASC_KEY_ID:-72Y2TZT54R}" \
  timeout 90 node "$HOME/.claude/skills/ipa-status/scripts/ipa-status.mjs" --ready 2>/dev/null | grep -i GovArbitrage | head -1)
asc_ok=0; printf '%s' "$asc_line" | grep -qi "SUBMIT-READY" && asc_ok=1

# overall = everything automatable green (recording is the human gate, reported separately)
auto_ok=0; [ $backend_ok = 1 ] && [ $reply_ok = 1 ] && [ $tool_ok = 1 ] && [ $asc_ok = 1 ] && auto_ok=1

cat <<JSON
{
  "ticket": "TK-10279",
  "ts": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "gates": {
    "backend":   { "ok": $(json_bool $backend_ok), "root": "$b_root", "privacy": "$b_priv", "listings": "$b_list_code", "total": ${b_total:-0} },
    "reply_text":{ "ok": $(json_bool $reply_ok), "note": "names GovDeals/GovPlanet/GSA/Public Surplus/GoIndustry" },
    "verifier":  { "ok": $(json_bool $tool_ok), "path": "verify-recording.sh" },
    "asc":       { "ok": $(json_bool $asc_ok), "state": "$(printf '%s' "$asc_line" | sed 's/^[^A-Za-z]*//; s/"/'"'"'/g' | tr -s ' ')" },
    "recording": { "ok": $(json_bool $rec_ok), "status": "$rec_status", "privacy_review": "$privacy_status", "file": "$rec_file", "note": "physical iPhone capture; requires technical validation + matching manual privacy-review SHA-256 sidecar" }
  },
  "automatable_ready": $(json_bool $auto_ok),
  "human_gated_remaining": ["physical-device recording", "ASC Resolution Center reply+upload"],
  "verdict": "$( [ $auto_ok = 1 ] && [ $rec_ok = 1 ] && echo READY_TO_SEND || { [ $auto_ok = 1 ] && echo READY_EXCEPT_RECORDING || echo NOT_READY; } )"
}
JSON