From 3f1ba38f19da386b2db41ac88c7b55c758b235ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sat, 22 Aug 2026 18:35:09 +0000 Subject: [PATCH] the chat panel's header names a new conversation too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The list learned the name and the panel header did not, which narrowed it to one lookup: the panel records its session id, and ChatHeader resolves the title by finding that id in the sessions LIST. The panel was recording `chat.sessionId` — OFFICER's session key — and the list is keyed on Claude's TRANSCRIPT id. Two id spaces on either side of one `find`, so it never matched: a new chat's header read "New chat" for the whole life of the conversation and offered no rename, because rename is a per-row action on a list the session was not found in. Selecting the conversation from the list fixed it, which is exactly why navigating away and back looked like the cure. Same trap as the Command HQ pane on 2026-08-21, third time this pair has caused a bug: officer's handle and the harness's transcript id are not interchangeable, and every place that keys one lookup on the other fails silently rather than loudly. The "only a REAL id, never null" rule is unchanged and still needed — both ids are null for a moment while a resumed session connects, and writing that null would turn "this panel has never chosen" into "the user asked for a new chat", so the next reload would open blank. Co-Authored-By: Claude Opus 5 --- .../src/apps/Chat/ChatPanelWrapper.tsx | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx b/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx index 5cbe7536..adc809d2 100644 --- a/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx +++ b/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx @@ -84,16 +84,23 @@ const ChatPanelInner = ({ useEffect(() => { setActiveSession(chat.sessionId); - // Only a REAL id, never null. - // - // A new chat is nameless until the harness names it on the first turn, and recording that id is what - // makes "New chat, say something, reload" return to that conversation instead of a third one. But - // `chat.sessionId` is also null for a moment while a resumed session connects — and writing that null - // would turn "this panel has never chosen" into "the user asked for a new chat", so the next reload - // would open blank. Asking for a new conversation is something the header says explicitly; this - // effect only ever reports what the harness decided. - if (chat.sessionId) onSessionId?.(chat.sessionId); - }, [chat.sessionId]); + /* + `claudeSessionId`, NOT `sessionId`. The panel's stored id is looked up in the sessions LIST — see + `ChatHeader`'s `sessions.find((s) => s.id === sessionId)` — and that list is keyed on Claude's + transcript id. Recording officer's own session key here put two id spaces on either side of one + lookup: it never matched, so a new chat's header read "New chat" for the life of the conversation and + offered no rename, because rename is a per-row action on a list the session was not found in. + Selecting the conversation from the list fixed it, which is why navigating away and back appeared to + be the cure. + + Only a REAL id, never null. A new chat has none until the harness names its transcript on the first + turn, and recording it is what makes "new chat, say something, reload" return to that conversation + rather than a third one. Both ids are also null for a moment while a resumed session connects, and + writing that null would turn "this panel has never chosen" into "the user asked for a new chat", so + the next reload would open blank. + */ + if (chat.claudeSessionId) onSessionId?.(chat.claudeSessionId); + }, [chat.sessionId, chat.claudeSessionId]); return (