From f6fb2fe63ffa28ab5d324eb0c0ea7115da710e7f Mon Sep 17 00:00:00 2001 From: jedarden Date: Thu, 25 Jun 2026 15:34:41 -0400 Subject: [PATCH] fix(bf-2f5): overall max-turn timeout now applies throughout entire session MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the overall timeout only applied before prompt injection. This change makes it apply throughout the entire session, preventing indefinite polling of stop.fifo regardless of when the child wedges. The overall timeout ensures claude-print exits non-zero (exit code 124) with proper SIGTERM→SIGKILL cleanup, clear diagnostics, and temp resource teardown even if the child hangs during tool use or model inference. Co-Authored-By: Claude --- src/watchdog.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/watchdog.rs b/src/watchdog.rs index 66291a8..5fe3888 100644 --- a/src/watchdog.rs +++ b/src/watchdog.rs @@ -3,11 +3,13 @@ //! This module implements a comprehensive watchdog that monitors: //! - Stream-json output from the transcript file //! - PTY output for first-output detection -//! - Overall session duration +//! - Overall session duration (max-turn timeout, applies throughout entire session) //! - Stop hook execution //! //! The watchdog ensures that hung child processes are terminated with -//! proper cleanup (SIGTERM → SIGKILL) and clear diagnostics. +//! proper cleanup (SIGTERM → SIGKILL) and clear diagnostics. The overall +//! timeout prevents indefinite polling of stop.fifo by killing the child +//! and exiting non-zero regardless of why the child wedged. use std::path::PathBuf; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; @@ -49,7 +51,7 @@ impl TimeoutType { match self { Self::PtyFirstOutput => "child produced no PTY output within deadline (process may be hung at startup)", Self::StreamJsonFirstOutput => "child produced no stream-json output within deadline (process may be hung during session initialization)", - Self::OverallTimeout => "session exceeded overall time deadline", + Self::OverallTimeout => "session exceeded overall max-turn deadline (max-turn timeout applies throughout entire session)", Self::StopHookTimeout => "Stop hook did not fire within deadline after prompt injection (child may have hung during tool use or model inference)", } } @@ -316,8 +318,8 @@ impl Watchdog { } } - // Check Phase 3: Overall timeout (only if configured and no prompt injected yet) - if config.overall_timeout_secs > 0 && prompt_injected.is_none() { + // Check Phase 3: Overall timeout (applies throughout entire session) + if config.overall_timeout_secs > 0 { if elapsed >= Duration::from_secs(config.overall_timeout_secs) { let _ = nix::sys::signal::kill(child_pid, nix::sys::signal::Signal::SIGTERM); timeout_fired.store(true, Ordering::SeqCst);