From 142fdf684702fc6c687abdbed5a82deef7428c08 Mon Sep 17 00:00:00 2001 From: Dotta Date: Sat, 10 Oct 2026 08:50:13 -0500 Subject: [PATCH] Classify prelaunch native artifact platform failures safely Co-Authored-By: Paperclip --- .../native-session-executor.test.ts | 32 +++++++++++++++++++ .../native-runtime/native-session-executor.ts | 6 ++++ 2 files changed, 38 insertions(+) diff --git a/server/src/services/native-runtime/native-session-executor.test.ts b/server/src/services/native-runtime/native-session-executor.test.ts index 5807a868630..4be78741d4a 100644 --- a/server/src/services/native-runtime/native-session-executor.test.ts +++ b/server/src/services/native-runtime/native-session-executor.test.ts @@ -331,6 +331,7 @@ import { retainedNativeCleanupJournalMatches, nativeProviderUsageLimitFromEvent, nativeSessionFailureSourceCode, + nativeProviderRecoveryEvidence, nativeSessionRecoveryProjection, nativeGovernedWaitResult, nativeConversationReplyResult, @@ -9338,6 +9339,37 @@ describe("native session bounded recovery", () => { ).toBe("native_current_wake_comments_changed_after_read"); }); + it.each([ + [{}, [], "bootstrap_retry"], + [{ uncertain: true }, [], "ambiguous_state"], + [{}, [{ eventType: "turn.started" }], "ambiguous_state"], + ])("classifies a platform mismatch without weakening persisted recovery evidence", async (checkpoint, events, mode) => { + const code = nativeSessionFailureSourceCode( + new Error("runner_remote_artifact_platform_mismatch: configure the remote binary"), + ); + expect(code).toBe("runner_remote_artifact_platform_mismatch"); + expect(nativeSessionFailureDisposition(1, new Date(), code)).toMatchObject({ + phase: "terminal_failure", + failureCode: code, + nextAttemptAt: null, + }); + let reads = 0; + const db = { + select: () => ({ + from: () => ({ + where: () => ({ + limit: async () => ++reads === 1 + ? [{ runnerProfileJson: { sessionCheckpoint: checkpoint } }] + : events, + }), + }), + }), + }; + expect(await nativeProviderRecoveryEvidence({ + db: db as never, runId: "run", sourceFailureCode: code, + })).toMatchObject({ recoveryMode: mode }); + }); + it("requires operator action without retrying an approval-required terminal", () => { const code = nativeSessionFailureSourceCode( new NativeProviderTerminalFailure("approval_required", false, "Approval required"), diff --git a/server/src/services/native-runtime/native-session-executor.ts b/server/src/services/native-runtime/native-session-executor.ts index d5155806671..bb20e10b71c 100644 --- a/server/src/services/native-runtime/native-session-executor.ts +++ b/server/src/services/native-runtime/native-session-executor.ts @@ -6243,6 +6243,7 @@ export function nativeSessionFailureDisposition( sourceFailureCode === "native_provider_approval_required" || sourceFailureCode === "native_event_replay_conflict" || sourceFailureCode === "runner_remote_provider_artifact_incompatible" || + sourceFailureCode === "runner_remote_artifact_platform_mismatch" || sourceFailureCode === "native_provider_terminal_failed" || sourceFailureCode === "native_current_wake_comments_unread" || sourceFailureCode === "native_current_wake_comments_changed_after_read" || @@ -6299,6 +6300,7 @@ export function nativeSessionFailureSourceCode( | "native_session_cleanup_quarantined" | "native_adopted_runner_authentication_timeout" | "runner_remote_provider_artifact_incompatible" + | "runner_remote_artifact_platform_mismatch" | "provider_process_exited" | "provider_stdout_closed" | "provider_process_output_closed" @@ -6339,6 +6341,9 @@ export function nativeSessionFailureSourceCode( if (/native_adopted_runner_authentication_timeout/i.test(message)) { return "native_adopted_runner_authentication_timeout"; } + if (/^runner_remote_artifact_platform_mismatch(?::|$)/.test(message)) { + return "runner_remote_artifact_platform_mismatch"; + } if (/runner_remote_provider_artifact_incompatible/i.test(message)) { return "runner_remote_provider_artifact_incompatible"; } @@ -6466,6 +6471,7 @@ export async function nativeProviderRecoveryEvidence(input: { ReturnType >([ "runner_remote_provider_artifact_incompatible", + "runner_remote_artifact_platform_mismatch", "provider_process_exited", "provider_stdout_closed", "provider_process_output_closed",