Skip to content

fix(host-sweep): reopen outbound DB as writable for orphan claim cleanup#2183

Merged
gavrielc merged 2 commits intoqwibitai:mainfrom
cfis:fix/host-sweep-outbound-db-rw
May 2, 2026
Merged

fix(host-sweep): reopen outbound DB as writable for orphan claim cleanup#2183
gavrielc merged 2 commits intoqwibitai:mainfrom
cfis:fix/host-sweep-outbound-db-rw

Conversation

@cfis
Copy link
Copy Markdown
Contributor

@cfis cfis commented May 2, 2026

Problem

PR #2151 added deleteOrphanProcessingClaims() to resetStuckProcessingRows() in host-sweep.ts, but outDb is always opened readonly (immutable: true via openOutboundDb). The write silently fails, leaving orphan processing_ack rows that block future message delivery for the session.

Fix

Add openOutboundDbRw() alongside the existing readonly opener in session-db.ts and re-export it from session-manager.ts. In resetStuckProcessingRows(), open a short-lived writable handle just for the delete, then close it immediately. The readonly handle is still used for all reads above.

This is safe because resetStuckProcessingRows() is only called after the container has been killed or confirmed not running, so there is no concurrent writer.

Changes

  • src/db/session-db.ts — add openOutboundDbRw(dbPath)
  • src/session-manager.ts — re-export as openOutboundDbRw(agentGroupId, sessionId)
  • src/host-sweep.ts — use writable handle for the delete in resetStuckProcessingRows()

🤖 Generated with Claude Code

PR qwibitai#2151 added deleteOrphanProcessingClaims() to resetStuckProcessingRows(),
but outDb is always opened readonly (openOutboundDb uses immutable: true).
The write silently failed, leaving orphan processing_ack rows that block
future message delivery for the session.

Fix: add openOutboundDbRw() alongside the existing readonly opener and use
it in resetStuckProcessingRows() to open a short-lived writable handle just
for the delete. The readonly handle is still used for all reads above.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gavrielc gavrielc merged commit 6b76c1a into qwibitai:main May 2, 2026
@gavrielc
Copy link
Copy Markdown
Collaborator

gavrielc commented May 2, 2026

@cfis Thank you for the fix!!

cfis added a commit to cfis/nanoclaw that referenced this pull request May 3, 2026
…ssed in tests

qwibitai#2183 added orphan-claim cleanup that reopens `outbound.db` by session
path (`openOutboundDbRw(session.agent_group_id, session.id)`) so the
delete runs against a writable handle even when callers pass a readonly
one. That works for the production caller — there's a real on-disk
session DB at the expected path.

The test wrapper `_resetStuckProcessingRowsForTesting` (introduced in
the same series, qwibitai#2151) is called with in-memory DBs that have no
on-disk path. The reopen creates a fresh empty file at
`<DATA_DIR>/v2-sessions/ag-test/sess-test/outbound.db`, runs the delete
against that, and leaves the in-memory `outDb` (which the test reads
afterward) untouched. The two `resetStuckProcessingRows — orphan claim
cleanup` tests assert `getProcessingClaims(outDb).toEqual([])` after
the call and fail on the row that's still there.

Fix: drop the `_…ForTesting` wrapper, export `resetStuckProcessingRows`
directly with an optional `writableOutDb` parameter. When omitted
(production), the function reopens `outbound.db` RW by session path —
existing behavior, existing safety guarantee. When provided (tests, or
any future caller that already holds a writable handle), the function
uses it directly and skips the reopen. The optional parameter has a
real meaning, not a "for tests" hack.

Public API surface change: `_resetStuckProcessingRowsForTesting` is
gone, `resetStuckProcessingRows` is now exported. No other callers
inside the repo besides the test.
cfis added a commit to cfis/nanoclaw that referenced this pull request May 3, 2026
…ssed in tests

qwibitai#2183 added orphan-claim cleanup that reopens `outbound.db` by session
path (`openOutboundDbRw(session.agent_group_id, session.id)`) so the
delete runs against a writable handle even when callers pass a readonly
one. That works for the production caller — there's a real on-disk
session DB at the expected path.

The test wrapper `_resetStuckProcessingRowsForTesting` (introduced in
the same series, qwibitai#2151) is called with in-memory DBs that have no
on-disk path. The reopen creates a fresh empty file at
`<DATA_DIR>/v2-sessions/ag-test/sess-test/outbound.db`, runs the delete
against that, and leaves the in-memory `outDb` (which the test reads
afterward) untouched. The two `resetStuckProcessingRows — orphan claim
cleanup` tests assert `getProcessingClaims(outDb).toEqual([])` after
the call and fail on the row that's still there.

Fix: drop the `_…ForTesting` wrapper, export `resetStuckProcessingRows`
directly with an optional `writableOutDb` parameter. When omitted
(production), the function reopens `outbound.db` RW by session path —
existing behavior, existing safety guarantee. When provided (tests, or
any future caller that already holds a writable handle), the function
uses it directly and skips the reopen. The optional parameter has a
real meaning, not a "for tests" hack.

Public API surface change: `_resetStuckProcessingRowsForTesting` is
gone, `resetStuckProcessingRows` is now exported. No other callers
inside the repo besides the test.
gavrielc added a commit that referenced this pull request May 5, 2026
fix(host-sweep): orphan-claim delete missed in tests (regression from #2183)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants