fix(recovery): use normal lane for missing-comment retries

Missing-comment retries may need to complete deliverable work such as routine document updates. Scrub status-only recovery guards from both the queued run and wake payload while preserving the write gate for true status-only recovery.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Lourenco Castro 2026-09-11 14:19:48 +02:00
parent 932c8bec56
commit 17223a9b25
2 changed files with 27 additions and 6 deletions

View File

@ -3211,7 +3211,16 @@ describeEmbeddedPostgres("heartbeat comment wake batching", () => {
expect(runs[1]?.contextSnapshot).toMatchObject({
retryReason: "missing_issue_comment",
});
expect(runs[1]?.contextSnapshot).not.toHaveProperty("modelProfile");
for (const key of [
"modelProfile",
"paperclipModelProfile",
"recoveryIntent",
"allowDeliverableWork",
"allowDocumentUpdates",
"resumeRequiresNormalModel",
]) {
expect(runs[1]?.contextSnapshot).not.toHaveProperty(key);
}
} finally {
gateway.releaseFirstWait();
await gateway.close();
@ -3416,9 +3425,19 @@ describeEmbeddedPostgres("heartbeat comment wake batching", () => {
),
);
expect(missingCommentRetries).toHaveLength(1);
expect(missingCommentRetries[0]?.payload).not.toHaveProperty(
"modelProfile",
);
expect(missingCommentRetries[0]?.payload).toMatchObject({
retryReason: "missing_issue_comment",
});
for (const key of [
"modelProfile",
"paperclipModelProfile",
"recoveryIntent",
"allowDeliverableWork",
"allowDocumentUpdates",
"resumeRequiresNormalModel",
]) {
expect(missingCommentRetries[0]?.payload).not.toHaveProperty(key);
}
} finally {
gateway.releaseFirstWait();
await gateway.close();

View File

@ -13388,6 +13388,8 @@ export function heartbeatService(
const contextSnapshot = parseObject(run.contextSnapshot);
const taskKey = deriveTaskKeyWithHeartbeatFallback(contextSnapshot, null);
const sessionBefore = await resolveSessionBeforeForWakeup(agent, taskKey);
// Missing-comment retries continue the original deliverable work, so they
// must not inherit the status-only mutation guards.
const retryContextSnapshot = withRecoveryContext(
{
...contextSnapshot,
@ -13396,7 +13398,7 @@ export function heartbeatService(
retryReason: "missing_issue_comment",
missingIssueCommentForRunId: run.id,
},
"status_only",
"normal_model",
);
const responsibleUserId = await resolveResponsibleUserIdForRunContext(
run,
@ -13435,7 +13437,7 @@ export function heartbeatService(
retryOfRunId: run.id,
retryReason: "missing_issue_comment",
},
"status_only",
"normal_model",
),
status: "queued",
requestedByActorType: "system",