#!/usr/bin/env bash
# sdk/testing/generic-cli-stub — a headless agent CLI that knows NOTHING about
# Claude Code's flag surface (STORY-117 T-ENG-117b). Zero network, zero model.
#
# WHY IT IS HOSTILE
# -----------------
# `adapter: generic` promises the engine will invoke an unknown CLI *bare*: no
# flags, prompt on stdin, judged by exit code (ADR-026). A stub that merely
# ignored unexpected flags could not tell you whether the engine kept that
# promise — it would pass just as happily if core leaked `--permission-mode`
# into every dispatch.
#
# So this stub REFUSES. Any flag at all → exit 64 (EX_USAGE) with the offending
# argv on stderr, which fails the gate that dispatched it and fails the
# scenario. That makes "core sends no client flags to a generic runner" a
# property the CI proves rather than a claim the ADR makes.
#
# If this stub ever exits 64 in CI, do NOT teach it the flag: core has leaked a
# provider's vocabulary through the adapter boundary, which is a contract defect
# (ADR-026 "when to revisit").
#
# WHAT IT DOES
#   prompt   read from STDIN, always (the contract's only delivery path)
#   role     detected from the prompt's engine-owned markers — the verdict
#            grammar is the ENGINE's, not a vendor's, which is exactly why a
#            foreign CLI can satisfy it
#   output   plain text on stdout. No stream format: `generic` declares no
#            stream_decode, so the engine reads this verbatim.
#
# Env seams:
#   GENERIC_STUB_ARGV_LOG   append every invocation's argv (an `argv:` line,
#                           empty when invoked correctly) — the positive
#                           evidence to sit beside the exit-64 tripwire.
#   GENERIC_STUB_EXIT       force this exit code after printing (default 0).
set -uo pipefail

if [[ -n "${GENERIC_STUB_ARGV_LOG:-}" ]]; then
  printf 'argv: %s\n' "$*" >> "$GENERIC_STUB_ARGV_LOG" 2>/dev/null || true
fi

# The tripwire. Note it rejects EVERY argument, not a denylist of known claude
# flags: a denylist would silently accept the next provider's vocabulary.
if [[ $# -gt 0 ]]; then
  echo "generic-cli-stub: invoked with arguments, but a generic runner takes none." >&2
  echo "generic-cli-stub: argv was: $*" >&2
  echo "generic-cli-stub: core leaked client flags through the adapter boundary (ADR-026)." >&2
  exit 64
fi

prompt="$(cat)"

if [[ -n "${GENERIC_STUB_TRANSCRIPT:-}" ]]; then
  { printf '===== generic-cli-stub invocation =====\n%s\n' "$prompt"; } \
    >> "$GENERIC_STUB_TRANSCRIPT" 2>/dev/null || true
fi

echo "generic-cli-stub: a CLI with no idea who Claude is."

# print_acs_map <role> — the role's `acs:` map, every numbered AC of the TASK
# SPEC mapped `pass` with a citation: the engine decides AC coverage from it
# (lib/evidence.sh evidence_ac_coverage, T-PB-345c), whatever the runner.
print_acs_map() {
  echo "acs:"
  awk -v role="$1" '
    /^--- TASK SPEC/ { in_spec = 1; next }
    /^--- END TASK SPEC/ { in_spec = 0 }
    !in_spec { next }
    /^#+[ \t]/ { in_ac = (tolower($0) ~ /acceptance criteria/); next }
    in_ac && match($0, /^ ? ? ?[0-9]+[.)][ \t]/) { sub(/^ */, ""); sub(/[.)].*/, ""); print "  " $0 ": pass test:generic-cli-stub/" role "/ac-" $0 }
  ' <<<"$prompt"
}

if grep -q -- "/qa-verify CONTRACT" <<<"$prompt"; then
  echo "generic-cli-stub: qa role — verified to the engine's contract."
  print_acs_map qa
  echo "QA-VERDICT: PASS"
  exit "${GENERIC_STUB_EXIT:-0}"
fi

if grep -q "REVIEW-VERDICT:" <<<"$prompt"; then
  echo "## Findings"
  echo "### Blocking (must fix before merge)"
  echo "(none)"
  print_acs_map reviewer
  echo "REVIEW-VERDICT: CLEAN"
  exit "${GENERIC_STUB_EXIT:-0}"
fi

echo "generic-cli-stub: no recognised role marker — nothing to do."
exit "${GENERIC_STUB_EXIT:-0}"
