Repository navigation
fix(client): register running sessions missed while disconnected - #53012
Open
kitlangton wants to merge 2 commits into
Open
kitlangton wants to merge 2 commits into
kitlangton wants to merge 2 commits into
Conversation
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.
Why
When the TUI's event stream drops while a subagent starts, or the TUI starts while one is already running, it never receives that child's
session.created. Reconnect hydration restores the child's running status from/api/session/active, but never loads the child's session info, so the child never joins its root's family. Anything derived from the family is then wrong until the TUI restarts: the open picker shows the root as idle while its background subagent is still running, and tab busy state and family cost miss the child too.What Changes
After the reconnect snapshot is applied, any running session the client has no info for is synced, which registers it under its root.
Before: TUI offline → background subagent starts → TUI reconnects →
Release checklistrow in Ctrl-O shows no spinner, although its child is running.After: Same sequence → the row shows the running spinner.
sequenceDiagram participant TUI participant Server Note over TUI,Server: TUI disconnected Server-)TUI: session.created (child), missed Server-)TUI: session.execution.started (child), missed TUI->>Server: reconnect, server.connected TUI->>Server: GET /api/session/active Server-->>TUI: { child: running } TUI->>Server: GET /api/session/{child} (new) Server-->>TUI: child info with parentID Note over TUI: child joins the root's family, root row shows runningDemo
Real production TUI driven by
opencode-drivewith a simulated model. Same script and fixture for both: the TUI's connections are refused, a background subagent starts and holds its response, connections heal, then Ctrl-O filters to the root. Left:v2atd1f8f5b35e. Right: this branch.reconnect-child-family.mp4
Scope
Hydration now loads info only for sessions the snapshot reports as running and the client has never seen. That covers sessions created while disconnected and sessions already running when the client started, which had the same problem: a running child under a root that isn't open never joined its family. On reconnect this matches what a client that stayed connected would hold, since the live
session.createdhandler already loads every new session server-wide. It reads nothing beyond session info.Known limits, unchanged by this PR:
session.createdpath.This does not change how execution status itself is reconciled. The original report, a spinner still running long after a session went idle, happened around managed-service restarts and has not been reproduced yet.
Verification
adds running sessions created while disconnected to their familytest fails without the change and passes with it; the 8 family/activity tests pass.public import boundaries,exposes every standard HTTP API group, and two session HTTP/Effect contract tests) fail identically on the untouched base.bun run check: 36/36 tasks succeed.reconnect-child-family.tsfails ond1f8f5b35e(rootRowRunning: false) and passes here (rootRowRunning: true). Gauntlet seed 5, which found this, failed twice ond1f8f5b35eand passes on this branch along with seeds 4 and 8.