diff --git a/hive-ag3nt/src/stats.rs b/hive-ag3nt/src/stats.rs index 80298c04..cad8fce5 100644 --- a/hive-ag3nt/src/stats.rs +++ b/hive-ag3nt/src/stats.rs @@ -229,11 +229,15 @@ fn empty_snapshot(window: Window) -> Snapshot { } fn snapshot(path: &Path, window: Window) -> Result { - // Read-only open so an in-flight writer (the harness's own - // turn_stats sink) never blocks us and we can't corrupt the db - // via a query bug. + // Read-only open so we can't corrupt the db via a query bug. let conn = Connection::open_with_flags(path, OpenFlags::SQLITE_OPEN_READ_ONLY) .with_context(|| format!("open {} read-only", path.display()))?; + // turn_stats is rollback-journal (not WAL): a read landing while the + // harness's own sink is mid-INSERT gets SQLITE_BUSY, which propagates up + // and blanks the whole stats page. Wait out the brief write instead — + // matches hive-c0re's host-side reader (`hive_stats::read_agent`). + conn.busy_timeout(std::time::Duration::from_millis(500)) + .with_context(|| format!("set busy_timeout on {}", path.display()))?; let now = now_secs(); // Fixed windows look back a constant span; `all` starts at the earliest // recorded turn (`MIN(started_at)`, falling back to `now` on an empty