Conversation
PR 105985 — fix(desktop): retain background turn leases across reconnectTransport drops no longer settle running turns: the whole-turn lease now keeps the route alive so reconnect can replay missed events (
Non-blocking: a dropped route is now held open (with backoff redial) until explicit disposal or terminal settlement — bounded by existing backoff caps, acceptable. No concerns. |
6 of 8 tasks
OutThisLife
force-pushed
the
fix/desktop-background-turn-reconnect
branch
from
September 30, 2026 02:44
2985964 to
04c9c9e
Compare
OutThisLife
enabled auto-merge (rebase)
September 30, 2026 02:44
OutThisLife
force-pushed
the
fix/desktop-background-turn-reconnect
branch
from
September 30, 2026 02:49
04c9c9e to
27d5f8a
Compare
This branch has not been deployed
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 does this PR do?
Keeps a background secondary gateway alive across a transient WebSocket disconnect when its only remaining owner is an active-turn lease.
After a routed
prompt.submitACK, the per-request lease is released but the whole-turn lease must remain. Previously, the secondary'sclosed/errorcallback released that last lease, synchronously disposed the route, and setwantOpen = falsebefore reconnect could be scheduled. The background session then received neither replayed outage events nor subsequent completion unless another consumer rescued the route.Move orphaned-turn cleanup to actual secondary disposal. Transport reconnect retains the existing route and JSON-RPC replay state; explicit disposal disables reconnect and pending material-edit redial before releasing leases. Normal authoritative settlement remains unchanged.
Related Issue
Fixes #105983
Duplicate searches covered issues and open/closed PRs using desktop reconnect, secondary gateway, turn lease, and narrower mechanism terms. Adjacent changes inspected:
No exact competing fix found; mechanism searches repeated before publication.
Type of Change
Changes Made
apps/desktop/src/store/gateway.ts: preserve active-turn leases on transport close/error; release them at actual disposal with reentrancy protection and cancelled pending redial.apps/desktop/src/store/gateway-background-reconnect.test.ts: exercise the real request router, registry, HermesGateway and JSON-RPC client through an asynchronous mock WebSocket. Two parameterized behavior contracts cover automatic reconnect/event replay/foreground isolation, plus explicit close/removal/prune/permanent missing-connection cleanup and same-session reuse.apps/desktop/src/store/session-request-router.test.ts: replace the old immediate-disconnect-release expectation with retention until explicit route close. Existing terminal ACK, authoritative settlement and pruning tests remain exercised.No real remote gateway or model calls; no app/backend restart. Existing backoff policy is unchanged: this is ownership-lifetime repair, not a new retry-budget policy. Explicit teardown and permanent missing-connection failures stop retries, and authoritative session settlement releases an unpinned recovered route.
How to Test
prompt.submitACK while the turn runs.Executed from the repository root with independently installed worktree dependencies:
Checklist
Code
pytest tests/ -qand all tests pass — not run; renderer-only TypeScript change. Relevant desktop checks were run; full UI has reproduced baseline failures detailed below.Documentation & Housekeeping
cli-config.yaml.example: N/A, no configuration changes.CONTRIBUTING.md/AGENTS.md: N/A, no architecture/workflow changes.For New Skills
N/A.
Screenshots / Logs
Pinned base:
b2aa855b626ff8688eb34b95c60ee8b6a4af3679.Local commit:
29859645ab6ce656406282f4289d7bb16aec16f1.assert-dist-built: PASS. Vite reports native-config/dynamic-import/plugin timing warnings; build succeeds.voice-prefs.test.ts: desktop toggle across refreshes; legacy preference migration.billing/index.test.tsx: auto-refill bounds; polling/settled buy controls.fallback-model.test.ts: localized omitted-character count (5,000expectation).use-prompt-actions/utils.test.ts: locale-specific thousands separators.Local evidence:
/tmp/hermes-h2-red.log,/tmp/hermes-h2-final-focused.log,/tmp/hermes-h2-final-typecheck.log,/tmp/hermes-h2-lint.log,/tmp/hermes-h2-build.log,/tmp/hermes-h2-final-full-ui.log,/tmp/hermes-h2-baseline-full-ui.log,/tmp/hermes-h2-duplicates.json,/tmp/hermes-h2-adjacent-prs.json.