From 89770ba707fb1ebd4cabd184eec2e7fee226e0c3 Mon Sep 17 00:00:00 2001 From: Devin Foley Date: Mon, 12 Oct 2026 17:52:51 -0700 Subject: [PATCH] test(recovery): retain terminal-task native owner verification holds Co-Authored-By: Paperclip --- server/src/__tests__/heartbeat-process-recovery.test.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/server/src/__tests__/heartbeat-process-recovery.test.ts b/server/src/__tests__/heartbeat-process-recovery.test.ts index 3b2005cc961..b8648e94c50 100644 --- a/server/src/__tests__/heartbeat-process-recovery.test.ts +++ b/server/src/__tests__/heartbeat-process-recovery.test.ts @@ -2411,7 +2411,7 @@ describeEmbeddedPostgres("heartbeat orphaned process recovery", () => { .toMatchObject({ status: "active", resolvedAt: null }); }); - it("keeps existing terminal-task disposition for a native finalization hold", async () => { + it("retains the exact native owner hold without changing a terminal task's disposition", async () => { const f = await seedPendingNativeFinalization(); await db.update(heartbeatRuns).set({ runnerProfileJson: { nativeWorkspaceFinalizationOwner: { unknown: true } } }) .where(eq(heartbeatRuns.id, f.runId)); @@ -2419,6 +2419,13 @@ describeEmbeddedPostgres("heartbeat orphaned process recovery", () => { await heartbeat.recoverNativeRunsAfterRestart(); const [hold] = await db.select().from(issueRecoveryActions).where(eq(issueRecoveryActions.sourceIssueId, f.issueId)); await db.update(issues).set({ status: "done" }).where(eq(issues.id, f.issueId)); + for (let attempt = 0; attempt < 3; attempt += 1) { + await heartbeat.reconcileStrandedAssignedIssues(); + expect((await db.select().from(issueRecoveryActions).where(eq(issueRecoveryActions.id, hold.id)))[0]) + .toEqual(hold); + expect((await db.select().from(issues).where(eq(issues.id, f.issueId)))[0].status).toBe("done"); + } + await db.update(heartbeatRuns).set({ runnerProfileJson: {} }).where(eq(heartbeatRuns.id, f.runId)); await heartbeat.reconcileStrandedAssignedIssues(); expect((await db.select().from(issueRecoveryActions).where(eq(issueRecoveryActions.id, hold.id)))[0]) .toMatchObject({ status: "resolved", resolutionNote: "source_terminal" });