From ff9ee74c46917234c02b1a20b3af1b39d0fdb735 Mon Sep 17 00:00:00 2001 From: Dotta Date: Sat, 7 Nov 2026 21:26:24 -0600 Subject: [PATCH] fix(issues): do not wake the assignee for an issue created already closed Creating an issue with status done or cancelled and an agent assignee queued an issue_assigned wake, so the agent got a run for finished work (and it queued behind any run the agent already had). The update path already treats restoring an assignee on closed work as not a reopen request, and create-time fast responses already skip done and cancelled. Apply the same guard to the create-time assignment wake. Co-Authored-By: Claude Opus 5.5 --- ...issue-onboarding-first-task-routes.test.ts | 19 +++++++++++++++++++ server/src/routes/issues.ts | 6 ++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/server/src/__tests__/issue-onboarding-first-task-routes.test.ts b/server/src/__tests__/issue-onboarding-first-task-routes.test.ts index 0ae5a48a5e3..87b590e517c 100644 --- a/server/src/__tests__/issue-onboarding-first-task-routes.test.ts +++ b/server/src/__tests__/issue-onboarding-first-task-routes.test.ts @@ -342,6 +342,25 @@ describeEmbeddedPostgres("issue create onboarding first-task routes", () => { expect(mockAdapterExecute).not.toHaveBeenCalled(); }); + it.each(["done", "cancelled"])("does not queue an assignment wake for an issue created already %s", async (status) => { + const companyId = await seedCompany(); + const agentId = await seedAgent(companyId); + const app = createApp(); + + await request(app) + .post(`/api/companies/${companyId}/issues`) + .send({ title: "Historical record", status, assigneeAgentId: agentId }) + .expect(201); + + await drainHeartbeatRunsToQuiescence(db, heartbeatService(db)); + const wakeups = await db + .select() + .from(agentWakeupRequests) + .where(eq(agentWakeupRequests.companyId, companyId)); + expect(wakeups).toHaveLength(0); + expect(mockAdapterExecute).not.toHaveBeenCalled(); + }); + it("still queues an assignment wake for an ordinary assigned issue", async () => { const companyId = await seedCompany(); const agentId = await seedAgent(companyId); diff --git a/server/src/routes/issues.ts b/server/src/routes/issues.ts index a0507f4785e..c8dbbe7c1d9 100644 --- a/server/src/routes/issues.ts +++ b/server/src/routes/issues.ts @@ -13242,9 +13242,11 @@ export function issueRoutes( // Do not auto-wake the onboarding first task. Nothing should run and no // token should be spent until the user types: the greeting is posted above // (deterministic, no LLM) and the user's first comment wakes the assignee - // through the normal comment path. Every other create path keeps its wake. + // through the normal comment path. A task created already done or + // cancelled is a record, not work: like restoring an assignee on closed + // work, it must not wake the assignee. Every other create keeps its wake. - if (!isOnboardingFirstTask) { + if (!isOnboardingFirstTask && !isClosedIssueStatus(issue.status)) { void queueIssueAssignmentWakeup({ heartbeat, issue,