From a21ad23088abfa7c364f826ac2848f679b9763b1 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Aug 2026 03:26:54 +0000 Subject: [PATCH] fix(scripts): overnight.sh ran in the wrong directory and could snapshot a phantom database MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two production bugs from the first committed version, observed live: - cd "$(dirname $0)" landed in scripts/, not the repo root, so every relative path resolved under scripts/runs/. Fixed to dirname/.. (grind-news.sh already did this correctly). - sqlite3.connect on the resulting missing forward.sqlite silently CREATED an empty database, which was then snapshotted and seeded into work.sqlite — producing an all-zero cycle and a 'no such table: raw_responses' crash in normalize. The snapshot step now refuses loudly if forward.sqlite is absent or has no raw_responses table: an empty database must never masquerade as the collector's. Cleanup for anyone bitten: a phantom scripts/runs/ tree may exist and can be deleted; the real collector database was never touched. --- scripts/overnight.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/scripts/overnight.sh b/scripts/overnight.sh index 82c8d7e..d170528 100755 --- a/scripts/overnight.sh +++ b/scripts/overnight.sh @@ -5,19 +5,34 @@ # merges new raw responses into runs/nightly/work.sqlite, where all # normalization, LLM scoring, and analysis happen with no contention. set -u -cd "$(dirname "$0")" +cd "$(dirname "$0")/.." mkdir -p runs/nightly snapshot_and_merge() { python3 - <<'PY' import sqlite3 +import os, sys + def backup(src, dst): a = sqlite3.connect(src, timeout=60) b = sqlite3.connect(dst) a.backup(b) b.close(); a.close() +# GUARD: sqlite3.connect silently CREATES a missing file — an empty +# database must never masquerade as the collector's. Refuse loudly. +if not os.path.exists("runs/forward.sqlite"): + sys.exit("runs/forward.sqlite does not exist — is the collector " + "running, and is this script running from the repo root?") +probe = sqlite3.connect("runs/forward.sqlite", timeout=60) +tables = {r[0] for r in probe.execute( + "SELECT name FROM sqlite_master WHERE type='table'")} +probe.close() +if "raw_responses" not in tables: + sys.exit("runs/forward.sqlite has no raw_responses table — " + "refusing to snapshot an empty or foreign database") + backup("runs/forward.sqlite", "runs/nightly/snap.sqlite") import os if not os.path.exists("runs/nightly/work.sqlite"):