Skip to content

fix: restore mailbox on consume_pending session write failure - #1161

Open
STiFLeR7 wants to merge 1 commit into
usestrix:mainfrom
STiFLeR7:fix/consume-pending-mailbox-loss-on-write-failure
Open

fix: restore mailbox on consume_pending session write failure#1161
STiFLeR7 wants to merge 1 commit into
usestrix:mainfrom
STiFLeR7:fix/consume-pending-mailbox-loss-on-write-failure

Conversation

@STiFLeR7

Copy link
Copy Markdown

Summary

consume_pending() drains the agent's mailbox and zeroes pending_counts under the lock, then — outside the lock — tries to persist the drained items via session.add_items(). On failure it only logged the exception and fell through to returning the original (now-inflated) count as if the write had succeeded.

Callers with include_items=False (execution.py after a wait, respond/tool.py) rely entirely on the session for the next turn — they don't get the items back, just a count. So a transient write failure (e.g. a locked SQLite session) silently dropped the user's message: not in the mailbox (already cleared), not in the session (write failed), and reported as delivered to the caller.

Fix

On write failure:

  • Restore the drained messages to the front of the mailbox (any messages that arrived concurrently while the lock was released stay after them, preserving order).
  • Add their count back to pending_counts.
  • Set runtime.wake so a blocked wait_for_message() notices the restored pending work.
  • Return (0, []) so this attempt is honestly reported as not having delivered anything.

This makes the next consume_pending() call retry the same messages instead of losing them, matching the issue's suggested fix.

Fixes #1107.

Testing

  • Added test_consume_pending_restores_mailbox_on_session_write_failure, which injects a failing session.add_items via monkeypatch, asserts the mailbox/pending_counts are restored and (0, []) is returned, then removes the failure and confirms a subsequent consume_pending() call successfully delivers the same message.
  • Verified red-before-green: reverted the fix, confirmed the new test fails exactly as described (count=1 returned despite the write failing); restored the fix, confirmed it passes.
  • uv run pytest tests/test_execution.py -q: 60 passed.
  • uv run pytest tests/ -q: 1062 passed; 21 pre-existing failures confirmed present on unmodified main too (all Windows-specific — POSIX permission-bit assertions and a path-parsing bug that misreads a Windows drive letter as a path segment), none related to agents.py or this change.
  • uv run ruff check, uv run ruff format, uv run mypy strix/core/agents.py: all clean.

consume_pending() drains the agent's mailbox and zeroes pending_counts
under the lock, then - outside the lock - tries to persist the drained
items via session.add_items(). On failure it only logged the exception
and fell through to returning the original (now-inflated) count as if
the write had succeeded. Callers with include_items=False (execution.py
after a wait, respond/tool.py) rely entirely on the session for the
next turn, so a transient write failure (e.g. a locked SQLite session)
silently dropped the user's message: not in the mailbox (already
cleared), not in the session (write failed), and reported as delivered
to the caller.

On write failure, restore the drained messages to the front of the
mailbox and add their count back to pending_counts, wake the runtime so
a blocked wait_for_message() notices the pending work again, and return
(0, []) so this attempt is honestly reported as not having delivered
anything. This makes the next consume_pending() call retry the same
messages instead of losing them.

Fixes usestrix#1107.
@greptile-apps

greptile-apps Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Restores drained mailbox messages when session persistence fails so they can be retried instead of silently lost.

  • Prepends the failed batch to preserve its ordering relative to messages received concurrently.
  • Restores pending message accounting and wake state, and reports zero delivered items.
  • Adds a regression test covering failure, restoration, and successful retry.

Confidence Score: 5/5

The PR appears safe to merge, with the restored mailbox state remaining reachable by the existing pending-message retry flow.

The failure path restores the original batch ahead of concurrent arrivals under the coordinator lock, repairs pending-count state, and causes the next wait cycle to retry delivery; no blocking or independently actionable issue remains.

Important Files Changed

Filename Overview
strix/core/agents.py Adds lock-protected mailbox and pending-count restoration after session write failures without introducing a concrete correctness issue.
tests/test_execution.py Adds focused regression coverage confirming failed writes return no delivery and preserve messages for a later successful retry.

Reviews (1): Last reviewed commit: "fix: restore mailbox on consume_pending ..." | Re-trigger Greptile

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.

consume_pending drops mailbox messages when session write fails

1 participant