diff --git a/packages/loopover-miner/lib/attempt-cli.ts b/packages/loopover-miner/lib/attempt-cli.ts index 6dc4335ec..6c173bacc 100644 --- a/packages/loopover-miner/lib/attempt-cli.ts +++ b/packages/loopover-miner/lib/attempt-cli.ts @@ -1073,11 +1073,14 @@ export async function runAttempt(args: string[], options: RunAttemptOptions = {} } options.onResult?.(finalResult as AttemptCliResult); + // Terminal attempt outcome exit codes: submitted=0, abandon=7, stale=8, blocked=9, governed=10, verification_failed=12. switch (result.outcome) { case "submitted": return 0; case "abandon": return 7; + case "verification_failed": + return 12; case "stale": return 8; case "blocked": diff --git a/packages/loopover-miner/lib/attempt-runner.ts b/packages/loopover-miner/lib/attempt-runner.ts index 76bec8231..c58d56593 100644 --- a/packages/loopover-miner/lib/attempt-runner.ts +++ b/packages/loopover-miner/lib/attempt-runner.ts @@ -29,8 +29,9 @@ import type { import { prepareOpenPrSubmission } from "./harness-submission-trigger.js"; import { captureMinerError } from "./sentry.js"; -export const ATTEMPT_OUTCOMES: readonly ["abandon", "stale", "blocked", "governed", "submitted"] = Object.freeze([ +export const ATTEMPT_OUTCOMES: readonly ["abandon", "verification_failed", "stale", "blocked", "governed", "submitted"] = Object.freeze([ "abandon", + "verification_failed", "stale", "blocked", "governed", diff --git a/test/unit/miner-attempt-cli.test.ts b/test/unit/miner-attempt-cli.test.ts index f1b9d5975..38520fc42 100644 --- a/test/unit/miner-attempt-cli.test.ts +++ b/test/unit/miner-attempt-cli.test.ts @@ -1586,6 +1586,26 @@ describe("runAttempt (#5132)", () => { expect(String(error.mock.calls[0]?.[0])).toContain("target_not_found"); }); + it("REGRESSION (#10337): verification_failed has the dedicated exit code 12", async () => { + const { allocator, claimLedger, eventLedger, attemptLog, governorLedger } = tempLedgers(); + vi.spyOn(console, "log").mockImplementation(() => undefined); + + const exitCode = await runAttempt(["acme/widgets", "7", "--miner-login", "alice", "--json"], { + env: { MINER_CODING_AGENT_PROVIDER: "noop" }, + openWorktreeAllocator: () => allocator, + openClaimLedger: () => claimLedger, + initEventLedger: () => eventLedger, + initAttemptLog: () => attemptLog, + initGovernorLedger: () => governorLedger, + ...readyPipelineOptions({ + runMinerAttempt: async () => + ({ outcome: "verification_failed", verification: { status: "failed" }, loopResult: fakeLoopResult() }) as never, + }), + }); + + expect(exitCode).toBe(12); + }); + it("REGRESSION: an unexpected runMinerAttempt outcome falls through to exit 2", async () => { const { allocator, claimLedger, eventLedger, attemptLog, governorLedger } = tempLedgers(); vi.spyOn(console, "log").mockImplementation(() => undefined);