From 8dbf07e950d0c404052456fde2758ef2fe157fb6 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Mon, 31 Aug 2026 13:44:56 -0700 Subject: [PATCH] fix: satisfy the no-locked-pure-readers gate and close the DB before rmtree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _record_db_file_identity's PRAGMA fallback is a pure read — route it through _read_ctx() instead of the writer lock (Pattern C gate). test_codex_turn_persists_each_message_exactly_once leaked a live SessionDB into shutil.rmtree, racing the WAL sidecars ('Directory not empty' on CI); close the handle first and rmtree with ignore_errors. --- hermes_state.py | 4 ++-- tests/agent/test_codex_app_server_persist.py | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hermes_state.py b/hermes_state.py index 87651435b3..831fcbc78d 100644 --- a/hermes_state.py +++ b/hermes_state.py @@ -5978,8 +5978,8 @@ class SessionDB(SessionSearchMixin, SessionSchemaMixin, SessionPortabilityMixin) self._db_file_application_id = disk_id elif self._conn is not None and not self._db_file_application_id: try: - with self._lock: - pragma_row = self._conn.execute("PRAGMA application_id").fetchone() + with self._read_ctx() as conn: + pragma_row = conn.execute("PRAGMA application_id").fetchone() if pragma_row and pragma_row[0]: self._db_file_application_id = int(pragma_row[0]) except sqlite3.Error: diff --git a/tests/agent/test_codex_app_server_persist.py b/tests/agent/test_codex_app_server_persist.py index 55112fa319..46b167917c 100644 --- a/tests/agent/test_codex_app_server_persist.py +++ b/tests/agent/test_codex_app_server_persist.py @@ -111,6 +111,7 @@ def test_codex_turn_persists_each_message_exactly_once(): real AIAgent._flush_messages_to_session_db to prove no #860/#42039 duplicate-write regression on the codex path.""" tmp = tempfile.mkdtemp(prefix="codex_persist_") + db = None try: db = SessionDB(Path(tmp) / "state.db") sid = "sess-codex-once" @@ -163,7 +164,9 @@ def test_codex_turn_persists_each_message_exactly_once(): finally: import shutil - shutil.rmtree(tmp) + if db is not None: + db.close() + shutil.rmtree(tmp, ignore_errors=True) class TestGatewayPersistedResolution: