From 646795e8f9bf0c8845db9359cd226dcf1bc66e0a Mon Sep 17 00:00:00 2001 From: Dotta Date: Tue, 6 Oct 2026 10:03:49 -0500 Subject: [PATCH] Wait for the selected native response in live qualification Hydrate the final run receipt while polling persisted comments so an earlier deliverable-preparation comment cannot end the response consistency wait. Co-Authored-By: Paperclip --- tests/runner-e2e/matchers.ts | 5 ++++- tests/runner-e2e/runner.spec.ts | 19 +++++++++++++------ tests/runner-e2e/support.test.ts | 7 +++++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/tests/runner-e2e/matchers.ts b/tests/runner-e2e/matchers.ts index 173cfa6da65..b6b6287c366 100644 --- a/tests/runner-e2e/matchers.ts +++ b/tests/runner-e2e/matchers.ts @@ -172,7 +172,7 @@ export async function evaluateMatchers( export function persistedFinalRunMessage( comments: Array<{ id: string; createdByRunId?: string | null; body?: string | null }>, - run: { id: string; resultJson?: Record | null }, + run: { id: string; runtimeMode?: string; resultJson?: Record | null }, ): string { const runComments = comments.filter(comment => comment.createdByRunId === run.id); const decision = run.resultJson?.presentationDecision; @@ -183,5 +183,8 @@ export function persistedFinalRunMessage( if (typeof selectedId === "string") { return runComments.find(comment => comment.id === selectedId)?.body ?? ""; } + // Native finalization can publish a deliverable-preparation comment before + // its response decision. That earlier comment is not the selected reply. + if (run.runtimeMode === "native") return ""; return runComments.map(comment => comment.body ?? "").join("\n"); } diff --git a/tests/runner-e2e/runner.spec.ts b/tests/runner-e2e/runner.spec.ts index 2a017a32ec3..0c1fde9f4bf 100644 --- a/tests/runner-e2e/runner.spec.ts +++ b/tests/runner-e2e/runner.spec.ts @@ -1858,17 +1858,24 @@ for (const execution of executions) { terminal = await pollUntil({ label: `final agent comment for issue ${issue.id}`, deadlineAt: Math.min(deadlineAt, Date.now() + 30_000), - load: loadTaskState, + load: async () => { + const state = await loadTaskState(); + const finalRun = sortRunsChronologically(state.taskRuns).at(-1); + if (!finalRun) return state; + // The compact run list omits the native presentation receipt. + // Poll its public detail together with comments so an earlier + // deliverable-preparation comment cannot settle this wait. + const detailed = await api.get(`/api/heartbeat-runs/${finalRun.id}`); + return { ...state, taskRuns: state.taskRuns.map(run => run.id === detailed.id ? detailed : run) }; + }, accept: ({ taskRuns, comments }) => { if (!matchesRunCount(execution.task, taskRuns.length)) { return false; } const finalRun = sortRunsChronologically(taskRuns).at(-1); - return comments.some( - (comment) => - comment.createdByRunId === finalRun?.id && - comment.authorAgentId === fixtures!.agent.id, - ); + return Boolean(finalRun && persistedFinalRunMessage( + comments.filter(comment => comment.authorAgentId === fixtures!.agent.id), finalRun, + ).trim()); }, reject: ({ taskRuns }) => definitiveRunFailure(taskRuns), }).catch(() => terminal); diff --git a/tests/runner-e2e/support.test.ts b/tests/runner-e2e/support.test.ts index 85edfeab0a7..2dd5d269399 100644 --- a/tests/runner-e2e/support.test.ts +++ b/tests/runner-e2e/support.test.ts @@ -1431,6 +1431,13 @@ describe("persisted final response selection", () => { expect(persistedFinalRunMessage(comments.slice(0, 1), run)).toBe(""); expect(persistedFinalRunMessage(comments, { ...run, resultJson: { presentationDecision: { commentId: "other-run" } } })).toBe(""); }); + it("waits for the native response receipt and its selected comment, not an earlier attachment comment", () => { + const native = { ...run, runtimeMode: "native" }; + expect(persistedFinalRunMessage(comments.slice(0, 1), { id: native.id, runtimeMode: "native" })).toBe(""); + expect(persistedFinalRunMessage(comments, { id: native.id, runtimeMode: "native", resultJson: { summary: "FINAL" } })).toBe(""); + expect(persistedFinalRunMessage(comments.slice(0, 1), native)).toBe(""); + expect(persistedFinalRunMessage(comments, native)).toBe("FINAL"); + }); it("keeps legacy fallback and does not replace absent visible text with a summary", () => { expect(persistedFinalRunMessage(comments, { id: "run-1" })).toBe("Prepared file for this response.\nFINAL"); expect(persistedFinalRunMessage([], { id: "run-1", resultJson: { summary: "FINAL" } })).toBe("");