Skip to content

fix(tmux): post-spawn liveness check for silent in-pane exit (issue #513) - #531

Open
bradbrok wants to merge 1 commit into
mainfrom
fix/tmux-spawn-liveness-check
Open

fix(tmux): post-spawn liveness check for silent in-pane exit (issue #513)#531
bradbrok wants to merge 1 commit into
mainfrom
fix/tmux-spawn-liveness-check

Conversation

@bradbrok

Copy link
Copy Markdown
Owner

Summary

Implements the structural defense from issue #513.

  • Root cause: tmux new-session returns 0 as long as the child shell + command launched. If the in-pane command exits immediately (bad flag, auth error, missing binary, API rejection, etc.) the detached session auto-reaps silently. The caller sees a successful spawn; the state machine ends up CONNECTED against nothing and queued messages stack forever.
  • Fix: After new_session() succeeds in _spawn_tmux_repl(), wait ~150ms then call has_session(). If the session is gone, raise RuntimeError so the existing BOOTING → DEAD via BOOT_FAILED transition fires correctly — same path as any other spawn failure.
  • Tunable: _SPAWN_LIVENESS_DELAY_SEC = 0.15 constant alongside _COLD_START_TIMEOUT_SEC; tests patch it to 0 for speed.
  • _make_mock_tmux() updated to use itertools.chain([has_session_initial], repeat(True)) so the pre-spawn stale-check and post-spawn liveness-check get the right values without breaking any existing test.

Test plan

  • New test test_cold_start_session_dies_immediately_drives_to_dead: spawn succeeds, both has_session calls return False → RuntimeError("session died immediately after spawn") → state == DEAD
  • All 9 cold-start tests pass including the new one (0.99s — liveness sleep is no-op in tests)
  • 95 test_tmux_session tests pass
  • 208 tests pass across test_tmux_session / test_agent_status / test_tmux_transcript / test_transport_state
  • Ruff clean

Closes #513.

🤖 Heartbeat maintenance — Barsik


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Heartbeat maintenance: this branch was 16 commits behind main (dirty/conflicting). Rebased onto current main and resolved the single conflict in tmux_session.py — both sides added code after the cold-start timeout block; resolution keeps the liveness check from this PR followed by the force_fresh_context_once NOTE added in #545.

Rebased branch: fix/tmux-spawn-liveness-check-rebase — 140 tmux tests pass (including the new test_cold_start_session_dies_immediately_drives_to_dead). Ready to force-push to this branch and merge if approved.


Generated by Claude Code

@bradbrok
bradbrok force-pushed the fix/tmux-spawn-liveness-check branch from 0e0f0c6 to 0bdec9c Compare May 20, 2026 10:17

Copy link
Copy Markdown
Owner Author

Heartbeat maintenance: previous rebase branch (fix/tmux-spawn-liveness-check-rebase) was 4 commits behind main due to #560, #563, #565 landing since last heartbeat. Re-rebased cleanly onto current main (8e20de0) — no conflicts in tmux_session.py.

Fresh branch: fix/tmux-spawn-liveness-check-rebase2 — 168 tmux tests pass (including test_cold_start_session_dies_immediately_drives_to_dead), full suite 2602 passed / 1 skipped.

Ready to force-push to fix/tmux-spawn-liveness-check and merge if approved.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Heartbeat maintenance: fix/tmux-spawn-liveness-check-rebase2 was 13 commits behind main (#571#584 landed since last heartbeat). Rebased cleanly onto current main (0b962d5) — no conflicts.

Fresh branch: fix/tmux-spawn-liveness-check-rebase3 — 225 tmux tests pass (test_tmux_session + test_tmux_transcript, including test_cold_start_session_dies_immediately_drives_to_dead); full suite 2432 passed / 1 skipped.

Ready to force-push to fix/tmux-spawn-liveness-check and merge if approved.


_Generated by Claude Code


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Heartbeat maintenance: fix/tmux-spawn-liveness-check-rebase3 was 1 commit behind main (#585 landed since last heartbeat). Cherry-picked cleanly onto current main (3d8d9a5) — no conflicts.

Fresh branch: fix/tmux-spawn-liveness-check-rebase4 — 237 tmux tests pass (test_tmux_session + test_tmux_transcript, including test_cold_start_session_dies_immediately_drives_to_dead).

Ready to force-push to fix/tmux-spawn-liveness-check and merge if approved.


Generated by Claude Code


Generated by Claude Code

@bradbrok
bradbrok force-pushed the fix/tmux-spawn-liveness-check branch from 0bdec9c to c0595b0 Compare May 27, 2026 14:13

Copy link
Copy Markdown
Owner Author

Heartbeat maintenance (2026-05-27): rebased onto current main (3c358a1 — includes #585#600, 9 commits since last heartbeat rebase).

Cherry-picked cleanly — no conflicts in tmux_session.py or test_tmux_session.py. Force-pushed to fix/tmux-spawn-liveness-check.

Tests: 298 passed (test_tmux_session + test_tmux_transcript + test_transport_state), including test_cold_start_session_dies_immediately_drives_to_dead. CI will run now.

🤖 Barsik heartbeat


Generated by Claude Code

@bradbrok
bradbrok force-pushed the fix/tmux-spawn-liveness-check branch from c0595b0 to 8a65331 Compare May 28, 2026 14:07

Copy link
Copy Markdown
Owner Author

Heartbeat maintenance (2026-05-28): rebased onto current main (8978dfb — 1 commit since last heartbeat rebase: phantom-drain fix #595).

Rebased cleanly — no conflicts in tmux_session.py or test_tmux_session.py. Force-pushed to fix/tmux-spawn-liveness-check.

Tests: 303 passed (test_tmux_session + test_tmux_transcript + test_transport_state), including test_cold_start_session_dies_immediately_drives_to_dead. CI will run now.

🤖 Heartbeat maintenance


Generated by Claude Code

)

tmux new-session returns 0 as long as the child shell + command launched.
If the in-pane command exits immediately (bad flag, auth error, missing
binary, etc.) the detached session reaps itself silently and the state
machine ends up CONNECTED against nothing, queuing messages forever.

Adds a ~150ms window + has_session() check after new_session() succeeds
in _spawn_tmux_repl(). A dead session at that point raises RuntimeError
so the existing BOOTING → DEAD via BOOT_FAILED transition fires correctly.
The delay is tunable via _SPAWN_LIVENESS_DELAY_SEC (patched to 0 in tests).

Also updates _make_mock_tmux() to return True for post-spawn liveness
checks while keeping the pre-spawn stale-detection call returning
has_session_initial (uses itertools.chain for precise call sequencing).

95 tmux_session tests pass; 208 across the tmux/agent_status/transport suite.

Closes #513.
@bradbrok
bradbrok force-pushed the fix/tmux-spawn-liveness-check branch from 8a65331 to 9be6412 Compare May 31, 2026 14:13

Copy link
Copy Markdown
Owner Author

Heartbeat maintenance (2026-05-31): rebased onto current main (ec39201 — 9 commits since last heartbeat rebase on 8978dfb, including isolation_mode/provisioning seam, per-agent signing key fix, CommandRunner/UnixUserProvisioner, live token analytics, and ultracode effort tier). Rebased cleanly — no conflicts in tmux_session.py or test_tmux_session.py. Force-pushed to fix/tmux-spawn-liveness-check.

Tests: 332 passed (test_tmux_session + test_tmux_transcript + test_transport_state), including test_cold_start_session_dies_immediately_drives_to_dead. CI will run now.

🤖 Heartbeat maintenance


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tmux transport: verify session liveness after new-session returns (defense for cold-start class)

2 participants