#!/bin/sh
# Manifest cutover regression guard for omp-spt.
# Run: sh tests/manifest-shortcut.sh (exit 0 = pass).
ROOT=$(CDPATH= cd "$(dirname "$0")/.." && pwd)
MANIFEST="$ROOT/adapter/omp-spt.toml"
EXTENSION="$ROOT/adapter/strings/omp-spt.mjs"
fail=0

# ── shortcut brand: the generated endpoint launcher shortcut is omp-<id> ─────────────────────────
line=$(grep -E '^[[:space:]]*shortcut_basename[[:space:]]*=' "$MANIFEST")
if [ -z "$line" ]; then echo "FAIL no shortcut_basename assignment in manifest"; exit 1; fi
case "$line" in
  *'"omp"'*) echo "ok   shortcut_basename = \"omp\" (omp-<id> brand intact)" ;;
  *) echo "FAIL shortcut_basename is not \"omp\": $line"; fail=1 ;;
esac
n=$(grep -Ec '^[[:space:]]*shortcut_basename[[:space:]]*=' "$MANIFEST")
if [ "$n" -eq 1 ]; then echo "ok   single shortcut_basename assignment"; else echo "FAIL $n shortcut_basename assignments (want 1)"; fail=1; fi

# ── adapter identity ──────────────────────────────────────────────────────────────────────────────
grep -Eq '^[[:space:]]*name[[:space:]]*=[[:space:]]*"omp-spt"' "$MANIFEST" \
  && echo 'ok   [adapter].name = "omp-spt"' || { echo "FAIL [adapter].name != omp-spt"; fail=1; }
grep -Eq '^[[:space:]]*host_binaries[[:space:]]*=.*"omp"' "$MANIFEST" \
  && echo 'ok   host_binaries includes "omp"' || { echo "FAIL host_binaries misses omp"; fail=1; }

field_of() { awk -v h="[$1]" -v f="$2" '$0 == h {s=1;next} /^\[/{s=0} s && $0 ~ f' "$MANIFEST"; }
hosts=$(field_of adapter '^[[:space:]]*hostable_types[[:space:]]*=')
case "$hosts" in
  'hostable_types = ["LiveAgent", "ReadyAgent"]') echo "ok   hostable_types exposes ReadyAgent + LiveAgent only" ;;
  *) echo "FAIL hostable_types must be exactly LiveAgent + ReadyAgent: $hosts"; fail=1 ;;
esac

# ── bringup: launch shim resolves OMP, then native OMP owns the broker PTY ────────────────────────
# [unit->REQ-OMP-NATIVE-TUI] [unit->REQ-OMP-SESSION-TITLES]
self_spawn=$(field_of session.self '^[[:space:]]*command[[:space:]]*=')
resume_spawn=$(field_of session.resume '^[[:space:]]*command[[:space:]]*=')
case "$self_spawn" in
  'command = "{adapter_dir}/omp-spt launch-omp --id {id} --node {node} --extension {adapter_dir}/strings/omp-spt.mjs"')
    echo "ok   [session.self] snapshots endpoint env and forwards naming inputs before native OMP launch" ;;
  *) echo "FAIL [session.self] does not use the endpoint-aware native OMP launch shim: $self_spawn"; fail=1 ;;
esac
case "$resume_spawn" in
  'command = "{adapter_dir}/omp-spt launch-omp --id {id} --node {node} --resume {session_id} --extension {adapter_dir}/strings/omp-spt.mjs"')
    echo "ok   [session.resume] refreshes endpoint snapshot and naming inputs before native resume" ;;
  *) echo "FAIL [session.resume] does not use endpoint-aware native resume: $resume_spawn"; fail=1 ;;
esac
spawn="$self_spawn
$resume_spawn"
if [ "$(printf '%s\n' "$spawn" | grep -c -- '--mode rpc')" -eq 0 ]; then echo "ok   hosted sessions never use headless RPC mode"; else echo "FAIL a hosted session still uses --mode rpc: $spawn"; fail=1; fi
if [ "$(grep -Ec '^[[:space:]]*command[[:space:]]*=[[:space:]]*"\{adapter_dir\}/omp-spt launch-omp ' "$MANIFEST")" -eq 2 ]; then echo "ok   exactly 2 native launch-shim commands"; else echo "FAIL expected exactly 2 native launch-shim commands"; fail=1; fi

# ── continuity file-drops belong to SPT, not a harness configuration directory ───────────────────
commune_dir=$(field_of session '^[[:space:]]*commune_dir[[:space:]]*=')
signoff_dir=$(field_of session '^[[:space:]]*signoff_dir[[:space:]]*=')
case "$commune_dir" in 'commune_dir = ".spt"') echo "ok   commune_dir = .spt" ;; *) echo "FAIL commune_dir must be .spt: $commune_dir"; fail=1 ;; esac
case "$signoff_dir" in 'signoff_dir = ".spt"') echo "ok   signoff_dir = .spt" ;; *) echo "FAIL signoff_dir must be .spt: $signoff_dir"; fail=1 ;; esac
if [ -f "$EXTENSION" ]; then echo "ok   packaged omp-spt extension exists"; else echo "FAIL packaged omp-spt extension missing"; fail=1; fi
if command -v node >/dev/null 2>&1; then NODE=node
elif command -v node.exe >/dev/null 2>&1; then NODE=node.exe
else echo "FAIL node is required for the OMP extension unit test"; fail=1; NODE=:
fi
NODE_TEST="$ROOT/tests/omp-extension.mjs"
case "$NODE" in *.exe) NODE_TEST=$(wslpath -w "$NODE_TEST") ;; esac
"$NODE" "$NODE_TEST" || fail=1

# ── daemon seams use the project-local snapshot, never rejected read-env placeholders ─────────────
digest_cmd=$(field_of digest '^[[:space:]]*extractor[[:space:]]*=')
history_cmd=$(field_of history '^[[:space:]]*fetcher[[:space:]]*=')
echo_cmd=$(field_of session.echo_commune '^[[:space:]]*command[[:space:]]*=')
case "$digest_cmd" in
  'extractor = "omp-spt digest-omp --session {session_id} --project-dir \"{cwd}\""') echo "ok   [digest].extractor scans project snapshots by session" ;;
  *) echo "FAIL [digest].extractor is not project-snapshot-aware: $digest_cmd"; fail=1 ;;
esac
case "$history_cmd" in
  'fetcher = "omp-spt history-omp --session {session_id} --project-dir \"{cwd}\""') echo "ok   [history].fetcher scans project snapshots by session" ;;
  *) echo "FAIL [history].fetcher is not project-snapshot-aware: $history_cmd"; fail=1 ;;
esac
case "$echo_cmd" in
  'command = "omp-spt echo-commune-omp --id {id} --session-id {session_id}"') echo "ok   [session.echo_commune] recovers the endpoint snapshot by id" ;;
  *) echo "FAIL echo_commune command is not endpoint-snapshot-aware: $echo_cmd"; fail=1 ;;
esac
if grep -q -- '--captured-env' "$MANIFEST"; then
  echo "FAIL manifest still passes retired --captured-env argv"
  fail=1
else
  echo "ok   no retired --captured-env argv remains"
fi
for var in OMP_PROFILE PI_PROFILE PI_CODING_AGENT_DIR PI_CONFIG_DIR XDG_DATA_HOME HOME USERPROFILE OMP_SPT_OMP_BIN; do
  if grep -Eq "\{$var\}|^\[env\.$var\]" "$MANIFEST"; then
    echo "FAIL manifest still references registration-rejected read-env selector $var"
    fail=1
  fi
done
if [ "$fail" -eq 0 ]; then echo "ok   rejected read-env declarations/placeholders are absent"; fi

# Current spt-core only fills the published Psyche custody keys for Psyche roles. Profile/model/auth
# state comes from the endpoint snapshot, not from extra manifest substitutions.
npsy=$(grep -cE '^[[:space:]]*command[[:space:]]*=[[:space:]]*"omp-spt psyche-omp --id \{id\} --session-id \{session_id\} --psyche-context-file \{psyche_context_file\}"' "$MANIFEST")
if [ "$npsy" -eq 2 ]; then echo "ok   both psyche roles use the public Psyche key catalog"; else echo "FAIL expected 2 valid psyche-omp role commands, found $npsy"; fail=1; fi
for role in session.psyche_init session.psyche_resume; do
  role_keys=$(field_of "$role" '^[[:space:]]*keys[[:space:]]*=')
  role_cmd=$(field_of "$role" '^[[:space:]]*command[[:space:]]*=')
  case "$role_keys:$role_cmd" in
    *OMP_PROFILE*|*PI_PROFILE*|*PI_CODING_AGENT_DIR*|*PI_CONFIG_DIR*|*XDG_DATA_HOME*|*HOME*|*USERPROFILE*|*OMP_SPT_OMP_BIN*)
      echo "FAIL [$role] references an unsupported read-env substitution"; fail=1 ;;
    *) echo "ok   [$role] avoids unsupported read-env substitutions" ;;
  esac
done
# The retired resident key must stay GONE from both psyche roles.
if grep -q 'psyche_prompt' "$MANIFEST"; then echo "FAIL a psyche role references the retired {psyche_prompt}"; fail=1; else echo "ok   no {psyche_prompt} anywhere (event rides stdin)"; fi

# [unit->REQ-PSYCHE-EPHEMERAL-SHIM] — identity-env scrub on both Psyche roles.
for role in session.psyche_init session.psyche_resume; do
  scrub=$(field_of "$role" '^[[:space:]]*env_remove[[:space:]]*=')
  if [ -z "$scrub" ]; then echo "FAIL [$role] has no env_remove (identity-env scrub missing)"; fail=1; else
    case "$scrub" in
      *'"OWL_SESSION_ID"'*'"SPT_AGENT_ID"'*|*'"SPT_AGENT_ID"'*'"OWL_SESSION_ID"'*)
        echo "ok   [$role] env_remove scrubs OWL_SESSION_ID + SPT_AGENT_ID" ;;
      *) echo "FAIL $role env_remove misses an identity var: $scrub"; fail=1 ;;
    esac
  fi
done
rz_detach=$(field_of session.psyche_resume '^[[:space:]]*detach[[:space:]]*=')
case "$rz_detach" in *false*) echo "ok   psyche_resume is captured (detach=false)" ;; *) echo "FAIL psyche_resume must be detach=false, got: [$rz_detach]"; fail=1 ;; esac
rz_keys=$(field_of session.psyche_resume '^[[:space:]]*keys[[:space:]]*=')
case "$rz_keys" in *'"psyche_context_file"'*) echo "ok   psyche_resume keys include psyche_context_file" ;; *) echo "FAIL psyche_resume keys missing psyche_context_file: [$rz_keys]"; fail=1 ;; esac

# ── [update] — the gh_release self-update seam points at the fork ─────────────────────────────────
if grep -Eq '^[[:space:]]*repo[[:space:]]*=[[:space:]]*"BigscreenVR/omp-spt"' "$MANIFEST"; then echo 'ok   [update].repo = "BigscreenVR/omp-spt"'; else echo "FAIL [update].repo is not BigscreenVR/omp-spt"; fail=1; fi
if grep -Eq '^[[:space:]]*repo[[:space:]]*=[[:space:]]*"SaberMage/' "$MANIFEST"; then echo "FAIL an active repo assignment still points at SaberMage/*"; fail=1; else echo "ok   no active SaberMage repo assignment"; fi
if grep -Eq '^[[:space:]]*transport[[:space:]]*=[[:space:]]*"gh"' "$MANIFEST"; then echo 'ok   [update].transport = "gh"'; else echo "FAIL [update] transport must use gh for auth-capable release fetch"; fail=1; fi
if grep -Eq '^[[:space:]]*message[[:space:]]*=' "$MANIFEST"; then echo "ok   [update].message present"; else echo "FAIL [update] has no message field"; fail=1; fi
if grep -Eq 'endpoint run' "$MANIFEST"; then echo "FAIL manifest still names the retired spt endpoint run (ENDPOINT_RUN_RETIRED since spt-core 0.67.0)"; fail=1; else echo "ok   manifest names only the live lifecycle verbs (create/start/resume/go)"; fi
if grep -Eq 'spt endpoint create <id> --adapter omp-spt' "$MANIFEST"; then echo "ok   fresh-endpoint update notice uses spt endpoint create"; else echo "FAIL fresh-endpoint update notice does not name spt endpoint create"; fail=1; fi

# [unit->REQ-OMP-CORE-DELIVERY]
inject_activity=$(field_of inject '^[[:space:]]*activity[[:space:]]*=')
case "$inject_activity" in
  'activity = ["hook"]') echo "ok   [inject] routes idle and active custody through OMP hooks" ;;
  *) echo "FAIL [inject].activity must be exactly [\"hook\"]: [$inject_activity]"; fail=1 ;;
esac

# ── retired foreign-harness seams stay absent ────────────────────────────────────────────────────
# [unit->REQ-OMP-NATIVE-TUI]
for stale in \
  '^\[update\.post\]' \
  '^\[hooks\.' \
  '^\[message-idle-translation-binary\]' \
  '^\[env\.SPT_INJECT_VERIFY_ECHO\]' \
  '^\[env\.CLAUDE_CONFIG_DIR\]' \
  '^[[:space:]]*hook_cmd[[:space:]]*=' \
  '^[[:space:]]*command[[:space:]]*=.* translate'; do
  if grep -Eq "$stale" "$MANIFEST"; then
    echo "FAIL retired manifest surface remains: $stale"
    fail=1
  fi
done
if [ "$fail" -eq 0 ]; then echo "ok   retired update/hook/translation/env surfaces absent"; fi

# OMP model routing is native; the adapter ships no foreign profile overlay.
if grep -Eq '^\[profiles\.' "$MANIFEST"; then echo "FAIL a shipped [profiles.*] table lingers"; fail=1; else echo "ok   no shipped profile overlays"; fi


# [int->REQ-DIST-MANIFEST-SCHEMA] — real binary validation catches role-key rules the JSON schema
# cannot. Local developer machines may skip when spt is absent; a release gate must set
# OMP_SPT_RELEASE_MODE=1, which makes absence a hard failure instead of a false green.
if command -v spt >/dev/null 2>&1; then
  REG_TMP="${TMPDIR:-/tmp}/omp-spt-manifest-registration-$$"
  rm -rf "$REG_TMP"
  mkdir -p "$REG_TMP/localappdata" "$REG_TMP/canonical/strings"
  REG_LOCAL="$REG_TMP/localappdata"
  REG_MANIFEST="$MANIFEST"
  REG_CANONICAL="$REG_TMP/canonical/manifest.toml"
  case "$(uname -s 2>/dev/null)" in
    MINGW*|MSYS*|CYGWIN*)
      REG_LOCAL=$(cygpath -w "$REG_LOCAL")
      REG_MANIFEST=$(cygpath -w "$REG_MANIFEST")
      REG_CANONICAL=$(cygpath -w "$REG_CANONICAL")
      ;;
    *)
      case "$(command -v spt)" in
        *.exe)
          if command -v wslpath >/dev/null 2>&1; then
            REG_LOCAL=$(wslpath -w "$REG_LOCAL")
            REG_MANIFEST=$(wslpath -w "$REG_MANIFEST")
            REG_CANONICAL=$(wslpath -w "$REG_CANONICAL")
          fi
          ;;
      esac
      ;;
  esac
  if register_output=$(LOCALAPPDATA="$REG_LOCAL" spt adapter add "$REG_MANIFEST" 2>&1); then
    echo "ok   real isolated spt adapter add accepts adapter/omp-spt.toml"
  else
    echo "FAIL real isolated spt adapter add rejected manifest: $register_output"
    fail=1
  fi
  cp "$MANIFEST" "$REG_TMP/canonical/manifest.toml"
  cp "$EXTENSION" "$REG_TMP/canonical/strings/omp-spt.mjs"
  expected_version=$(field_of adapter '^[[:space:]]*version[[:space:]]*=' | cut -d'"' -f2)
  if canonical_output=$(LOCALAPPDATA="$REG_LOCAL" spt adapter add "$REG_CANONICAL" 2>&1) \
     && registered_version=$(LOCALAPPDATA="$REG_LOCAL" spt adapter version omp-spt 2>&1); then
    registered_version=$(printf '%s' "$registered_version" | tr -d '\r\n')
    if [ "$registered_version" = "$expected_version" ]; then
      echo "ok   real isolated spt reports omp-spt $expected_version"
    else
      echo "FAIL real isolated spt reports '$registered_version' (want $expected_version)"
      fail=1
    fi
  else
    echo "FAIL real isolated spt version check failed: $canonical_output ${registered_version:-}"
    fail=1
  fi
  rm -rf "$REG_TMP"
else
  case "${OMP_SPT_RELEASE_MODE:-0}:${GITHUB_REF_TYPE:-}" in
    1:*|*:tag)
      echo "FAIL spt is required for clean registration in release mode"
      fail=1
      ;;
    *) echo "SKIP real spt clean-registration check (spt not on PATH)" ;;
  esac
fi
[ "$fail" -eq 0 ] && { echo "MANIFEST-SHORTCUT OK"; exit 0; } || { echo "MANIFEST-SHORTCUT FAIL"; exit 1; }
