From ddae171a37a9b8232daac1f0514dea967a1b33cf Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Wed, 22 Apr 2026 02:15:39 -0400 Subject: [PATCH] =?UTF-8?q?fix(pilot):=20clear=20messages=20in=20resetSess?= =?UTF-8?q?ionDerivedState=20=E2=80=94=20was=20leaking=20across=20chats?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symptom: sidebar showed "User mjones got locked out … 0 messages" but the conversation pane was rendering 2 messages from a different chat. The task lane content matched what was displayed (so the AI was fine post- prompt-sweep) — the leak was purely UI: messages from the previous chat stayed on screen until the new chat's getSession returned. selectChat resetSessionDerivedState() then awaits getSession before calling setMessages(detail.conversation_messages). Between the reset and that await, the prior chat's messages remain visible. handleNewChat already had an explicit setMessages([]) call so it was unaffected; selectChat did not. Folded setMessages([]) into resetSessionDerivedState so any new chat- switch entry point gets the wipe for free. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/pages/AssistantChatPage.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/AssistantChatPage.tsx b/frontend/src/pages/AssistantChatPage.tsx index 4edc528a..7e4d27b0 100644 --- a/frontend/src/pages/AssistantChatPage.tsx +++ b/frontend/src/pages/AssistantChatPage.tsx @@ -272,12 +272,18 @@ export default function AssistantChatPage() { } } - // Single source of truth for "wipe every per-session task-lane state field" - // before switching to a different chat. Called from selectChat, handleNewChat, - // sendPrefill, and handleResumeNew so adding new lane-scoped state in future + // Single source of truth for "wipe every per-chat UI state field" before + // switching to a different chat. Called from selectChat, handleNewChat, + // sendPrefill, and handleResumeNew so adding new chat-scoped state in future // phases only requires touching this one helper. Forgetting to clear a field - // leaks the previous session's data into the new one (Phase 5 regression). + // leaks the previous chat's data into the new one — first noticed as a task + // lane regression (Phase 5), surfaced again as the conversation pane showing + // the previous chat's messages while the sidebar entry said "0 messages". + // `messages` belongs in here too: selectChat clears it asynchronously when + // getSession returns, but the gap between switching and that response is + // exactly when the previous chat's content stays visible. const resetSessionDerivedState = useCallback(() => { + setMessages([]) setShowTaskLane(false) setActiveQuestions([]) setActiveActions([])