Skip to content

Commit 3fa503e

Browse files
test(server): cover finalization of a run stopped through the ownership guard
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
1 parent 8f86852 commit 3fa503e

1 file changed

Lines changed: 63 additions & 0 deletions

File tree

‎apps/server/src/orchestration-v2/RunFinalized.test.ts‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
ProjectId,
1313
ProviderInstanceId,
1414
ProviderThreadId,
15+
RunAttemptId,
1516
RunId,
1617
ThreadId,
1718
} from "@t3tools/contracts";
@@ -52,6 +53,7 @@ const rootNodeId = NodeId.make("node:run-finalized-root");
5253
const providerThreadId = ProviderThreadId.make("provider-thread:run-finalized");
5354
const providerInstanceId = ProviderInstanceId.make("codex");
5455
const checkpointId = CheckpointId.make("checkpoint:run-finalized");
56+
const attemptId = RunAttemptId.make("attempt:run-finalized");
5557

5658
const maxAttempts = 2;
5759
/** The worker's backoff after a capture's first failed attempt. */
@@ -445,6 +447,67 @@ it.effect.each(["interrupted", "cancelled"] as const)(
445447
}).pipe(Effect.provide(makeLayer(commitCapture(status)))),
446448
);
447449

450+
/** Ends a running attempt through the ownership guard, as RunExecutionService does. */
451+
const finishGuardedTurn = (
452+
status: "interrupted" | "cancelled",
453+
guard: { readonly activeAttemptId: RunAttemptId; readonly expectedStatus: "running" | "waiting" },
454+
) =>
455+
Effect.gen(function* () {
456+
const eventSink = yield* EventSink.EventSinkV2;
457+
const now = yield* DateTime.now;
458+
yield* eventSink.write({
459+
events: [
460+
runEvent("run.updated", makeRun(now, "running", { activeAttemptId: attemptId }), now),
461+
],
462+
});
463+
return yield* eventSink.writeIfRunCurrent({
464+
threadId,
465+
runId,
466+
...guard,
467+
events: [
468+
runEvent(
469+
"run.updated",
470+
makeRun(now, status, { activeAttemptId: attemptId, completedAt: now }),
471+
now,
472+
),
473+
],
474+
effects: [captureEffect],
475+
});
476+
});
477+
478+
it.effect.each(["interrupted", "cancelled"] as const)(
479+
"a guarded stop that queues a capture finalizes as %s after the capture",
480+
(status) =>
481+
Effect.gen(function* () {
482+
yield* seedThread;
483+
const result = yield* finishGuardedTurn(status, {
484+
activeAttemptId: attemptId,
485+
expectedStatus: "running",
486+
});
487+
assert.isTrue(result.committed);
488+
assert.lengthOf(yield* finalizationRecords, 0);
489+
yield* drainWorker;
490+
assert.deepEqual(yield* finalizationRecords, [
491+
{ type: "run.finalized", payload: { runId, outcome: status, checkpointId } },
492+
]);
493+
}).pipe(Effect.provide(makeLayer(commitCapture(status)))),
494+
);
495+
496+
it.effect("a guarded stop that no longer owns the run commits and queues nothing", () =>
497+
Effect.gen(function* () {
498+
yield* seedThread;
499+
const result = yield* finishGuardedTurn("interrupted", {
500+
activeAttemptId: RunAttemptId.make("attempt:run-finalized-stale"),
501+
expectedStatus: "running",
502+
});
503+
assert.isFalse(result.committed);
504+
assert.deepEqual(yield* captureStatus, Option.none());
505+
assert.equal(yield* drainWorker, 0);
506+
assert.equal(yield* runStatus, "running");
507+
assert.lengthOf(yield* finalizationRecords, 0);
508+
}).pipe(Effect.provide(makeLayer(commitCapture("interrupted")))),
509+
);
510+
448511
it.effect("a run that ends without a capture finalizes in its terminal commit", () =>
449512
Effect.gen(function* () {
450513
const eventSink = yield* EventSink.EventSinkV2;

0 commit comments

Comments
 (0)