From 35c997bde035f48d670d20be435d82814c0f0ca0 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 19 Oct 2026 15:46:36 -0700 Subject: [PATCH 1/3] Stop Claude Code from retrying the mock's deliberate 400 Claude Code 2.1.304 retries the deterministic 400 returned by the Anthropic mock, so claude_session_emits_traces hits the mock's panic arm and times out. The harness set ANTHROPIC_MAX_RETRIES, which Claude Code never reads; it honors CLAUDE_CODE_MAX_RETRIES. The Anthropic mock now also sends x-should-retry: false on error replies. Co-Authored-By: Claude Opus 5.5 --- bt-daemon/tests/support/agents/claude.rs | 3 ++- bt-daemon/tests/support/inference/anthropic.rs | 6 +++--- bt-daemon/tests/support/inference/mod.rs | 5 +++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/bt-daemon/tests/support/agents/claude.rs b/bt-daemon/tests/support/agents/claude.rs index 15594f0f..4d8ef249 100644 --- a/bt-daemon/tests/support/agents/claude.rs +++ b/bt-daemon/tests/support/agents/claude.rs @@ -78,7 +78,8 @@ impl ClaudeAgent { ]) .arg(plugin) .current_dir(world.workspace()) - .env("ANTHROPIC_MAX_RETRIES", "0") + // Claude Code reads CLAUDE_CODE_MAX_RETRIES, not ANTHROPIC_MAX_RETRIES. + .env("CLAUDE_CODE_MAX_RETRIES", "0") .env("DISABLE_AUTOUPDATER", "1") .env("DISABLE_TELEMETRY", "1") .env("CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC", "1"); diff --git a/bt-daemon/tests/support/inference/anthropic.rs b/bt-daemon/tests/support/inference/anthropic.rs index 59662b1c..730a2b65 100644 --- a/bt-daemon/tests/support/inference/anthropic.rs +++ b/bt-daemon/tests/support/inference/anthropic.rs @@ -1,4 +1,4 @@ -use super::{decode_json_body, json_response, raw_response, sse, MockReply, RequestContext}; +use super::{decode_json_body, error_response, raw_response, sse, MockReply, RequestContext}; use axum::body::Bytes; use axum::extract::State; use axum::http::{HeaderMap, StatusCode}; @@ -228,7 +228,7 @@ async fn messages( ) -> axum::response::Response { let body = match decode_json_body(&headers, &body) { Ok(body) => body, - Err(error) => return json_response(StatusCode::BAD_REQUEST, json!({"error": error})), + Err(error) => return error_response(StatusCode::BAD_REQUEST, json!({"error": error})), }; let request = AnthropicRequest { body }; state @@ -248,7 +248,7 @@ async fn messages( "text/event-stream", sse(&turn.events(index)), ), - MockReply::HttpError { status, body } => json_response(status, body), + MockReply::HttpError { status, body } => error_response(status, body), MockReply::Raw { status, content_type, diff --git a/bt-daemon/tests/support/inference/mod.rs b/bt-daemon/tests/support/inference/mod.rs index 43390366..051c4950 100644 --- a/bt-daemon/tests/support/inference/mod.rs +++ b/bt-daemon/tests/support/inference/mod.rs @@ -67,6 +67,11 @@ fn json_response(status: StatusCode, body: Value) -> axum::response::Response { (status, axum::Json(body)).into_response() } +fn error_response(status: StatusCode, body: Value) -> axum::response::Response { + use axum::response::IntoResponse; + (status, [("x-should-retry", "false")], axum::Json(body)).into_response() +} + fn raw_response( status: StatusCode, content_type: &'static str, From 88ed68fda4bd3c4458b229dada2aced80fc5aa5c Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 19 Oct 2026 15:51:20 -0700 Subject: [PATCH 2/3] Drop retry env var comment Co-Authored-By: Claude Opus 5.5 --- bt-daemon/tests/support/agents/claude.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/bt-daemon/tests/support/agents/claude.rs b/bt-daemon/tests/support/agents/claude.rs index 4d8ef249..948cdba3 100644 --- a/bt-daemon/tests/support/agents/claude.rs +++ b/bt-daemon/tests/support/agents/claude.rs @@ -78,7 +78,6 @@ impl ClaudeAgent { ]) .arg(plugin) .current_dir(world.workspace()) - // Claude Code reads CLAUDE_CODE_MAX_RETRIES, not ANTHROPIC_MAX_RETRIES. .env("CLAUDE_CODE_MAX_RETRIES", "0") .env("DISABLE_AUTOUPDATER", "1") .env("DISABLE_TELEMETRY", "1") From 76560705d3b2315f4d2ef31e7c3494b4e7e91ca4 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 19 Oct 2026 16:15:41 -0700 Subject: [PATCH 3/3] Disable ToolSearch so Claude Code 2.1.304 does not resend the failed request After the deterministic 400, Claude Code 2.1.304 reissues the request with ToolSearch disabled. That fallback ignores CLAUDE_CODE_MAX_RETRIES. Start with ToolSearch off so the fallback never applies. Co-Authored-By: Claude Opus 5.5 --- bt-daemon/tests/support/agents/claude.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bt-daemon/tests/support/agents/claude.rs b/bt-daemon/tests/support/agents/claude.rs index 948cdba3..101c102b 100644 --- a/bt-daemon/tests/support/agents/claude.rs +++ b/bt-daemon/tests/support/agents/claude.rs @@ -79,6 +79,7 @@ impl ClaudeAgent { .arg(plugin) .current_dir(world.workspace()) .env("CLAUDE_CODE_MAX_RETRIES", "0") + .env("ENABLE_TOOL_SEARCH", "false") .env("DISABLE_AUTOUPDATER", "1") .env("DISABLE_TELEMETRY", "1") .env("CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC", "1");