#!/usr/bin/env bash set -uo pipefail # CASAN H6 cost-spike detector (WP-C). # Answers the H6 key question: "if a step suddenly costs 3x the tokens, does # anyone know?". Reads real per-step usage from provider-usage.jsonl, computes # the median total_tokens across steps, and flags any step exceeding # MULTIPLIER x median. Exits non-zero if a spike is found (so a pipeline/CI gate # goes red). # # Usage: cost-spike-detect.sh [provider-usage.jsonl] [multiplier] # Exit: 0 no spike, 2 spike detected, 64 usage, 3 not enough data. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" LOG="${1:-$PROJECT_ROOT/.specify/logs/level5/provider-usage.jsonl}" MULT="${2:-3.0}" [[ -f "$LOG" ]] || { echo "COST_SPIKE_NO_DATA file=$LOG" >&2; exit 3; } python3 - "$LOG" "$MULT" <<'PY' import json, sys, statistics path, mult = sys.argv[1], float(sys.argv[2]) rows = [] for line in open(path, encoding="utf-8"): line = line.strip() if not line: continue try: r = json.loads(line) except ValueError: continue if "total_tokens" in r: rows.append((r.get("step", "?"), int(r["total_tokens"]))) if len(rows) < 3: sys.stderr.write(f"COST_SPIKE_NO_DATA records={len(rows)} (need >=3)\n") raise SystemExit(3) tokens = [t for _, t in rows] median = statistics.median(tokens) threshold = median * mult spikes = [(s, t) for s, t in rows if t > threshold] print(f"records={len(rows)} median_tokens={median} threshold={threshold:.0f} (x{mult})") for s, t in spikes: print(f"SPIKE step={s} tokens={t} (> {threshold:.0f})") if spikes: sys.stderr.write(f"COST_SPIKE_DETECTED count={len(spikes)}\n") raise SystemExit(2) print("COST_SPIKE_NONE") PY