Files
winning-wallet-finder_github/research/nightly.sh
T
2026-07-27 15:33:04 -04:00

93 lines
4.1 KiB
Bash
Executable File

#!/bin/bash
# research nightly — scores the frozen studies on fresh tape and versions
# the forward ledger. SILO: touches only research/ (+ the append-only
# resolutions cache via payouts.py). Fired at 09:15 local by
# com.jaxperro.research-nightly, but the clock time is advisory: the Mac
# sleeps and the 08:00 daily pipeline's tape ingest lands whenever it lands
# (2026-07-21: daily started 09:31 on wake, ingest hours later, and the
# 09:15 firing both CRASHED on launchd's bare `python3` — no duckdb — and
# would have scored a stale tape). So: absolute framework python, and WAIT
# for the tape to be fresh (max ts within FRESH_S of now) before scoring,
# up to DEADLINE_S; then run anyway and log the staleness.
# Safe to run by hand any time: bash research/nightly.sh
set -e
cd "$(dirname "$0")"
PY=/Library/Frameworks/Python.framework/Versions/3.11/bin/python3
FRESH_S=$((6 * 3600))
DEADLINE_S=$((8 * 3600))
POLL_S=900
# ABSOLUTE lock path: the script cd's to the repo root before the git
# steps, so a relative trap rmdir missed the dir entirely (2026-07-21 first
# run: exit 1 + a stale lock that would have skipped every future night).
LOCK="$(pwd)/.nightly.lock.d"
if ! mkdir "$LOCK" 2>/dev/null; then
# STALE-LOCK GUARD (2026-07-27): a killed run (pause, crash, reboot) can
# leave the dir behind — the EXIT trap never fires on SIGKILL — and every
# later night then skips SILENTLY. Trust the recorded PID: if it is gone,
# the lock is debris, so take it over.
OWNER=$(cat "$LOCK/pid" 2>/dev/null)
if [ -n "$OWNER" ]; then
if kill -0 "$OWNER" 2>/dev/null; then
echo "$(date -u +%FT%TZ) already running (pid $OWNER) — skip" >> forward.log
exit 0
fi
echo "$(date -u +%FT%TZ) STALE lock (pid $OWNER gone) — taking over" >> forward.log
else
# No pid file = a lock from before this guard existed (or a crash between
# mkdir and the write). Do NOT assume stale — that ran two nightlies at
# once on 2026-07-27. Age it out instead: 6h is longer than any real run.
AGE=$(( $(date +%s) - $(stat -f %m "$LOCK" 2>/dev/null || echo 0) ))
if [ "$AGE" -lt 21600 ]; then
echo "$(date -u +%FT%TZ) lock held (no pid, age ${AGE}s < 6h) — skip" >> forward.log
exit 0
fi
echo "$(date -u +%FT%TZ) STALE lock (no pid, age ${AGE}s) — taking over" >> forward.log
fi
fi
echo $$ > "$LOCK/pid"
trap 'rmdir "$LOCK"' EXIT
tape_age() {
"$PY" - <<'EOF'
import duckdb, time
db = duckdb.connect("../live/rtds.duckdb", read_only=True)
mx, = db.execute("select max(ts) from trades").fetchone()
print(int(time.time() - (mx or 0)))
EOF
}
start=$(date +%s)
while true; do
age=$(tape_age) || age=999999
if [ "$age" -le "$FRESH_S" ]; then
echo "== $(date -u +%FT%TZ) nightly (tape age ${age}s) ==" >> forward.log
break
fi
if [ $(( $(date +%s) - start )) -ge "$DEADLINE_S" ]; then
echo "== $(date -u +%FT%TZ) nightly DEADLINE — tape still ${age}s stale, scoring anyway ==" >> forward.log
break
fi
sleep "$POLL_S"
done
"$PY" forward.py >> forward.log 2>&1
"$PY" informed_set.py >> forward.log 2>&1 # surge harness reads this daily
"$PY" maker_set.py >> forward.log 2>&1 || true # leanbot input (#26)
"$PY" grade_surge.py >> forward.log 2>&1 || true # A2 measurement -> chain truth
"$PY" surge_book_replay.py >> forward.log 2>&1 || true # virtual $100/5% book
"$PY" grade_oracle.py >> forward.log 2>&1 || true # oracle paper -> chain truth
"$PY" grade_lag.py >> forward.log 2>&1 || true # lead-lag paper -> chain truth
"$PY" grade_lean.py >> forward.log 2>&1 || true # maker-lean paper -> chain truth
"$PY" meta_snap.py >> forward.log 2>&1 || true # market metadata (local gz)
cd ..
git add research/forward_ledger.jsonl research/params/informed_set.json \
research/lean_paper_ledger.jsonl research/params/maker_set.json \
research/surge_paper_ledger.jsonl research/oracle_paper_ledger.jsonl research/lag_paper_ledger.jsonl \
research/surge_meas_ledger.jsonl research/surge_book.json 2>/dev/null
if ! git diff --cached --quiet; then
git commit -q -m "research: forward ledger $(date -u +%F) [skip ci]"
git pull --rebase --autostash -q && git push -q
fi