From ec926ce89e5460a67f556faa8432747155955bc9 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Tue, 14 Jul 2026 17:20:35 -0400 Subject: [PATCH] fix(desktop): full-reset the thread runtime on a disjoint transcript swap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The incremental external-store runtime reconciles message repositories in place (addOrUpdateMessage + prune-non-incoming). On a session switch the incoming transcript shares no ids with the current one, and grafting the new chain onto the old tree before pruning can strand a stale head/branch — the thread keeps showing the previous session. When nothing carries over there's nothing to preserve, so clear the tree first (leaves→root) then rebuild clean. Belt-and- suspenders alongside the $messages-carryover fix. --- .../src/lib/incremental-external-store-runtime.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/desktop/src/lib/incremental-external-store-runtime.ts b/apps/desktop/src/lib/incremental-external-store-runtime.ts index c055175091dd..7cf5520ce804 100644 --- a/apps/desktop/src/lib/incremental-external-store-runtime.ts +++ b/apps/desktop/src/lib/incremental-external-store-runtime.ts @@ -39,6 +39,17 @@ function syncRepositoryIncrementally( ): readonly ThreadMessage[] { const repository = (runtime as unknown as { repository: ExternalStoreThreadRuntimeCore['repository'] }).repository const incomingIds = new Set(messageRepository.messages.map(({ message }) => message.id)) + const existing = repository.export().messages + + // A thread switch swaps in a fully-DISJOINT transcript (no id carries over). + // Reconciling two unrelated trees in place — grafting the new chain onto the + // old one, then pruning — can strand a stale head/branch, so there's nothing + // to preserve: clear the tree first (leaves→root), then rebuild clean. + if (existing.length > 0 && !existing.some(({ message }) => incomingIds.has(message.id))) { + for (const { message } of [...existing].reverse()) { + repository.deleteMessage(message.id) + } + } for (const { message, parentId } of messageRepository.messages) { repository.addOrUpdateMessage(parentId, message)