diff --git a/apps/server/test/threads/thread-send-dispatch.test.ts b/apps/server/test/threads/thread-send-dispatch.test.ts index 9245cfa05..d4a076921 100644 --- a/apps/server/test/threads/thread-send-dispatch.test.ts +++ b/apps/server/test/threads/thread-send-dispatch.test.ts @@ -313,6 +313,56 @@ describe("user message telemetry", () => { }); describe("turn submit failure settlement", () => { + it("issue 2370 keeps a live thread active after a pending-start refusal", async () => { + await withTestHarness(async (harness) => { + const { environment, thread } = seedProviderThreadFixture({ + harness, + status: "active", + value: 2370, + }); + seedTurnStarted(harness.deps, { + environmentId: environment.id, + providerThreadId: "provider-send-dispatch-2370", + sequence: 3, + threadId: thread.id, + turnId: "turn-still-healthy", + }); + const activeThread = getThread(harness.db, thread.id); + if (!activeThread) throw new Error("Expected an active thread"); + + await sendThreadMessage(harness.deps, { + environment, + payload: { + input: textInput("send while the first turn is still starting"), + mode: "auto", + model: "gpt-5", + permissionMode: "full", + reasoningLevel: "medium", + serviceTier: "default", + }, + thread: activeThread, + trigger: "user", + }); + const queued = await waitForQueuedCommand( + harness, + (candidate) => + candidate.command.type === "turn.submit" && + candidate.command.threadId === thread.id, + ); + await reportQueuedCommandError(harness, queued, { + errorCode: "command_failed", + errorMessage: + `Refusing to start a competing turn while ${thread.id} is still starting`, + }); + + const eventTypes = listEvents(harness.db, { + threadId: thread.id, + }).map((event) => event.type); + expect.soft(eventTypes).not.toContain("system/error"); + expect.soft(getThread(harness.db, thread.id)?.status).toBe("active"); + }); + }); + it("records a terminal rejection for the failed client request", async () => { await withTestHarness(async (harness) => { const { environment, thread } = seedProviderThreadFixture({