Confirmatory run

June 16, 2026 · View on GitHub

Keep the Mac plugged in with the lid open. Run each block in the surface-bench directory. Run the five models one at a time: wait for wrote results/run-<model>/raw.jsonl before starting the next. Each model writes its own dir, so if one fails you only re-run that model.

0. Pre-flight: confirm the pre-registration is frozen (DO THIS BEFORE ANY MODEL RUN)

The pre-registration has already been frozen and tagged as prereg-v2-multi (surf 0.6.2), and pushed. Just confirm the tag is present before running:

git tag --list prereg-v2-multi      # must print: prereg-v2-multi

Do not start a model run unless that tag exists — the freeze must predate all confirmatory data.

1. Load API keys

set -a; source ~/.surface-bench.env; set +a

2. Run each model (one at a time)

The scenario set is the cascade family; idempotency-window-qa auto-excludes in multi mode (650 cells/model). Run one block, watch it finish, then run the next.

haiku

nohup caffeinate -i -s uv run python -m surface_bench.run --models haiku --mode multi --max-turns 8 --trials 10 --scenarios $(ls -d scenarios/cascade-* | xargs -n1 basename) --out results/run-haiku > run-haiku.log 2>&1 &

sonnet

nohup caffeinate -i -s uv run python -m surface_bench.run --models sonnet --mode multi --max-turns 8 --trials 10 --scenarios $(ls -d scenarios/cascade-* | xargs -n1 basename) --out results/run-sonnet > run-sonnet.log 2>&1 &

opus

nohup caffeinate -i -s uv run python -m surface_bench.run --models opus --mode multi --max-turns 8 --trials 10 --scenarios $(ls -d scenarios/cascade-* | xargs -n1 basename) --out results/run-opus > run-opus.log 2>&1 &

gpt (OpenAI — watch credit; ≈ $9)

nohup caffeinate -i -s uv run python -m surface_bench.run --models gpt --mode multi --max-turns 8 --trials 10 --scenarios $(ls -d scenarios/cascade-* | xargs -n1 basename) --out results/run-gpt > run-gpt.log 2>&1 &

gemini (Google — watch credit; ≈ $13, slowest/most rate-limited)

nohup caffeinate -i -s uv run python -m surface_bench.run --models gemini --mode multi --max-turns 8 --trials 10 --scenarios $(ls -d scenarios/cascade-* | xargs -n1 basename) --out results/run-gemini > run-gemini.log 2>&1 &

3. Confirm it's running / watch

jobs                      # should show the job running (not "done")
tail -f run-<model>.log   # Ctrl+C stops the tail only; the run keeps going

The first log line should say it is excluding cascade-idempotency-window-qa. The run is done when the log ends with wrote results/run-<model>/raw.jsonl.

4. Sanity-check each model before moving on

wc -l < results/run-<model>/raw.jsonl              # expect 650
grep -c '"error"' results/run-<model>/raw.jsonl    # expect 0

If a model died partway, just re-run its block (it overwrites only its own dir).

5. After all five finish: merge + report + oracle

TS=$(date -u +%Y%m%dT%H%M%SZ); D=results/confirmatory-$TS; mkdir -p "$D"
cat results/run-*/raw.jsonl > "$D/raw.jsonl"
uv run python - "$D" <<'PY'
import json, glob, sys
dirs = sorted(glob.glob("results/run-*/run.json"))
base = json.load(open(dirs[0])); base["models"] = {}
for f in dirs:
    base["models"].update(json.load(open(f))["models"])
json.dump(base, open(sys.argv[1] + "/run.json", "w"), indent=2)
print("merged", len(base["models"]), "models into", sys.argv[1])
PY
uv run python -m surface_bench.report "$D"
uv run python -m surface_bench.oracle "$D"
echo "merged matrix in $D"

Expect 3250 rows total (5 × 650). The oracle must exit clean on the real models.

Stop a run (if needed)

pkill -f surface_bench.run