#!/usr/bin/env bash # Tier 1.5 local mid-smoke — RTX 3050 Ti, b=128, 2000 train + 500 eval steps. # # Closes the 700× dev-cycle gap between Tier 1 (6 sec local correctness) and # Tier 2 (70 min cluster eval). Gates 80%+ of bad hypotheses before they reach # cluster. Target wall-clock: ≤ 10 min on RTX 3050. # # Spec: docs/superpowers/specs/2026-06-02-fast-dev-cycle.md §3.2 # Verdict: python3 scripts/tier1_5_verdict.py # # Data: test_data/futures-baseline-mid/ES.FUT/ — symlinks to 2024-Q1 (train, # 4.8GB) + 2024-Q2 (eval, 14GB) MBP-10 files from the canonical PVC. # Walk-forward split: --n-folds 2 --fold-idx 0 → train=Q1, eval=Q2. # # Usage: # ./scripts/local-mid-smoke.sh # default seed=42 # ./scripts/local-mid-smoke.sh --seed 123 # override seed # ./scripts/local-mid-smoke.sh --out /tmp/foxhunt-alt # custom out dir # ./scripts/local-mid-smoke.sh --n-backtests 64 # smaller batch # # Per `feedback_local_smoke_before_cluster`: run this BEFORE every cluster # smoke when touching .cu / trait impls / buffers / N_ACTIONS / ISV slots. set -euo pipefail SEED=42 OUT_DIR="/tmp/foxhunt-mid-smoke" N_BACKTESTS=128 N_STEPS=2000 N_EVAL_STEPS=500 N_FOLDS=2 FOLD_IDX=0 usage() { cat <&2; usage >&2; exit 2 ;; esac done REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$REPO_ROOT" # --mbp10-data-dir points DIRECTLY at the instrument's .dbn.zst directory # (matches argo-rl template line: --mbp10-data-dir /data/futures-baseline-mbp10/ES.FUT). MBP10_DIR="$REPO_ROOT/test_data/futures-baseline-mid/ES.FUT" PREDECODED_DIR="$REPO_ROOT/test_data/futures-baseline-mid" # Sanity checks. if [[ ! -d "$MBP10_DIR" ]]; then echo "ERROR: $MBP10_DIR not found." >&2 echo "Run setup: see CLAUDE.md 'Tier 1.5 data path' or docs/superpowers/specs/2026-06-02-fast-dev-cycle.md §3.1" >&2 exit 3 fi n_mbp_files=$(find -L "$MBP10_DIR" -maxdepth 1 -name '*.dbn.zst' 2>/dev/null | wc -l) if [[ "$n_mbp_files" -lt 2 ]]; then echo "ERROR: $MBP10_DIR has $n_mbp_files MBP-10 files; need ≥ 2 for walk-forward split." >&2 exit 3 fi mkdir -p "$OUT_DIR" echo "=== Tier 1.5 mid-smoke ===" echo " Repo: $REPO_ROOT" echo " Seed: $SEED" echo " Batch: $N_BACKTESTS" echo " Steps: $N_STEPS train + $N_EVAL_STEPS eval" echo " Walk-forward: fold $FOLD_IDX of $N_FOLDS" echo " MBP-10 dir: $MBP10_DIR (${n_mbp_files} files)" echo " Out dir: $OUT_DIR" echo # Build (sccache + dev-release for fast iteration; --release matches cluster). echo "[build] cargo build --release --example alpha_rl_train -p ml-alpha" SQLX_OFFLINE=true cargo build --release --example alpha_rl_train -p ml-alpha BINARY="$REPO_ROOT/target/release/examples/alpha_rl_train" if [[ ! -x "$BINARY" ]]; then echo "ERROR: binary not found at $BINARY after build." >&2 exit 4 fi echo echo "[run] $BINARY ..." START_TS=$(date +%s) # Per `feedback_no_stubs`: the binary owns its full life cycle. We just # invoke it and capture wall time. Exit code 2 = G8 NaN abort (per binary # docstring); we propagate it so the caller knows the run died. "$BINARY" \ --mbp10-data-dir "$MBP10_DIR" \ --predecoded-dir "$PREDECODED_DIR" \ --out "$OUT_DIR" \ --diag-jsonl "$OUT_DIR/diag.jsonl" \ --eval-diag-jsonl "$OUT_DIR/eval_diag.jsonl" \ --n-steps "$N_STEPS" \ --n-eval-steps "$N_EVAL_STEPS" \ --n-backtests "$N_BACKTESTS" \ --n-folds "$N_FOLDS" \ --fold-idx "$FOLD_IDX" \ --seed "$SEED" \ --instrument-mode front-month \ --log-every 200 \ --gpu-idx 0 END_TS=$(date +%s) ELAPSED=$((END_TS - START_TS)) ELAPSED_MIN=$((ELAPSED / 60)) ELAPSED_SEC=$((ELAPSED % 60)) echo echo "=== Mid-smoke complete in ${ELAPSED_MIN}m ${ELAPSED_SEC}s ===" echo "Outputs:" ls -lh "$OUT_DIR" 2>/dev/null echo echo "Next:" echo " python3 $REPO_ROOT/scripts/tier1_5_verdict.py $OUT_DIR"