fix: clear gate-derived rows on step rerun (idempotency)

This commit is contained in:
2026-07-17 00:57:53 -04:00
parent 9e8a254fbb
commit ea6bec5421
2 changed files with 123 additions and 9 deletions
+69
View File
@@ -0,0 +1,69 @@
"""step 重跑幂等:gate 派生行必须随 step 清理,否则崩溃重跑累积重复。"""
from __future__ import annotations
import sqlite3
from typing import TYPE_CHECKING
from app.harness.runner import _clear_step_rows
if TYPE_CHECKING:
from pathlib import Path
def _mk_db(tmp_path: Path) -> Path:
"""构造含 rollout 行、gate 派生行、他 step 行与前缀陷阱行的最小 harness.db。
参数:
tmp_path: pytest 临时目录。
返回:
harness.db 路径。
"""
db = tmp_path / "harness.db"
conn = sqlite3.connect(db)
conn.execute("CREATE TABLE predictions (run_id TEXT, question_id TEXT)")
conn.execute("CREATE TABLE traces (run_id TEXT, question_id TEXT)")
conn.execute("CREATE TABLE gate_evidence (run_id TEXT, epoch INTEGER, step INTEGER)")
conn.execute("CREATE TABLE quadrant_pair (run_id TEXT, epoch INTEGER, step INTEGER)")
rows = [
("infer_adhoc_e1_s0", "q1"), # rollout 行
("infer_adhoc_e1_s0_gate_action-reasoning_base", "q2"), # gate base 臂
("infer_adhoc_e1_s0_gate_action-reasoning_cand", "q3"), # gate cand 臂
("infer_adhoc_e1_s1", "q4"), # 其他 step,不许误删
("infer_adhoc_e1_s10_gate_x_base", "q5"), # s10 前缀陷阱,不许误删
]
conn.executemany("INSERT INTO predictions VALUES (?, ?)", rows)
conn.executemany("INSERT INTO traces VALUES (?, ?)", rows)
conn.execute("INSERT INTO gate_evidence VALUES ('infer_adhoc', 1, 0)")
conn.execute("INSERT INTO gate_evidence VALUES ('infer_adhoc', 1, 1)")
conn.execute("INSERT INTO quadrant_pair VALUES ('infer_adhoc', 1, 0)")
conn.commit()
conn.close()
return db
def test_clear_step_rows_removes_rollout_and_gate_rows(tmp_path) -> None:
"""rollout 行 + 本 step 全部 gate 派生行被清;他 step 与 s10 前缀陷阱不动。"""
db = _mk_db(tmp_path)
_clear_step_rows(str(db), baseline_run_id="infer_adhoc", epoch=1, step=0)
conn = sqlite3.connect(db)
left = {r[0] for r in conn.execute("SELECT run_id FROM predictions")}
assert left == {"infer_adhoc_e1_s1", "infer_adhoc_e1_s10_gate_x_base"}
left_t = {r[0] for r in conn.execute("SELECT run_id FROM traces")}
assert left_t == left
ge = list(conn.execute("SELECT step FROM gate_evidence"))
assert ge == [(1,)] # 只剩 step=1 的行
assert list(conn.execute("SELECT COUNT(*) FROM quadrant_pair"))[0][0] == 0
conn.close()
def test_clear_step_rows_missing_tables_is_noop(tmp_path) -> None:
"""gate_evidence/quadrant_pair 表尚未建(首个 step)时不报错。"""
db = tmp_path / "harness.db"
conn = sqlite3.connect(db)
conn.execute("CREATE TABLE predictions (run_id TEXT)")
conn.execute("CREATE TABLE traces (run_id TEXT)")
conn.commit()
conn.close()
_clear_step_rows(str(db), baseline_run_id="infer_adhoc", epoch=1, step=0)