From ab0e50bbdae2abaef8e05b01d54eba20d7dccf79 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Tue, 3 Nov 2026 02:29:25 +0000 Subject: [PATCH 1/2] test(server): reproduce #29860, a remote result overwriting a settled parent run The test commits the parent's checkpoint capture between delegated_task.remote.complete reading the parent run and committing, and expects the run to stay completed with its completedAt and checkpointId. On main the remote result writes the stale run row back. Co-Authored-By: Claude Opus 5.5 --- .../RemoteDelegatedTask.test.ts | 78 ++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/apps/server/src/orchestration-v2/RemoteDelegatedTask.test.ts b/apps/server/src/orchestration-v2/RemoteDelegatedTask.test.ts index 4bb8c103f6df7..b3e2c705485f1 100644 --- a/apps/server/src/orchestration-v2/RemoteDelegatedTask.test.ts +++ b/apps/server/src/orchestration-v2/RemoteDelegatedTask.test.ts @@ -1,5 +1,6 @@ -import { assert, it } from "@effect/vitest"; +import { assert, it, vi } from "@effect/vitest"; import { + CheckpointId, CommandId, EnvironmentId, EventId, @@ -408,4 +409,79 @@ it.layer(layerTest)("a delegated task in a linked environment", (it) => { assert.equal(offered[0]?.threadId, parent.threadId); }), ); + it.effect("keeps a parent run that settled between its result's read and commit", () => + Effect.gen(function* () { + const orchestrator = yield* Orchestrator.OrchestratorV2; + const sink = yield* EventSink.EventSinkV2; + const now = yield* DateTime.now; + const parent = yield* seedLiveParent("settles-mid-result"); + yield* orchestrator.dispatch({ + type: "delegated_task.remote.request", + commandId: CommandId.make("command:remote-delegate:settles-mid-result"), + parentThreadId: parent.threadId, + parentRunId: parent.runId, + parentNodeId: parent.rootNodeId, + task: "Run the suite there.", + driver: ProviderDriverKind.make("remote"), + modelSelection, + remoteChild, + completionWake: "always", + }); + const projection = yield* orchestrator.getThreadProjection(parent.threadId); + const task = projection.subagents[0]!; + const run = projection.runs.find((candidate) => candidate.id === parent.runId)!; + const checkpointId = CheckpointId.make("checkpoint:settles-mid-result"); + const commit = sink.commitCommand; + let settled = false; + yield* Effect.acquireUseRelease( + Effect.sync(() => + vi.spyOn(sink, "commitCommand").mockImplementation((input) => + Effect.gen(function* () { + if (!settled && input.commandType === "delegated_task.remote.complete") { + settled = true; + // The parent's checkpoint lands after the result read its run. + yield* commit({ + commandId: CommandId.make("command:checkpoint:settles-mid-result"), + threadId: parent.threadId, + commandType: "checkpoint.capture", + acceptedAt: now, + effects: [], + events: [ + { + id: EventId.make("event:settles-mid-result:settled"), + type: "run.updated", + threadId: parent.threadId, + runId: parent.runId, + occurredAt: now, + payload: { ...run, status: "completed", completedAt: now, checkpointId }, + }, + ], + }); + } + return yield* commit(input); + }), + ), + ), + () => + orchestrator.dispatch({ + type: "delegated_task.remote.complete", + commandId: CommandId.make("command:remote-complete:settles-mid-result"), + parentThreadId: parent.threadId, + taskId: task.id, + status: "completed", + result: "All 412 tests pass on the box.", + stoppedThere: "ran-out", + }), + (spy) => Effect.sync(() => spy.mockRestore()), + ); + assert.isTrue(settled); + const after = (yield* orchestrator.getThreadProjection(parent.threadId)).runs.find( + (candidate) => candidate.id === parent.runId, + )!; + assert.deepEqual( + { status: after.status, completedAt: after.completedAt, checkpointId: after.checkpointId }, + { status: "completed", completedAt: now, checkpointId }, + ); + }), + ); }); From 0fd7fb30ebcee05ed22ae705072050a69f71709a Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Tue, 3 Nov 2026 02:33:49 +0000 Subject: [PATCH 2/2] fix(server): a remote delegated result no longer reverts a settled parent run delegated_task.remote.complete wrote the parent run row it read at dispatch start. When the parent's checkpoint capture committed in between, the run went back to running with no completedAt or checkpointId and the thread deadlocked. The command now returns the parent run id it updates, as the completion delivery acknowledge/dispose and notification.delivery.accept commands do, so the event sink re-reads that run at commit and takes only delegatedCompletion from the payload. Fixes pingdotgg/t3code#29860 Co-Authored-By: Claude Opus 5.5 --- apps/server/src/orchestration-v2/Orchestrator.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/server/src/orchestration-v2/Orchestrator.ts b/apps/server/src/orchestration-v2/Orchestrator.ts index 035bd9c73db66..d6b4d13c51620 100644 --- a/apps/server/src/orchestration-v2/Orchestrator.ts +++ b/apps/server/src/orchestration-v2/Orchestrator.ts @@ -8233,7 +8233,8 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio if (task.result !== null) { // A Stop or cancel here that lost the race to the result still owes its stop. if (command.stoppedThere === undefined) { - return yield* emitRemoteStopOwed(events, command, task, task.remoteChild!); + yield* emitRemoteStopOwed(events, command, task, task.remoteChild!); + return; } const owesStop = task.status === "cancelled" || @@ -8344,6 +8345,7 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio } as OrchestrationV2TurnItem, }); } + return plan.parentRun?.id; }); /** @@ -13346,7 +13348,10 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio yield* dispatchRemoteDelegatedTaskRequest(command, events); break; case "delegated_task.remote.complete": - yield* dispatchRemoteDelegatedTaskComplete(command, events); + updateDelegatedCompletionOnlyRunId = yield* dispatchRemoteDelegatedTaskComplete( + command, + events, + ); break; case "delegated_task.remote.stop": yield* dispatchRemoteDelegatedTaskStop(command, events);