fix(harness): change _runs INSERT OR IGNORE to ON CONFLICT DO UPDATE for incremental infer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-12 22:45:18 -04:00
parent 8b48005a17
commit 73ae1f7143
2 changed files with 41 additions and 7 deletions
+9 -4
View File
@@ -1,8 +1,9 @@
"""HarnessLogSQLite 薄包装 + RunLogImpl 只读查询端口。 """HarnessLogSQLite 薄包装 + RunLogImpl 只读查询端口。
HarnessLog 提供统一的结构化日志接口,从 TRM4 直搬,保留全部线程安全与幂等语义。 HarnessLog 提供统一的结构化日志接口,从 TRM4 直搬,保留全部线程安全与幂等语义。
同 run_id 重复创建时通过 ON CONFLICT DO UPDATE 更新 started_at/config/status。
RunLogImpl 实现 core/evolution/protocols.py::RunLog Protocol,用独立连接做只读 SELECT, RunLogImpl 实现 core/evolution/protocols.py::RunLog Protocol,用独立连接做只读 SELECT,
不经 HarnessLog 生命周期(不触发 _runs INSERT OR IGNORE),避免污染运行状态。 不经 HarnessLog 生命周期(不触发 _runs upsert),避免污染运行状态。
""" """
from __future__ import annotations from __future__ import annotations
@@ -41,7 +42,7 @@ class HarnessLog:
关键设计: 关键设计:
- WAL 模式 + threading.Lock 保证共享连接下并发安全。 - WAL 模式 + threading.Lock 保证共享连接下并发安全。
- INSERT OR IGNORE INTO _runs 保证幂等(同 run_id 多次创建不报错) - ON CONFLICT DO UPDATE 保证幂等(同 run_id 多次创建不报错)并更新 started_at/config/status
- query 也持锁:共享连接(check_same_thread=False)下并发 SELECT + INSERT - query 也持锁:共享连接(check_same_thread=False)下并发 SELECT + INSERT
在同一连接上 execute 会损坏游标状态,故读也须串行化。 在同一连接上 execute 会损坏游标状态,故读也须串行化。
- context manager 语义:正常退出 completed,异常退出 failed。 - context manager 语义:正常退出 completed,异常退出 failed。
@@ -70,9 +71,13 @@ class HarnessLog:
resolved_sha = git_sha or _get_git_sha() resolved_sha = git_sha or _get_git_sha()
config_json = json.dumps(config_snapshot, ensure_ascii=False) if config_snapshot else None config_json = json.dumps(config_snapshot, ensure_ascii=False) if config_snapshot else None
self._conn.execute( self._conn.execute(
"INSERT OR IGNORE INTO _runs" "INSERT INTO _runs"
" (run_id, git_sha, started_at, config, status)" " (run_id, git_sha, started_at, config, status)"
" VALUES (?, ?, ?, ?, ?)", " VALUES (?, ?, ?, ?, ?)"
" ON CONFLICT(run_id) DO UPDATE SET"
" started_at=excluded.started_at,"
" config=excluded.config,"
" status=excluded.status",
(run_id, resolved_sha, _now_iso(), config_json, "running"), (run_id, resolved_sha, _now_iso(), config_json, "running"),
) )
self._conn.commit() self._conn.commit()
+32 -3
View File
@@ -8,6 +8,7 @@ from __future__ import annotations
import sqlite3 import sqlite3
import threading import threading
import time
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import pytest import pytest
@@ -118,8 +119,8 @@ class TestHarnessLog:
assert row["status"] == "failed" assert row["status"] == "failed"
def test_insert_or_ignore_idempotent(self, db_path: str, run_id: str) -> None: def test_upsert_idempotent(self, db_path: str, run_id: str) -> None:
"""同一 run_id 多次创建 HarnessLog 不报错(INSERT OR IGNORE 幂等)。""" """同一 run_id 多次创建 HarnessLog 不报错(ON CONFLICT DO UPDATE 幂等)。"""
with HarnessLog(db_path, run_id): with HarnessLog(db_path, run_id):
pass pass
@@ -134,7 +135,7 @@ class TestHarnessLog:
).fetchone()[0] ).fetchone()[0]
conn.close() conn.close()
assert count == 1, "INSERT OR IGNORE 应保证 _runs 只有一行" assert count == 1, "ON CONFLICT DO UPDATE 应保证 _runs 只有一行"
def test_wal_mode(self, db_path: str, run_id: str) -> None: def test_wal_mode(self, db_path: str, run_id: str) -> None:
"""连接初始化后 journal_mode 应为 WAL。""" """连接初始化后 journal_mode 应为 WAL。"""
@@ -195,6 +196,34 @@ class TestHarnessLog:
assert rows[0]["val"] == "2" assert rows[0]["val"] == "2"
# ===========================================================================
# HarnessLog upsert 行为测试
# ===========================================================================
class TestHarnessLogUpsert:
"""_runs 表 upsert 行为。"""
def test_same_run_id_updates_started_at(self, tmp_path: Path) -> None:
"""同 run_id 第二次创建 HarnessLog 应更新 started_at。"""
db = str(tmp_path / "test.db")
with HarnessLog(db, "run_1", git_sha="abc") as log1:
rows = log1.query("SELECT started_at FROM _runs WHERE run_id='run_1'")
first_time = rows[0]["started_at"]
time.sleep(0.05)
with HarnessLog(db, "run_1", git_sha="abc") as log2:
rows = log2.query("SELECT started_at FROM _runs WHERE run_id='run_1'")
second_time = rows[0]["started_at"]
assert second_time > first_time
with HarnessLog(db, "run_1") as log3:
rows = log3.query("SELECT COUNT(*) as cnt FROM _runs WHERE run_id='run_1'")
assert rows[0]["cnt"] == 1
# =========================================================================== # ===========================================================================
# RunLogImpl 测试 # RunLogImpl 测试
# =========================================================================== # ===========================================================================