fix: stop consuming a mailbox from costing a round trip per message (#159) - #165
Merged
Merged
Conversation
…159) `inbox` archived each message with its own `move`, and the daemon forwarded `move` synchronously to the real store while `put` acked from its disk outbox. On a git bus that is fetch → commit → push per message, so a full mailbox blew through any command timeout while `peek` — served from the warm mirror — returned instantly. `inbox --as <alias>`, the documented recovery path when mail sits at another alias, was unusable for the same reason. Archiving is now one operation. A new `Batchable` capability (`moveMany`) is feature-detected like `Claimable`/`Waitable`; the git backend implements it as a single commit for the whole mailbox, and `Bus.archive` falls back to per-key moves if a batch is refused so partial progress still happens. The daemon's outbox carries moves and deletes too, so consuming acks in milliseconds like a send. Its poll replays the undelivered outbox over the store's view — without that, a poll between the ack and the flush would resurrect the messages the archive already consumed and deliver them twice. Finally, a git invocation that hangs is now a clear, attributable error after AGENTCOMM_GIT_TIMEOUT_MS (default 120s) instead of silence that is indistinguishable from a deadlock.
yonidavidson
force-pushed
the
fix/159-batch-consume
branch
from
August 9, 2026 07:47
e4dcae8 to
c46d592
Compare
This was referenced Aug 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #159.
Consuming a mailbox archived each message with its own
Backend.move, and the daemon forwardedmovesynchronously to the real store whileputwas acked from its disk outbox. On a git bus that is fetch → commit → push per message: N messages = N sequential round trips, soinboxblew through any command timeout whilepeek(served from the warm mirror) returned instantly.inbox --as <alias>— the documented recovery path when mail sits at another alias — was unusable for the same reason.What changed
Batchablecapability (src/types.ts) —moveMany(moves), feature-detected likeClaimable/Waitable.Bus.archiveuses it for the whole mailbox and falls back to per-key moves if the batch is refused, so a partial failure still archives what it can.src/backends/git.ts—moveManyputs every add/remove in ONE commit and pushes once. Also caps eachgitinvocation (AGENTCOMM_GIT_TIMEOUT_MS, default 120s): a remote that accepts the connection and goes quiet used to hang forever, which reaches the caller as a command that simply never returns.src/daemon.ts— the outbox now carries moves and deletes, not just puts, so consuming acks in milliseconds like a send does. The poll replays the undelivered outbox over the store's view, so an accepted-but-not-yet-flushed archive can't resurrect the messages it consumed. Old spool entries (puts without anop) still deliver.src/backends/socket.ts—moveManyover the daemon protocol;--syncstill forces straight-through delivery for moves and deletes.Tests
test/git.e2e.test.ts: consuming a 4-message mailbox adds exactly one commit to the bus branch.test/daemon.e2e.test.ts: consuming acks from the outbox, a poll before the drain does not re-deliver, anddaemon stoplands the archive on the store exactly once.test/bus.test.ts:moveManyis used once per archive, and a refused batch falls back to per-key moves.