cmux-next: continuity gate kills and freezes the daemon mid agent turn, times recovery, checks the recovery UI

Merged
TE
16d ago
+414-13

The session continuity gate (#22187) killed the cmux-tui daemon only between turns. It didn't time the recovery, didn't look at what the app showed meanwhile, and never froze the daemon. This PR covers those cases.

Journey (scripts/cmux-next/restore-journey.py)

  • daemon: SIGKILL while an agent chat turn is in flight. The turn is the test agent's gate: turn, which streams and then waits on a FIFO.
    • Rows give the seconds from the kill to a new daemon, to the app connected to it, and to restore settled.
    • The turn must end (end_turn) and its answer must show on the chat page.
  • daemon-stop (new): SIGSTOP the daemon, as a wedged owner.
    • The app must notice and offer Restart cmux-tui.
    • Restart, on the button's path after its confirm, must start a new daemon, reconnect and bring every view back. Rows time each step.
    • The stopped process is ended at the end, and at exit, if it's still there.
  • Both variants sample debug.daemon and debug.surfaces every 250 ms during recovery. The row fails if any of these happens:
    • a window shows neither its workspace nor the connecting view;
    • a pane is blank;
    • a shown terminal is disconnected without reconnecting for over a second.
  • --continuity now runs quit,crash,daemon,daemon-stop,reboot. An explicit --variants overrides that list.

App (DEBUG builds only): debug.daemon reports:

  • the local daemon's startup and connection state, and its pid;
  • DaemonRecovery's offers_restart, is_restarting and restart_failure;
  • per window, whether it shows workspace content or the connecting view.

{action: "restart"} runs DaemonRecovery.restart(), the same call the Restart button makes after its confirm. {action: "retry"} runs Retry Now.

Proof

Swift test (failing first, df6041feef6), on the fleet:
package-test-lane.sh suite Packages/macOS/CmuxNext DaemonRestartTests: RED_RESULT on the test commit, GREEN_RESULT on the head.

Runtime test: JOURNEY_RESULT

Review: REVIEW_RESULT

Observed / Not run

OBSERVED

Changelog

none

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Extends the session continuity gate to kill or freeze the cmux-tui daemon while an agent chat turn is in flight, timing each recovery step and checking what the app shows meanwhile.

Journey (scripts/cmux-next/restore-journey.py)

  • daemon kills mid turn: the turn streams, waits on a gate, and must end and show on its page after the reconnect.
  • New daemon-stop variant freezes the daemon instead; the app must offer Restart and restart through the button's path.
  • Both variants sample debug.daemon and debug.surfaces every 250 ms: each window shows its workspace or connecting view, no pane is blank, every shown terminal stays connected/restoring/reconnecting, and neither call may go silent for over a second.
  • --continuity runs quit,crash,daemon,daemon-stop,reboot; an explicit --variants overrides the list.

Debug builds

  • debug.daemon lives in CmuxNextDaemonService (the app's size cap refused it) and reports the daemon's startup, connection, pid, recovery state, and per-window shows, omitting absent fields.
  • {action: "restart"} runs DaemonRecovery.restart() on the button's confirm path; {action: "retry"} runs Retry Now.

Proof

Swift test covering the report and Restart/Retry paths (failing first), plus the runtime journey result: JOURNEY_RESULT. Review: REVIEW_RESULT.

Observed / Not run

OBSERVED

Changelog

none