From a1bd8f6d76df65658c17c8326746a50fde4a9253 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Sun, 15 Nov 2026 10:02:17 -0500 Subject: [PATCH] Coordinator WAL commits stop fsyncing per commit: one durability policy, set to NORMAL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A single #comms send committed ~58 times across the coordinator's WAL stores (coordination 26, transcript_routes 12, registry 10, input_dispositions 8, turn_context 2) and, under synchronous=FULL, paid one fsync per commit — the bulk of the send burst's wall time (108 syncs/send measured). WAL keeps the database file consistent at every synchronous level. NORMAL loses nothing an application or process crash could take; only an OS crash or power loss can roll a WAL back, and only to the last checkpoint. For the coordinator that is self-healing: the bus message is the source of truth and cohort acceptance is idempotent (AlreadyApplied), so a rolled-back acceptance is re-derived on the next read. The policy was declared twice — WalStore defaulted FULL and CoordinationStore restated FULL as a literal in its own configure_connection. That duplication is why "change the durability" looked like two edits. Collapse it to one declaration on StoreWriter, the ancestor both share, and set it to NORMAL. WalStore inherits it; CoordinationStore applies cls.synchronous instead of a literal. A store that must survive power loss still overrides (goal stores declare EXTRA; transcript keeps NORMAL). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01XbFMSnLEc51gw21bLFFRK1 --- src/agent_comms/coordination/database.py | 6 +++--- src/agent_comms/storage/typed_table.py | 12 ++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/agent_comms/coordination/database.py b/src/agent_comms/coordination/database.py index 92301520c0..b90570a5cd 100644 --- a/src/agent_comms/coordination/database.py +++ b/src/agent_comms/coordination/database.py @@ -140,9 +140,9 @@ def configure_connection(cls, connection: sqlite3.Connection) -> None: connection.execute("PRAGMA foreign_keys = ON") # WAL is set once, on the private stage before the file is published (or by the # coordinator_wal carry with every owner stopped), and persists in the file header, so - # no opener switches the mode and fresh openers cannot race over it. A commit is one - # sync of the log; the rollback journal took three (journal, file, directory). - connection.execute("PRAGMA synchronous = FULL") + # no opener switches the mode and fresh openers cannot race over it. The durability of + # a commit is the one StoreWriter policy every WAL writer shares, not a literal here. + connection.execute(f"PRAGMA synchronous = {cls.synchronous}") def _prepare_private_file(self) -> None: self.path.parent.mkdir(parents=True, exist_ok=True) diff --git a/src/agent_comms/storage/typed_table.py b/src/agent_comms/storage/typed_table.py index 1d1f10cfde..e3b181c667 100644 --- a/src/agent_comms/storage/typed_table.py +++ b/src/agent_comms/storage/typed_table.py @@ -3274,6 +3274,14 @@ class StoreWriter(PublishedSQLiteFile): CarriedFile kind or RuntimeFile, and a TypedStore inherits DurableStore or DerivedStore. """ + # The durability every WAL writer here applies, declared once for the family. WAL keeps + # the database file consistent at every synchronous level, so NORMAL is correct and loses + # nothing an application crash could take: only an OS crash or power loss can roll a WAL + # back, and only to the last checkpoint. FULL fsynced the log on every commit; a message + # ping committed ~58 times across the coordinator stores and paid ~58 fsyncs for it. A + # store that must survive power loss raises its own bar (goal stores declare EXTRA). + synchronous: ClassVar[str] = "NORMAL" + @property @abstractmethod def store(self) -> WrittenFile: @@ -3518,9 +3526,9 @@ class RuntimeWriter(RuntimeFile, StoreWriter): class WalStore(SQLiteReader, StoreWriter, StoreLockFile): - """One WAL file owns connection setup, attachment and retirement.""" + """One WAL file owns connection setup, attachment and retirement. - synchronous: ClassVar[str] = "FULL" + Its durability is StoreWriter.synchronous; a store that needs more overrides it.""" def _create_file(self) -> None: """Create only a new inode; never close a descriptor for a live SQLite inode."""