From 006433521e77028816d7c5bcb0b783e7fe099ed6 Mon Sep 17 00:00:00 2001 From: Sawyer Hood Date: Mon, 7 Sep 2026 03:20:13 -0700 Subject: [PATCH] Avoid duplicate task lifecycle startup reconciliation --- plugins/tasks/lifecycle/index.ts | 1 - plugins/tasks/lifecycle/lifecycle.test.ts | 19 +++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/plugins/tasks/lifecycle/index.ts b/plugins/tasks/lifecycle/index.ts index 361ffb3f91..208ce01672 100644 --- a/plugins/tasks/lifecycle/index.ts +++ b/plugins/tasks/lifecycle/index.ts @@ -196,5 +196,4 @@ export async function registerLifecycle( }); await reconcileTrackedThreads(bb, store); - await reconcileTrackedThreads(bb, store); } diff --git a/plugins/tasks/lifecycle/lifecycle.test.ts b/plugins/tasks/lifecycle/lifecycle.test.ts index 8854a5eeeb..f56e2464c9 100644 --- a/plugins/tasks/lifecycle/lifecycle.test.ts +++ b/plugins/tasks/lifecycle/lifecycle.test.ts @@ -63,6 +63,18 @@ function trackedThreadFixture( } describe("task thread lifecycle", () => { + it("reconciles each non-terminal task thread once during startup", async () => { + const fixture = trackedThreadFixture("working", "active"); + + await registerLifecycle(fixture.bb, fixture.store); + + expect(fixture.harness.sdk.callsTo("threads.get")).toEqual([ + [{ threadId: "thr_worker" }], + ]); + + await fixture.harness.dispose(); + }); + it("moves a working thread to completed, comments, and publishes", async () => { const fixture = trackedThreadFixture("working", "active"); await registerLifecycle(fixture.bb, fixture.store); @@ -149,7 +161,6 @@ describe("task thread lifecycle", () => { expect(fixture.harness.sdk.callsTo("threads.get")).toEqual([ [{ threadId: "thr_worker" }], - [{ threadId: "thr_worker" }], ]); expect( fixture.store.tasks.getTaskThread(fixture.taskThreadId)?.liveStatus, @@ -210,7 +221,7 @@ describe("task thread lifecycle", () => { "thread.failed": 1, "thread.deleted": 1, }); - expect(host.harness.sdk.callsTo("threads.get")).toHaveLength(2); + expect(host.harness.sdk.callsTo("threads.get")).toHaveLength(1); expect(store.tasks.getTaskThread(tracked.id)?.liveStatus).toBe("starting"); await host.harness.dispose(); @@ -231,7 +242,7 @@ describe("task thread lifecycle", () => { expect( fixture.store.tasks.getTaskThread(fixture.taskThreadId)?.liveStatus, ).toBe("working"); - expect(fixture.harness.sdk.callsTo("threads.get")).toHaveLength(2); + expect(fixture.harness.sdk.callsTo("threads.get")).toHaveLength(1); expect(fixture.harness.sdk.callsTo("subscribe")).toEqual([]); await fixture.harness.dispose(); @@ -248,7 +259,7 @@ describe("task thread lifecycle", () => { reads += 1; return makeThreadResponse({ id: "thr_safety_net", - status: reads <= 2 ? "starting" : "active", + status: reads === 1 ? "starting" : "active", }); }, },