From 14a04507c61f7256fdfaa373b49ef019a1ced157 Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Sat, 15 Aug 2026 02:22:46 +0800 Subject: [PATCH] fix: keep managed runs fail-open when nothing was traced MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `run_traced` bailed when a managed run flushed zero accepted sessions, which discarded the wrapped agent's `ExitStatus` and turned a successful agent into a failed `bt trace run`. Tracing is fail-open everywhere else in this repo — hooks are thin fail-open launchers, and a flush that times out or fails outright only warns — so a flush that succeeds and honestly reports nothing should not be the one fatal case. Zero accepted sessions now logs at warn like its siblings and the child's exit status is returned unchanged. Legitimate zero-event runs exist: `bt trace run codex -- --version` never opens a session, and Ctrl-C before the first turn reaches the same flush. The message stays a `tracing` diagnostic rather than going to stderr. A managed run wraps an interactive agent, so the integration should record what it could not trace without printing into that agent's terminal. Extends the managed-run exit-status test with an agent that emits no hook events at all, asserting that both a success and a failure pass through untouched. That test fails against the previous behavior. Co-Authored-By: Claude Opus 5 (1M context) --- bt-daemon/src/lib.rs | 9 ++++----- bt-daemon/tests/pipeline.rs | 25 ++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/bt-daemon/src/lib.rs b/bt-daemon/src/lib.rs index 3fadfc9..8e3fa52 100644 --- a/bt-daemon/src/lib.rs +++ b/bt-daemon/src/lib.rs @@ -516,11 +516,10 @@ pub async fn run_traced( }; let socket = paths::socket_path(None); match flush_managed_run(&managed_run_id, &socket, MANAGED_RUN_FLUSH_TIMEOUT_MS).await { - Ok(result) if result.accepted_sessions == 0 => { - anyhow::bail!( - "managed run produced no accepted trace events; verify hook output and `bt trace status`" - ) - } + Ok(result) if result.accepted_sessions == 0 => tracing::warn!( + managed_run_id, + "managed run produced no accepted trace events" + ), Ok(result) if result.flushed => {} Ok(result) => tracing::warn!( managed_run_id, diff --git a/bt-daemon/tests/pipeline.rs b/bt-daemon/tests/pipeline.rs index 183b00f..e4a4cd2 100644 --- a/bt-daemon/tests/pipeline.rs +++ b/bt-daemon/tests/pipeline.rs @@ -1064,7 +1064,7 @@ impl Drop for EnvVarGuard { #[cfg(all(feature = "cli", unix))] #[tokio::test] -async fn managed_run_flushes_after_success_failure_and_signal_exit() { +async fn managed_run_flushes_and_preserves_agent_exit_status() { use std::os::unix::fs::PermissionsExt; let version = env!("CARGO_PKG_VERSION"); @@ -1081,12 +1081,19 @@ for argument in "$@"; do done session_id=$previous mode=$last -printf '{"session_id":"%s","hook_event_name":"SessionStart"}\n' "$session_id" | - "$BT_DAEMON_TEST_BIN" hook --source debug --managed-run-hook --no-spawn +case "$mode" in + untraced-success|untraced-failure) ;; + *) + printf '{"session_id":"%s","hook_event_name":"SessionStart"}\n' "$session_id" | + "$BT_DAEMON_TEST_BIN" hook --source debug --managed-run-hook --no-spawn + ;; +esac case "$mode" in success) exit 0 ;; failure) exit 7 ;; signal) kill -TERM "$$" ;; + untraced-success) exit 0 ;; + untraced-failure) exit 7 ;; *) exit 99 ;; esac "#, @@ -1127,6 +1134,18 @@ esac assert!(!signal_status.success()); assert_eq!(signal_status.code(), None); + assert!(run("managed-untraced", "untraced-success") + .await + .unwrap() + .success()); + assert_eq!( + run("managed-untraced", "untraced-failure") + .await + .unwrap() + .code(), + Some(7) + ); + assert_eq!( *flushes.lock().unwrap(), HashMap::from([