Commit Graph
2 Commits
Author SHA1 Message Date
Miguel Palhas 938dd62648 fix(maestro): stop retrying a WS attach that never opened
Integration review (#168): a rejected attach handshake — a dormant
session's 409 not_attachable, most likely — looks identical to a
dropped stream from the WebSocket API (close code 1006, no reason).
shouldRetryClose kept retrying it on the catalog's Running/Dead check
alone, which loops for as long as the catalog hasn't caught up with
the session going dormant.

Track whether the socket ever reached `open`; a handshake that never
did is a rejection, not a blip, so it is never retried regardless of
catalog status. The caller (wired up in the next commit) gets a
distinct onNeverAttached callback instead of onClosed, so it can offer
the resume affordance rather than assuming the session is gone.
2026-09-04 09:19:09 +01:00
Miguel PalhasandClaude Opus 5 f31377c34f fix(maestro): three defects the review flagged and left open
ci / web (pull_request) Successful in 28s
ci / rust (pull_request) Successful in 1m58s
ci / web (push) Successful in 34s
ci / rust (push) Successful in 2m44s
SPA attach had no reconnect at all. Any dropped frame closed the socket,
`onClosed` fired, and the pane was destroyed permanently — the TUI
reconnects forever on the same endpoint. Session death also reached the UI
on two uncoordinated channels: the row from the events socket, the pane
from `ws.onclose`, with nothing reconciling them, so either could happen
without the other.

The catalog is now the authority. `shouldRetryClose` decides from session
status: Running means the link dropped, so retry with 500ms-to-10s
backoff; Dead means the PTY stream was sealed and nothing more is coming;
absent means it is gone. Application closes (4000+, a relayed daemon
rejection) and clean closes are never retried. The shell also closes any
pane whose session has left the catalog. The policy lives in reconnect.ts
so it is tested without a DOM.

kill_session checked `has()` before `kill()`, which only opened a window
for the liveness watcher to reap in between — turning a 404 into a 502.
`kill` reports the miss itself.

with_spawn_history logged and carried on when `Arc::get_mut` failed,
producing a daemon whose recent-dirs picker is permanently empty with
nothing to show for it. It panics now: that is a construction-order
mistake, at startup, in code that runs once.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 16:31:54 +01:00