{"repo":"NousResearch/hermes-agent","public_id":"30636","display_label":"SQLite state.db corruption and durability fixes","summary":"These members concern corruption of state.db during unclean shutdowns (e.g., SIGTERM under launchd) and the absence of crash recovery, alongside two fixes adding fsync barriers and WAL checkpoint settings to improve write durability on macOS.","subsystem":"agent","counts":{"members":4,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":2,"merged_prs":1,"attempt_prs":1},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":54045},"resolution":{"state":"partially_resolved","by":"pr-54045"},"freshness":{"state":"verified","last_verified_at":"2026-06-28T07:53:19+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.3933333333333333},"fix_edges":[{"issue_number":30636,"pr_number":54045,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true}],"members":[{"kind":"issue","number":30636,"title":"state.db corruption from SIGTERM during launchd shutdown under high load","url":null,"state":"closed"},{"kind":"issue","number":32687,"title":"SessionDB: no crash recovery path when state.db is corrupted after unclean shutdown","url":null,"state":"closed"},{"kind":"pr","number":30654,"title":"fix(state): add PRAGMA synchronous=FULL + TRUNCATE checkpoint to prevent WAL corruption","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#54045","number":54045},{"kind":"pr","value":"#30636","number":30636},{"kind":"pr","value":"#54045","number":54045}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":54045,"title":"fix(state): F_FULLFSYNC barrier at WAL checkpoints on macOS (#30636)","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["hermes_state.py","infographic/state-db-fullfsync/infographic.png","tests/test_hermes_state.py"],"fix_hunks":[{"file":"hermes_state.py","hunks":["@@ -19,6 +19,7 @@\n import random\n import re\n import sqlite3\n+import sys\n import threading\n import time\n from pathlib import Path","@@ -241,6 +242,41 @@ def _on_disk_journal_mode(conn: sqlite3.Connection) -> Optional[str]:\n     return str(mode).strip().lower() if mode is not None else None\n \n \n+def _apply_macos_checkpoint_barrier(conn: sqlite3.Connection) -> None:\n+    \"\"\"Enable ``PRAGMA checkpoint_fullfsync`` on macOS (no-op elsewhere).\n+\n+    On Darwin, ``synchronous=FULL`` (the WAL default) issues a plain\n+    ``fsync()``, which Apple documents does *not* guarantee that data\n+    has reached stable storage or that writes are not reordered — see\n+    the ``fsync(2)`` man page.  SQLite's WAL corruption-safety guarantee\n+    assumes the OS honors the fsync write barrier; macOS does not unless\n+    the app uses ``F_FULLFSYNC``.\n+\n+    During a launchd *system* shutdown/reboot the OS page cache is\n+    dropped (effectively a power-loss event for in-flight pages), so a\n+    WAL checkpoint whose ``fsync()`` \"reported\" durable may never have\n+    hit the platter — corrupting ``state.db`` with a malformed image.\n+    This is the trigger in issue #30636 (\"SIGTERM during launchd\n+    shutdown under high load\"), distinct from a plain in-session kill\n+    (which the page cache survives and SQLite recovers from).\n+\n+    ``checkpoint_fullfsync=1`` forces an ``F_FULLFSYNC`` barrier only at\n+    checkpoint boundaries — where WAL frames land in the main DB — so the\n+    cost amortizes to roughly +0.1 ms/commit (vs ~+4 ms for the broader\n+    ``fullfsync=1`` that flushes on every commit's WAL sync).  Guarded by\n+    ``sys.platform == \"darwin\"`` because ``F_FULLFSYNC`` is macOS-only;\n+    on other platforms the PRAGMA is a no-op, so we skip it entirely.\n+\n+    Best-effort: never raises.\n+    \"\"\"\n+    if sys.platform != \"darwin\":\n+        return\n+    try:\n+        conn.execute(\"PRAGMA checkpoint_fullfsync=1\")\n+    except sqlite3.OperationalError:\n+        pass\n+\n+\n def apply_wal_with_fallback(\n     conn: sqlite3.Connection,\n     *,","@@ -271,12 +307,14 @@ def apply_wal_with_fallback(\n     try:\n         current_mode = conn.execute(\"PRAGMA journal_mode\").fetchone()\n         if current_mode and current_mode[0] == \"wal\":\n+            _apply_macos_checkpoint_barrier(conn)\n             return \"wal\"\n     except sqlite3.OperationalError:\n         pass\n \n     try:\n         conn.execute(\"PRAGMA journal_mode=WAL\")\n+        _apply_macos_checkpoint_barrier(conn)\n         return \"wal\"\n     except sqlite3.OperationalError as exc:\n         msg = str(exc).lower()"]},{"file":"tests/test_hermes_state.py","hunks":["@@ -4191,6 +4191,96 @@ def execute(self, sql, params=()):\n             \"set-pragma must fire on a fresh (non-WAL) connection\"\n         )\n \n+    def test_macos_checkpoint_fullsync_barrier_applied(self, tmp_path, monkeypatch):\n+        \"\"\"On Darwin, apply_wal_with_fallback sets checkpoint_fullfsync=1 (issue #30636).\"\"\"\n+        import sqlite3\n+        import hermes_state\n+        from hermes_state import apply_wal_with_fallback\n+\n+        class _TracingConn(sqlite3.Connection):\n+            def __init__(self, *a, **kw):\n+                super().__init__(*a, **kw)\n+                self.executed = []\n+\n+            def execute(self, sql, params=()):\n+                self.executed.append(sql)\n+                return super().execute(sql, params)\n+\n+        monkeypatch.setattr(hermes_state.sys, \"platform\", \"darwin\")\n+\n+        db_path = tmp_path / \"macos_fresh.db\"\n+        conn = _TracingConn(str(db_path))\n+        try:\n+            result = apply_wal_with_fallback(conn)\n+        finally:\n+            conn.close()\n+\n+        assert result == \"wal\"\n+        assert any(\"checkpoint_fullfsync=1\" in sql for sql in conn.executed), (\n+            \"checkpoint_fullfsync barrier must be applied on macOS\"\n+        )\n+\n+    def test_macos_barrier_applied_when_already_wal(self, tmp_path, monkeypatch):\n+        \"\"\"The Darwin barrier fires on the already-WAL early-return path too.\"\"\"\n+        import sqlite3\n+        import hermes_state\n+        from hermes_state import apply_wal_with_fallback\n+\n+        class _TracingConn(sqlite3.Connection):\n+            def __init__(self, *a, **kw):\n+                super().__init__(*a, **kw)\n+                self.executed = []\n+\n+            def execute(self, sql, params=()):\n+                self.executed.append(sql)\n+                return super().execute(sql, params)\n+\n+        db_path = tmp_path / \"macos_wal.db\"\n+        with sqlite3.connect(str(db_path)) as seed:\n+            seed.execute(\"PRAGMA journal_mode=WAL\")\n+\n+        monkeypatch.setattr(hermes_state.sys, \"platform\", \"darwin\")\n+\n+        conn = _TracingConn(str(db_path))\n+        try:\n+            result = apply_wal_with_fallback(conn)\n+        finally:\n+            conn.close()\n+\n+        assert result == \"wal\"\n+        assert any(\"checkpoint_fullfsync=1\" in sql for sql in conn.executed), (\n+            \"checkpoint_fullfsync barrier must fire on the already-WAL path\"\n+        )\n+\n+    def test_checkpoint_fullsync_barrier_skipped_off_darwin(self, tmp_path, monkeypatch):\n+        \"\"\"Non-macOS platforms must NOT issue the macOS-only PRAGMA.\"\"\"\n+        import sqlite3\n+        import hermes_state\n+        from hermes_state import apply_wal_with_fallback\n+\n+        class _TracingConn(sqlite3.Connection):\n+            def __init__(self, *a, **kw):\n+                super().__init__(*a, **kw)\n+                self.executed = []\n+\n+            def execute(self, sql, params=()):\n+                self.executed.append(sql)\n+                return super().execute(sql, params)\n+\n+        monkeypatch.setattr(hermes_state.sys, \"platform\", \"linux\")\n+\n+        db_path = tmp_path / \"linux_fresh.db\"\n+        conn = _TracingConn(str(db_path))\n+        try:\n+            result = apply_wal_with_fallback(conn)\n+        finally:\n+            conn.close()\n+\n+        assert result == \"wal\"\n+        assert not any(\"checkpoint_fullfsync\" in sql for sql in conn.executed), (\n+            \"checkpoint_fullfsync must not be issued off macOS\"\n+        )\n+\n     def test_apply_wal_concurrent_connects_no_eio(self, tmp_path):\n         \"\"\"20 threads calling connect() on the same DB must not see disk I/O error.\"\"\"\n         import sys\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}