From 31b2fd50d54779b9ea89f3ea1e3066d1bde7e1ba Mon Sep 17 00:00:00 2001 From: Dotta Date: Fri, 11 Sep 2026 17:08:40 -0500 Subject: [PATCH] test(campaign): prioritize explicit no-retry errors over cleanup noise Co-Authored-By: Paperclip --- tests/runner-e2e/failure-classifier.ts | 4 +++- tests/runner-e2e/support.test.ts | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/runner-e2e/failure-classifier.ts b/tests/runner-e2e/failure-classifier.ts index c480b1e9dd..66d9d791e8 100644 --- a/tests/runner-e2e/failure-classifier.ts +++ b/tests/runner-e2e/failure-classifier.ts @@ -3,7 +3,7 @@ import type { FailureClass } from "./types.js"; const TRANSIENT = /(?:\b429\b|\b5\d\d\b|rate.?limit|ECONN(?:RESET|REFUSED)|socket hang up|network (?:error|interruption|timeout)|service unavailable|(?:provider|server|bootstrap|browser|webserver|health|daytona|sandbox|ingress|preview|connection|harness).*(?:temporar|timed? out|timeout|closed|failed|unavailable|interrupt|reset|refused|create|start|connect)|(?:timed? out|timeout).*(?:provider|server|bootstrap|browser|webserver|health|daytona|sandbox|ingress|preview|connection|harness))/i; const PERMANENT = - /(?:retryable=false|effective_model_mismatch|missing (?:credential|fixture secret)|invalid.*(?:credential|api key)|unauthorized|forbidden|qualification|model.*(?:unsupported|incompatible)|artifact.*incompatible|runner_remote_.*(?:incompatible|unavailable)|immutable image digest)/i; + /(?:missing (?:credential|fixture secret)|invalid.*(?:credential|api key)|unauthorized|forbidden|qualification|model.*(?:unsupported|incompatible)|artifact.*incompatible|runner_remote_.*(?:incompatible|unavailable)|immutable image digest)/i; const CANDIDATE = /(?:matcher|expected.*observed|marker|issue status|run status|runtime mode|wrong output|missing output)/i; @@ -14,6 +14,8 @@ export function classifyFailure(error: unknown): FailureClass { return "transient_infrastructure"; if (/secret.*(?:leak|plaintext|redaction)/i.test(message)) return "secret_leak"; + if (/retryable=false|effective_model_mismatch/i.test(message)) + return "permanent_infrastructure"; if (/cleanup|teardown|lease.*release/i.test(message)) { return TRANSIENT.test(message) ? "transient_infrastructure" diff --git a/tests/runner-e2e/support.test.ts b/tests/runner-e2e/support.test.ts index fed018a617..32c94bac3d 100644 --- a/tests/runner-e2e/support.test.ts +++ b/tests/runner-e2e/support.test.ts @@ -738,9 +738,9 @@ describe("runner E2E failure policy", () => { }); describe("runner E2E server isolation", () => { - it("does not retry a provider rejection explicitly marked nonretryable", () => { + it.each(["", "; cleanup: provider failed to start"])("does not retry an explicitly nonretryable provider rejection%s", (suffix) => { const failure = classifyFailure(new Error( - "failed to start ACPX provider: ACPX sidecar command session.open was rejected (retryable=false, classification=effective_model_mismatch)", + "failed to start ACPX provider: ACPX sidecar command session.open was rejected (retryable=false, classification=effective_model_mismatch)" + suffix, )); expect(failure).toBe("permanent_infrastructure"); expect(shouldRetryFailure(failure)).toBe(false);