Repository navigation
app: bound host joins and release drains - #2014
Merged
Merged
Conversation
Share one five-second budget across desktop host discovery and welcomes. Return a retryable unreachable receipt, close failed sockets and clear the deadline on successful joins without changing terminal dialing policy. Drain conversation producers against one closing deadline channel. Cover silent hosts, retry, long turns and delayed clean producers with fakes. Verify timeout consumption with the shortened timer hook, and document the desktop behavior. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AbirAbbas
force-pushed
the
fix/app-host-join-budget
branch
from
October 28, 2026 19:48
abaf6d7 to
d3aa35c
Compare
This was referenced Oct 29, 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.
What was wrong
When the desktop opens a chat that a terminal
codeafis hosting, app mode joins that terminal's session host.appJoinExistingcalledremote.Dial, which writes hello and then waits for the welcome with no deadline, while holding the chat's gate. If the terminal host is busy, wedged or stopped, the desktop's open stays pending until the host answers again. Users who run the TUI and the desktop side by side read this as "the engine is waiting".Separately,
appBackend.finishshared onetime.Afterchannel across several waits. After the first wait consumed its value, a later unfinished producer could block the release forever.What changes (app mode only)
unreachable: "This chat didn't answer from the other codeaf window. Try again, or continue there." The desktop already shows that in its existing "Couldn't open chat / Try again" receipt. No takeover, no reopen of a locked journal, no replayed send. The terminal's ownremote.Dialis unchanged.box.Close(). A clean close still drains everything it produced.Validation contract → tests
unreachablewithin the budget, releases the gate and closes the socket; other requests keep answering (TestAppHostJoinSilentOpenReleasesGate).…CandidatesShareBudget,…StartingHostSharesBudget).…RetryAndLongTurn).…FailedCandidatesClose).finishwith stuck producers returns within the release wait; clean producers drain promptly (TestAppFinishSharesOneDeadline,TestAppFinishDrainsCleanProducersPromptly).Manual verification on a real engine
Linux, isolated temporary homes, a local OpenAI-compatible stub, and a real
codeaf engine --daemonhost holding the chat. Only the host was SIGSTOPped for 12 s while the app calledagents.open:unreachable(copy above)On both binaries,
agents.listandmodels.listkept answering in milliseconds during the pause. In all six runs, the retry right after resume joined the original chat. Transcript bytes were unchanged, with no new entries, tasks or provider calls. A healthy join followed by a 16 s turn completed on both binaries.Checks
gofmt,go vet ./cmd/codeaf, and the named tests above: 18 cases, all passing. CI (ci.yml,ci-full.yml) was dispatched on this branch; it is judged against an app/v3 Full baseline because app/v3's own Full is red.Merge order: after #2009 lands in app/v3 (rebase then). This branch does not touch #2011's hunks.
🤖 Generated with Claude Code