Repository navigation
V7: Return 409 with Retry-After when a channel's session is busy - #675
Merged
Merged
Conversation
…t it as a failed turn A channel turn on a session another process or replica runs (its run lease held: LOUSHO_SESSION_BUSY) was a 500 reported to onError with stage 'parse'. channelCore now answers a turn that fails before the ack itself: a 409 with Retry-After and the coded error for a busy session, else the usual 500; both are reported with stage 'turn'. The hosts forward response headers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LinuxDevil
force-pushed
the
v7-channel-session-busy
branch
from
October 19, 2026 20:41
9f02402 to
7beff3c
Compare
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.
Fixes audit finding SWE-2 (Vercel competitor audit, 2026-10-19).
What was wrong
Two channel replicas (or two agents) on one SQLite store, same
sessionKey, 0.7 s apart: the second replica's turn hit the run lease and answeredHTTP 500 {"error":"The request failed…","code":"LOUSHO_SESSION_BUSY"}, logged as[webhook] parse failed. A turn that failed before the ack was thrown to the host, which reported every such error with stage'parse'and mapped it to 500; only approval conflicts were 409.What changed
channelCore: a turn that fails before the channel acknowledged the request is now answered and reported by the core.LOUSHO_SESSION_BUSYis a409 { error, code: "LOUSHO_SESSION_BUSY" }withRetry-After: 2; any other error is still a 500 with only the error's code. Both go toonErrorwith stage'turn'(and the session id), not'parse'.ChannelCoreRespondtype:(status, body, headers?).ChannelRespondfor channels is unchanged, and a 2-arg respond still type-checks.mountChannels/mountFetchChannels: forward the optional headers onto the response. These are the hosts that own the transport, so channelCore can't set headers by itself. This is the minimal plumbing outside channelCore.parse, so a busy turn is already post-ack for them: they keep their 200 and the in-conversation "request failed" reply. No change there.docs/channels.md: documents the 409 + Retry-After and the'turn'stage.Tests
src/channels/channelCore.busy.test.ts: a stubbed agent whose turn throwsSDKError(LOUSHO_SESSION_BUSY)throughhttpChannel()gets 409 + numericRetry-After+code: LOUSHO_SESSION_BUSYon bothmountChannelsandmountFetchChannels, andonErroris called withstage: 'turn'. A generic pre-ack turn failure is still a 500 that hides the message, now reported as stage'turn'. All 3 failed before the fix (500 / stage'parse').npx vitest run src/channels src/deploy src/server: 50 files, 618 tests passed.npx tsc --noEmit,npm run typecheck:tests,npm run lint: clean.npm run test:coverage: only the known baseline failures remain (scripts/changelogGuard.test.ts, create-lousho-agentindex.test.ts/template.e2e.test.ts). One timing flake insrc/tools/mcp/connect.test.tsunder full-suite load passes alone (35/35).npm run fallow: exit 0.Changelog: Channels answer a turn on a session another process or replica is running (
LOUSHO_SESSION_BUSY) with409+Retry-Afterinstead of a 500, and report pre-ack turn failures toonErrorwith stage'turn'instead of'parse'.🤖 Generated with Claude Code