#!/usr/bin/env bash # Observer smoke — autonomous-iteration witness service end-to-end. # All assertions go through gateway :3110. # # Validates: # - POST /observer/event records an op (success path + scenario source) # - GET /observer/stats aggregates by source + counts successes/failures # - Stats.recent_scenario_ops surfaces scenario digests # - Validation: empty endpoint → 400 # - Persistence: kill+restart observerd preserves ops via JSONL replay set -euo pipefail cd "$(dirname "$0")/.." export PATH="$PATH:/usr/local/go/bin" echo "[observer-smoke] building observerd + gateway..." go build -o bin/ ./cmd/observerd ./cmd/gateway pkill -f "bin/(observerd|gateway)" 2>/dev/null || true sleep 0.3 PIDS=() TMP="$(mktemp -d)" PERSIST="$TMP/ops.jsonl" CFG="$TMP/observer.toml" cleanup() { echo "[observer-smoke] cleanup" for p in "${PIDS[@]}"; do [ -n "$p" ] && kill "$p" 2>/dev/null || true; done rm -rf "$TMP" } trap cleanup EXIT INT TERM cat > "$CFG" </dev/null 2>&1; then return 0; fi sleep 0.05 done return 1 } launch_observerd() { ./bin/observerd -config "$CFG" > /tmp/observerd.log 2>&1 & OBSERVERD_PID=$! PIDS+=($OBSERVERD_PID) poll_health 3219 || { echo "observerd failed"; tail /tmp/observerd.log; return 1; } } echo "[observer-smoke] launching observerd → gateway..." launch_observerd ./bin/gateway -config "$CFG" > /tmp/gateway.log 2>&1 & PIDS+=($!) poll_health 3110 || { echo "gateway failed"; tail /tmp/gateway.log; exit 1; } FAILED=0 # ── 1. Record 5 ops: 3 success + 2 fail across 2 sources ───────── echo "[observer-smoke] record 5 ops:" for i in 1 2 3; do curl -sS -o /dev/null -X POST http://127.0.0.1:3110/v1/observer/event \ -H 'Content-Type: application/json' \ -d "{\"endpoint\":\"/v1/test\",\"input_summary\":\"ok-$i\",\"success\":true,\"duration_ms\":10,\"output_summary\":\"ok\",\"source\":\"mcp\"}" done for i in 1 2; do curl -sS -o /dev/null -X POST http://127.0.0.1:3110/v1/observer/event \ -H 'Content-Type: application/json' \ -d "{\"endpoint\":\"/v1/test\",\"input_summary\":\"fail-$i\",\"success\":false,\"duration_ms\":10,\"output_summary\":\"err\",\"error\":\"boom\",\"source\":\"scenario\",\"staffer_id\":\"st-$i\",\"event_kind\":\"fill\",\"role\":\"Forklift\"}" done echo " ✓ 5 events posted" # ── 2. Stats aggregation ───────────────────────────────────────── echo "[observer-smoke] /observer/stats aggregates correctly:" STATS="$(curl -sS http://127.0.0.1:3110/v1/observer/stats)" TOT="$(echo "$STATS" | jq -r '.total')" OK="$(echo "$STATS" | jq -r '.successes')" ERR="$(echo "$STATS" | jq -r '.failures')" MCP="$(echo "$STATS" | jq -r '.by_source.mcp')" SCEN="$(echo "$STATS" | jq -r '.by_source.scenario')" RECENT_LEN="$(echo "$STATS" | jq -r '.recent_scenario_ops | length')" if [ "$TOT" = "5" ] && [ "$OK" = "3" ] && [ "$ERR" = "2" ] && [ "$MCP" = "3" ] && [ "$SCEN" = "2" ] && [ "$RECENT_LEN" = "2" ]; then echo " ✓ total=5 (3 ok + 2 fail) · by_source: mcp=3 scenario=2 · 2 scenario digests" else echo " ✗ total=$TOT ok=$OK err=$ERR mcp=$MCP scen=$SCEN recent=$RECENT_LEN" echo " full: $STATS" FAILED=1 fi # ── 3. Validation: empty endpoint → 400 ────────────────────────── echo "[observer-smoke] empty endpoint → 400:" HTTP="$(curl -sS -o /dev/null -w '%{http_code}' -X POST http://127.0.0.1:3110/v1/observer/event \ -H 'Content-Type: application/json' \ -d '{"endpoint":"","input_summary":"x","success":true,"duration_ms":1,"output_summary":"x"}')" if [ "$HTTP" = "400" ]; then echo " ✓ empty endpoint rejected" else echo " ✗ got $HTTP"; FAILED=1 fi # ── 4. Persistence: kill + restart preserves ops ───────────────── echo "[observer-smoke] kill + restart observerd → ops survive:" kill $OBSERVERD_PID 2>/dev/null || true wait $OBSERVERD_PID 2>/dev/null || true sleep 0.3 launch_observerd sleep 0.2 STATS2="$(curl -sS http://127.0.0.1:3110/v1/observer/stats)" TOT2="$(echo "$STATS2" | jq -r '.total')" OK2="$(echo "$STATS2" | jq -r '.successes')" ERR2="$(echo "$STATS2" | jq -r '.failures')" if [ "$TOT2" = "5" ] && [ "$OK2" = "3" ] && [ "$ERR2" = "2" ]; then echo " ✓ total=5 ok=3 err=2 preserved through restart" else echo " ✗ post-restart total=$TOT2 ok=$OK2 err=$ERR2"; FAILED=1 fi if [ "$FAILED" -eq 0 ]; then echo "[observer-smoke] Observer acceptance gate: PASSED" exit 0 else echo "[observer-smoke] Observer acceptance gate: FAILED" exit 1 fi