Skip to content

fix(state): route session-resume reads through the WAL read-only connection (salvage #73539) - #77803

Merged
kshitijk4poor merged 1 commit into
NousResearch:mainfrom
kshitijk4poor:salvage-73539-resume-readonly
Aug 3, 2026
Merged

fix(state): route session-resume reads through the WAL read-only connection (salvage #73539)#77803
kshitijk4poor merged 1 commit into
NousResearch:mainfrom
kshitijk4poor:salvage-73539-resume-readonly

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Salvages #73539 by @pierrenode — commit cherry-picked to preserve authorship; one conflict resolved (main centralized the resume SELECT's column list into _CONVERSATION_ROW_COLUMNS after the PR's base — kept main's constant, the PR's connection routing).

Context — what this fixes, for whom

Anyone resuming sessions while the writer is busy: session.resume's read paths (get_resume_conversations, lineage walk, ancestor resolution) still ran on the writer connection under self._lock, so a resume convoyed behind writer flushes/checkpoints. Main already has the per-thread WAL read-connection infrastructure (_read_ctx(), added for dashboard polling in this campaign's #76895 line of work) — this PR routes the four resume-path read sites through it. In DELETE-journal mode _read_ctx() falls back to the locked writer path, so non-WAL runtimes are unchanged.

Absorption check (why this is NOT mooted by #76895)

#76895 routed dashboard/read-polling paths; the resume sites at hermes_state.py ~7003/7057/7096 still used self._lock + self._conn on current main (verified pre-pick). This PR is the complementary half for the resume path.

Verification (with one honest caveat)

  • tests/test_hermes_state.py: 178 passed on the merged tree
  • tests/test_session_db_read_path_split.py: 3 passed, 5 skipped LOCALLY — the 5 skips (including the PR's new test_session_resume_reads_do_not_take_writer_lock) are requires_wal tests, and this machine's SQLite 3.46.0 has the WAL-reset bug so Hermes runs journal_mode=DELETE. They exercise on any runtime with WAL active (the PR author built the skip guard correctly). The mutation check is therefore vacuous for the new test locally; the non-WAL fallback path (test_non_wal_uses_locked_path) does run and passes.
  • ruff clean

Closes #73539 (superseded by this salvage — original author credited via cherry-pick authorship).

…ection

get_messages_as_conversation, get_resume_conversations, and
get_ancestor_display_prefix still took self._lock — the same global
choke point the read-path split (WAL per-thread read-only connections)
was meant to remove from every recall/browse read. These three are the
hottest reads in the file: every session resume across the gateway,
CLI, and ACP adapter goes through one of them, so a resume racing a
burst of concurrent-session writer flushes still convoys behind them
exactly like the fixed paths used to.

_session_lineage_root_to_tip (the lineage walk shared by all three,
plus get_conversation_root) had its own independent self._lock use and
needed the same conversion — without it the outer functions still
blocked on the very first line.

Verified empirically: a reader thread calling all three functions
while another thread holds self._lock blocked for the writer's full
hold duration before the fix, and returned immediately after (SQLite
3.50.4 in this dev venv falls back to journal_mode=DELETE per the
WAL-reset-bug guard, so the requires_wal-marked regression test is
exercised via a local WAL-forced script instead; it still runs and
passes on any runtime where WAL is actually active).
@kshitijk4poor
kshitijk4poor enabled auto-merge (rebase) August 3, 2026 15:15
@alt-glitch alt-glitch added type/perf Performance improvement or optimization P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint area/sessions Session lifecycle, resume, persistence, history sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Aug 3, 2026
@kshitijk4poor
kshitijk4poor merged commit 67d4bbb into NousResearch:main Aug 3, 2026
43 checks passed
@kshitijk4poor
kshitijk4poor deleted the salvage-73539-resume-readonly branch August 5, 2026 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/sessions Session lifecycle, resume, persistence, history comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/perf Performance improvement or optimization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants