From 5729b0155ca818a146b226b4385db3083e6957ef Mon Sep 17 00:00:00 2001 From: nesquena-hermes Date: Tue, 22 Sep 2026 23:00:14 +0000 Subject: [PATCH] fix(state-db): fail loud when state.db has no agent table instead of skipping everything A missing *column* is an older agent schema (skip that index); a missing *table* means the path is not an agent state.db. Without this the new skip path reported every index 'skipped' with exit 0 on an unrelated DB. --- scripts/ensure_state_db_read_indexes.py | 4 ++++ tests/test_pr7445_readonly_review_followups.py | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/scripts/ensure_state_db_read_indexes.py b/scripts/ensure_state_db_read_indexes.py index 8d38b8a7..9d8fb197 100644 --- a/scripts/ensure_state_db_read_indexes.py +++ b/scripts/ensure_state_db_read_indexes.py @@ -97,6 +97,10 @@ def ensure_read_indexes(db_path, *, confirmed_drained=False, lock_file=None): # messages.timestamp). Skip that index instead of letting its # CREATE fail and roll back the ones this schema supports. present = {r[1] for r in db.execute(f"PRAGMA table_info({table})")} + if not present: + # No such table: this is not an agent state.db (or a + # mistyped path to another database). Fail loud. + raise RuntimeError(f"state.db has no {table!r} table; refusing to continue") if any(col not in present for col, _ in keys): statuses[name] = "skipped" continue diff --git a/tests/test_pr7445_readonly_review_followups.py b/tests/test_pr7445_readonly_review_followups.py index 665f0eae..45cdbbcc 100644 --- a/tests/test_pr7445_readonly_review_followups.py +++ b/tests/test_pr7445_readonly_review_followups.py @@ -272,6 +272,19 @@ def test_maintenance_skips_indexes_an_older_schema_cannot_hold(tmp_path, mainten assert "idx_sessions_webui_fingerprint" not in names +def test_maintenance_fails_loud_on_a_database_without_agent_tables(tmp_path, maintenance_without_fcntl): + """``skipped`` is for a missing column only. A database with no ``messages`` + table is not an agent state.db, so the tool must raise, not report success.""" + module = maintenance_without_fcntl + path = tmp_path / "state.db" + with closing(sqlite3.connect(str(path))) as conn: + conn.execute("CREATE TABLE unrelated(x)") + with pytest.raises(RuntimeError, match="no 'messages' table"): + module.ensure_read_indexes(path, confirmed_drained=True) + with closing(sqlite3.connect(str(path))) as conn: + assert conn.execute("SELECT count(*) FROM sqlite_master WHERE type='index'").fetchone()[0] == 0 + + @pytest.fixture def maintenance_without_fcntl(monkeypatch): """Import the maintenance module as a platform without ``fcntl`` sees it."""