From 6e8422ade0afb36ea9968b8a90942840ebbcb806 Mon Sep 17 00:00:00 2001 From: Alex Southwell <4596216+saphid@users.noreply.github.com> Date: Tue, 3 Nov 2026 08:17:24 +1100 Subject: [PATCH] fix(server): pinning a settled thread stamps its return to the active list Co-Authored-By: Claude Opus 5.5 --- apps/server/src/orchestration-v2/Orchestrator.ts | 1 + .../src/orchestration-v2/runtimeLayer.test.ts | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/apps/server/src/orchestration-v2/Orchestrator.ts b/apps/server/src/orchestration-v2/Orchestrator.ts index 0df010b690829..6f6622aa17c6c 100644 --- a/apps/server/src/orchestration-v2/Orchestrator.ts +++ b/apps/server/src/orchestration-v2/Orchestrator.ts @@ -3550,6 +3550,7 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio settledOverride: thread.settledOverride === "settled" ? "active" : thread.settledOverride, settledAt: thread.settledOverride === "settled" ? null : thread.settledAt, + ...(thread.settledOverride === "settled" ? { unsettledAt: now } : {}), snoozedUntil: null, snoozedAt: null, lastSnoozeWakeAt: thread.snoozedUntil == null ? thread.lastSnoozeWakeAt : now, diff --git a/apps/server/src/orchestration-v2/runtimeLayer.test.ts b/apps/server/src/orchestration-v2/runtimeLayer.test.ts index 769ced28d2f15..b1377849d27bd 100644 --- a/apps/server/src/orchestration-v2/runtimeLayer.test.ts +++ b/apps/server/src/orchestration-v2/runtimeLayer.test.ts @@ -2641,6 +2641,20 @@ it.layer(layerTest)("OrchestrationV2LayerLive lifecycle", (it) => { ); assert.deepEqual(activeShell?.unsettledAt, activeProjection.thread.unsettledAt); + yield* orchestrator.dispatch({ + type: "thread.settle", + commandId: CommandId.make("runtime-layer-lifecycle-resettle"), + threadId, + }); + yield* orchestrator.dispatch({ + type: "thread.pin", + commandId: CommandId.make("runtime-layer-lifecycle-pin-settled"), + threadId, + }); + const pinnedProjection = yield* orchestrator.getThreadProjection(threadId); + assert.equal(pinnedProjection.thread.settledOverride, "active"); + assert.isNotNull(pinnedProjection.thread.unsettledAt); + const archive = yield* orchestrator.dispatch({ type: "thread.archive", commandId: CommandId.make("runtime-layer-lifecycle-archive"),