test: identify active Stop boundary from durable provider events

This commit is contained in:
Dotta committed 2026-10-21 11:39:24 -05:00
1 parent 12624d60c3
commit 2d89146adc
3 files changed
+20 -10

No files matched your search

@@ -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");
+11 -5
View File
@@ -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);
});
+6 -2
View File
@@ -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<string, string>): boolean {
let parsed: unknown;