From 2d89146adcbde171b44b7709e299c2105741d40d Mon Sep 17 00:00:00 2001 From: Dotta Date: Wed, 21 Oct 2026 11:39:24 -0500 Subject: [PATCH] test: identify active Stop boundary from durable provider events --- tests/runner-e2e/followup-stop-resume-flow.ts | 6 +++--- tests/runner-e2e/followup-stop-resume.test.ts | 16 +++++++++++----- tests/runner-e2e/followup-stop-resume.ts | 8 ++++++-- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/tests/runner-e2e/followup-stop-resume-flow.ts b/tests/runner-e2e/followup-stop-resume-flow.ts index 130f8511f83..ded01e0d1d5 100644 --- a/tests/runner-e2e/followup-stop-resume-flow.ts +++ b/tests/runner-e2e/followup-stop-resume-flow.ts @@ -86,9 +86,9 @@ export async function runFollowupStopResumeFlow(input: { load: async () => { await refresh(); const run = runs[0]; - if (runs.length !== 1 || !isActiveStopCheckpointRun(run)) return false; + if (runs.length !== 1 || !run || run.status !== "running") return false; const events = prpEvents(await runEvents(run.id), run.id); - if (!events.some(event => event.eventType === "turn.started" && event.sourceKind === "runner") || events.some(event => event.eventType === "run.result.accepted")) return false; + if (!isActiveStopCheckpointRun(run, events)) return false; const checkpoint = await readRegisteredArtifacts(api, issue!.id, run.id, [files.checkpoint]) .then(([artifact]) => artifact).catch(error => { if (error instanceof RegisteredArtifactNotFoundError) return null; @@ -111,7 +111,7 @@ export async function runFollowupStopResumeFlow(input: { observation.followup = { commentIds: followup.commentIds, runId: active.id, runStatus: active.status, acceptedResults: activeEvents.filter(event => event.eventType === "run.result.accepted").length, providerStarted: activeEvents.some(event => event.eventType === "turn.started"), observedAt: new Date().toISOString() }; - if (runs.length !== 1 || active.status !== "running" || observation.followup.acceptedResults !== 0) + if (runs.length !== 1 || !isActiveStopCheckpointRun(active, activeEvents)) throw new Error("Follow-up was not recorded before the original active Stop boundary"); await persist("followup-during-work"); await input.capture("before-stop", "Follow-up persisted during original active work", "before-stop.png"); diff --git a/tests/runner-e2e/followup-stop-resume.test.ts b/tests/runner-e2e/followup-stop-resume.test.ts index 7fa8063fe8a..bc1975989f1 100644 --- a/tests/runner-e2e/followup-stop-resume.test.ts +++ b/tests/runner-e2e/followup-stop-resume.test.ts @@ -66,9 +66,15 @@ describe("one task across follow-up, Stop and explicit resumption", () => { }); }); -it("recognizes the production active-provider phase before checkpoint publication", () => { - expect(isActiveStopCheckpointRun({ status: "running", nativePhase: "provider_running" })).toBe(true); - for (const run of [undefined, { status: "queued", nativePhase: "provider_running" }, - { status: "succeeded", nativePhase: "committed" }, { status: "running", nativePhase: "result_accepted" }, - { status: "running", nativePhase: "workspace_finalizing" }]) expect(isActiveStopCheckpointRun(run)).toBe(false); +it("observes the actual active provider through its durable turn rather than a finalization phase label", () => { + const run = { id: "run", status: "running", nativePhase: "observed" }; + const started = { runId: "run", eventType: "turn.started", sourceKind: "runner" }; + expect(isActiveStopCheckpointRun(run, [started])).toBe(true); + const prepared = { ...run, nativePhase: "provider_running" }; + expect(isActiveStopCheckpointRun(prepared, [started])).toBe(true); + for (const candidate of [undefined, { ...run, status: "queued" }, { ...run, status: "succeeded" }]) + expect(isActiveStopCheckpointRun(candidate, [started])).toBe(false); + for (const events of [[], [started, started], [{ ...started, runId: "foreign" }], [{ ...started, sourceKind: "control_plane" }], + ...["run.result.accepted", "run.terminal", "turn.completed", "turn.failed", "turn.cancelled"].map(eventType => [started, { runId: "run", eventType }])]) + expect(isActiveStopCheckpointRun(run, events)).toBe(false); }); diff --git a/tests/runner-e2e/followup-stop-resume.ts b/tests/runner-e2e/followup-stop-resume.ts index 4e59340ed95..196740d4b1c 100644 --- a/tests/runner-e2e/followup-stop-resume.ts +++ b/tests/runner-e2e/followup-stop-resume.ts @@ -25,8 +25,12 @@ export const followupStopTask: RunnerTaskFixture = { ].join("\n"); }, buildMatchers: () => [], }; -export function isActiveStopCheckpointRun(run: { status?: string; nativePhase?: string | null } | undefined) { - return run?.status === "running" && run.nativePhase === "provider_running"; +export function isActiveStopCheckpointRun(run: { id?: string; status?: string } | undefined, + events: readonly { runId?: string; eventType?: string; sourceKind?: string }[]) { + if (!run?.id || run.status !== "running") return false; + const owned = events.filter(event => event.runId === run.id); + return owned.filter(event => event.eventType === "turn.started" && event.sourceKind === "runner").length === 1 && + !owned.some(event => ["run.result.accepted", "run.terminal", "turn.completed", "turn.failed", "turn.cancelled"].includes(event.eventType ?? "")); } export function exactSyntheticJson(content: string, expected: Record): boolean { let parsed: unknown;