diff --git a/server/src/services/recovery/service.ts b/server/src/services/recovery/service.ts index 05e7d6edaf5..bd0b3db3e23 100644 --- a/server/src/services/recovery/service.ts +++ b/server/src/services/recovery/service.ts @@ -40,6 +40,7 @@ import { FINISH_SUCCESSFUL_RUN_HANDOFF_REASON, SUCCESSFUL_RUN_MISSING_STATE_REASON, buildSuccessfulRunHandoffExhaustedNotice, + noticeMetadataReferencesRecoveryAction, type SuccessfulRunHandoffNotice, } from "./successful-run-handoff.js"; import { @@ -1846,7 +1847,7 @@ export function recoveryService(db: Db, deps: { enqueueWakeup: RecoveryWakeup }) const escalationCommentMarker = `Recovery action: \`${recoveryAction.id}\``; const hasEscalationComment = await db - .select({ id: issueComments.id, body: issueComments.body }) + .select({ id: issueComments.id, body: issueComments.body, metadata: issueComments.metadata }) .from(issueComments) .where( and( @@ -1856,7 +1857,10 @@ export function recoveryService(db: Db, deps: { enqueueWakeup: RecoveryWakeup }) ) .orderBy(desc(issueComments.createdAt)) .limit(50) - .then((rows) => rows.some((row) => (row.body ?? "").includes(escalationCommentMarker))); + .then((rows) => rows.some((row) => + (row.body ?? "").includes(escalationCommentMarker) || + noticeMetadataReferencesRecoveryAction(row.metadata, recoveryAction.id), + )); if (!hasEscalationComment) { if (notice) { diff --git a/server/src/services/recovery/successful-run-handoff.test.ts b/server/src/services/recovery/successful-run-handoff.test.ts index d2848ae73d8..d11aaff5112 100644 --- a/server/src/services/recovery/successful-run-handoff.test.ts +++ b/server/src/services/recovery/successful-run-handoff.test.ts @@ -10,6 +10,7 @@ import { decideSuccessfulRunHandoff, isIdempotentFinishSuccessfulRunHandoffWakeStatus, isSuccessfulRunHandoffRequiredNoticeBody, + noticeMetadataReferencesRecoveryAction, } from "./successful-run-handoff.js"; const run = { @@ -287,6 +288,8 @@ describe("successful run handoff decision", () => { ]), }), ])); + expect(noticeMetadataReferencesRecoveryAction(notice.metadata, "77777777-7777-4777-8777-777777777777")).toBe(true); + expect(noticeMetadataReferencesRecoveryAction(notice.metadata, "88888888-8888-4888-8888-888888888888")).toBe(false); }); it("recognizes new notices and legacy markdown headings for fallback deduplication", () => { diff --git a/server/src/services/recovery/successful-run-handoff.ts b/server/src/services/recovery/successful-run-handoff.ts index 3a9c07a76ce..53ec9b64280 100644 --- a/server/src/services/recovery/successful-run-handoff.ts +++ b/server/src/services/recovery/successful-run-handoff.ts @@ -61,6 +61,19 @@ export type SuccessfulRunHandoffNotice = { metadata: IssueCommentMetadata; }; +export function noticeMetadataReferencesRecoveryAction( + metadata: IssueCommentMetadata | null | undefined, + recoveryActionId: string, +) { + return (metadata?.sections ?? []).some((section) => + section.rows.some((row) => + row.type === "key_value" && + row.label === "Recovery action" && + row.value === recoveryActionId, + ), + ); +} + export type SuccessfulRunHandoffDecision = | { kind: "enqueue";