diff --git a/apps/server/src/orchestration-v2/ThreadSettlementService.test.ts b/apps/server/src/orchestration-v2/ThreadSettlementService.test.ts index cbca5b3066d8..aa1032642091 100644 --- a/apps/server/src/orchestration-v2/ThreadSettlementService.test.ts +++ b/apps/server/src/orchestration-v2/ThreadSettlementService.test.ts @@ -130,13 +130,36 @@ describe("isAutoSettlementCandidate", () => { snoozedAt: at(-60 * 60 * 1_000), }); expect(isAutoSettlementCandidate(snoozed, NOW_MS)).toBe(false); - expect(isAutoSettlementCandidate(shell({ ...snoozed, status: "failed" }), NOW_MS)).toBe(true); + expect( + isAutoSettlementCandidate( + shell({ ...snoozed, status: "failed", latestRunCompletedAt: at(-30 * 60 * 1_000) }), + NOW_MS, + ), + ).toBe(true); expect( isAutoSettlementCandidate( shell({ ...snoozed, latestRunCompletedAt: at(-30 * 60 * 1_000) }), NOW_MS, ), ).toBe(true); + expect( + isAutoSettlementCandidate( + shell({ ...snoozed, status: "failed", latestRunCompletedAt: at(-2 * 60 * 60 * 1_000) }), + NOW_MS, + ), + ).toBe(false); + expect( + isAutoSettlementCandidate( + shell({ ...snoozed, status: "failed", latestRunCompletedAt: snoozed.snoozedAt }), + NOW_MS, + ), + ).toBe(false); + expect( + isAutoSettlementCandidate( + shell({ ...snoozed, status: "failed", latestRunCompletedAt: null }), + NOW_MS, + ), + ).toBe(false); // Expired snooze is no longer a park. expect(isAutoSettlementCandidate(shell({ ...snoozed, snoozedUntil: at(-1) }), NOW_MS)).toBe( true, diff --git a/apps/server/src/orchestration-v2/ThreadSettlementService.ts b/apps/server/src/orchestration-v2/ThreadSettlementService.ts index ebe13f0d2b5f..5222fd2a72aa 100644 --- a/apps/server/src/orchestration-v2/ThreadSettlementService.ts +++ b/apps/server/src/orchestration-v2/ThreadSettlementService.ts @@ -112,7 +112,9 @@ export function isAutoSettlementCandidate( // one still parked on its wake time keeps its stronger statement. const snoozedAtMs = toMillis(thread.snoozedAt); const completedAtMs = toMillis(thread.latestRunCompletedAt); - const wokeOnError = thread.status === "failed"; + const wokeOnError = + thread.status === "failed" && + (snoozedAtMs === null || (completedAtMs !== null && completedAtMs > snoozedAtMs)); const wokeOnCompletion = snoozedAtMs !== null && completedAtMs !== null && completedAtMs > snoozedAtMs; return wokeOnError || wokeOnCompletion;