Skip to content

fix: keep managed runs fail-open when nothing was traced - #22

Merged
Stephen Belanger (Qard) merged 1 commit into
mainfrom
fix/managed-run-fail-open
Aug 14, 2026
Merged

fix: keep managed runs fail-open when nothing was traced#22
Stephen Belanger (Qard) merged 1 commit into
mainfrom
fix/managed-run-fail-open

Conversation

@Qard

@Qard Stephen Belanger (Qard) commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

run_traced bails when a managed run flushes zero accepted sessions:

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; ...")
    }
    Ok(result) if result.flushed => {}
    Ok(result) => tracing::warn!(/* flush timed out */),
    Err(error) => tracing::warn!(/* flush failed */),
}
status

That bail! means status is never returned, so the wrapped agent's ExitStatus is discarded. A bt trace run whose agent succeeded exits non-zero whenever tracing happened to record nothing. In trace_runtime.rs the Run arm does run_traced(...).await? and only then checks status.success(), so the ? swallows a perfectly good run before its status is ever examined.

It's also inconsistent with its own neighbors: a flush that times out or fails outright only warns, while a flush that succeeds and honestly reports nothing is the single fatal case. That inverts the severity, and it cuts against the fail-open design this repo states for tracing ("Plugin hooks are thin fail-open shell launchers").

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.

Change

Zero accepted sessions now logs at warn like its siblings, and the child's exit status is returned unchanged. All four arms are consistent: record what could not be traced, then fall through to the child's own outcome.

It stays a tracing diagnostic rather than going to stderr. A managed run wraps an interactive agent, and the integration should stay out of that agent's terminal — this is debug information for whoever is diagnosing the daemon, not guidance the user needs mid-session.

Worth noting separately: when this runtime is embedded in bt, none of these warnings are visible, because bt never installs a tracing subscriber outside the daemon command (init_daemon_logging is only called from the Daemon arm). That is pre-existing and applies equally to the two existing arms, so it is out of scope here — but if we want managed-run diagnostics to be reachable under bt, the fix is a subscriber on bt's side, not stderr writes from this crate.

Testing

managed_run_flushes_after_success_failure_and_signal_exit already asserted that success, failure, and signal statuses pass through — it only passed because its fake agent emits a SessionStart hook. Renamed to managed_run_flushes_and_preserves_agent_exit_status and extended with untraced-success / untraced-failure modes whose agent emits no hook event at all, asserting both an exit 0 and an exit 7 survive untouched.

Verified the new test fails against the previous behavior:

called `Result::unwrap()` on an `Err` value: managed run produced no accepted
trace events; verify hook output and `bt trace status`

Full suite passes (cargo test --manifest-path bt-daemon/Cargo.toml --all-features), cargo fmt --check and clippy clean.

Context

Found while bumping bt's pin to latest main (braintrustdata/bt#314). The bail arrived in 1f52bb0 (#21) alongside the managed-run acceptance accounting; that commit's message describes the persistence and RouteRequirements work but doesn't mention making zero-accepted fatal, and the line had no test or doc coverage.

🤖 Generated with Claude Code

`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) <noreply@anthropic.com>
@Qard
Stephen Belanger (Qard) merged commit 1ca65d4 into main Aug 14, 2026
20 checks passed
@Qard
Stephen Belanger (Qard) deleted the fix/managed-run-fail-open branch August 14, 2026 19:49
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.

3 participants