mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-20 15:09:57 +02:00
46 lines
2.9 KiB
TypeScript
46 lines
2.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { executionFailureRetryCount } from "./execution-recovery-attempt.js";
|
|
|
|
describe("failure attempts across resource waits", () => {
|
|
it("preserves prior failures through subscription waits without trusting unrelated context", () => {
|
|
expect(executionFailureRetryCount({ scheduledRetryReason: "ai_connection_busy", scheduledRetryAttempt: 12,
|
|
contextSnapshot: { failureRetriesBeforeAiConnectionWait: 1 } })).toBe(1);
|
|
expect(executionFailureRetryCount({ scheduledRetryReason: "transient_failure", scheduledRetryAttempt: 2,
|
|
contextSnapshot: { failureRetriesBeforeAiConnectionWait: 0 } })).toBe(2);
|
|
for (const count of [undefined, -1, 1.5, "0"]) {
|
|
expect(executionFailureRetryCount({ scheduledRetryReason: "ai_connection_busy", scheduledRetryAttempt: 4,
|
|
contextSnapshot: { failureRetriesBeforeAiConnectionWait: count } })).toBe(4);
|
|
}
|
|
});
|
|
it("preserves prior failures through repeated workspace waits", () => {
|
|
expect(executionFailureRetryCount({ scheduledRetryReason: "workspace_busy", scheduledRetryAttempt: 12,
|
|
contextSnapshot: { failureRetriesBeforeWorkspaceWait: 1 } })).toBe(1);
|
|
});
|
|
it("does not trust a caller-supplied count outside a server-created workspace retry", () => {
|
|
expect(executionFailureRetryCount({ scheduledRetryReason: "transient_failure", scheduledRetryAttempt: 2,
|
|
contextSnapshot: { failureRetriesBeforeWorkspaceWait: 0 } })).toBe(2);
|
|
});
|
|
it("keeps ambiguous historical counts without treating a historical productive count as failures", () => {
|
|
expect(executionFailureRetryCount({ scheduledRetryReason: "workspace_busy", scheduledRetryAttempt: 4 })).toBe(4);
|
|
expect(executionFailureRetryCount({ scheduledRetryReason: "max_turns_continuation", scheduledRetryAttempt: 4 })).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("persisted independent accounting", () => {
|
|
it.each(["computer_admission_wait", "max_turns_continuation", "issue_disposition_repair", "workspace_busy", "ai_connection_busy", "ai_connection_pool_wait"])("%s cannot erase prior infrastructure debits or spend more", scheduledRetryReason => {
|
|
expect(executionFailureRetryCount({ scheduledRetryReason, scheduledRetryAttempt: 20,
|
|
contextSnapshot: { executionRetryAccounting: { version: 1, failureRetries: 2, maxTurnContinuations: 1 } },
|
|
})).toBe(2);
|
|
});
|
|
it("never lowers the current failure count from a partial or stale ledger", () => {
|
|
for (const executionRetryAccounting of [
|
|
{ version: 1, failureRetries: 0, maxTurnContinuations: 1 },
|
|
{ version: 1, failureRetries: -1, maxTurnContinuations: 1 },
|
|
{ version: 1, failureRetries: "0", maxTurnContinuations: 1 },
|
|
{ version: 2, failureRetries: 0, maxTurnContinuations: 1 },
|
|
]) expect(executionFailureRetryCount({ scheduledRetryReason: "transient_failure", scheduledRetryAttempt: 2,
|
|
contextSnapshot: { executionRetryAccounting },
|
|
})).toBe(2);
|
|
});
|
|
});
|