Summary
Three code paths that clear #chat-history do not call window.chatHistory.reset() first, violating the DOM-virtualization invariant introduced by the message-window work (#2): "reset() must precede innerHTML='' so observers/holders are released" (see static/js/chatHistory.js:12, static/js/sessions.js:40-41).
#2 retrofitted the guard to six wipe sites but missed these three:
| Site |
Function |
Trigger |
static/js/sessions.js:2086 |
createDirectChat |
New Chat button |
static/js/slashCommands.js:1182 |
_cmdSessionClear |
/clear command |
static/js/sessions.js:2680 |
archived-session view |
opening an archived chat |
User-visible symptom (New Chat path)
Open Odysseus with a restored session of N messages, then click New Chat. The header shows "New Chat · N msgs" — a stale count leaking from the previous session — instead of a clean "New Chat".
Root cause
The header counter (static/app.js:344-351) treats window.chatHistory.messageCount() as authoritative and recomputes on every #chat-history mutation. messageCount() returns _serverTotal + _liveMsgs. Because createDirectChat clears the DOM without reset(), _serverTotal (= previous session's row count) survives, so the innerHTML='' mutation re-fires the counter and it reads the stale total. reset() sets _serverTotal = null, which makes messageCount() return null, and the counter then falls back to the (now empty) DOM count → the badge clears.
The /clear and archived-view paths have the same defect: stale header count and a live MutationObserver tracking a DOM it no longer matches.
Fix
Insert if (window.chatHistory) window.chatHistory.reset(); immediately before the innerHTML='' at each of the three sites, matching the six existing compliant sites. Add a source-assertion regression guard that asserts reset() precedes the wipe in each function.
Scope / classification
Regression introduced by #2 (the message-window feature). Fix belongs on fix/dom-oom-virtualization, cherry-picked to develop. No separate upstream PR — folds into #2.
Summary
Three code paths that clear
#chat-historydo not callwindow.chatHistory.reset()first, violating the DOM-virtualization invariant introduced by the message-window work (#2): "reset() must precede innerHTML='' so observers/holders are released" (seestatic/js/chatHistory.js:12,static/js/sessions.js:40-41).#2 retrofitted the guard to six wipe sites but missed these three:
static/js/sessions.js:2086createDirectChatstatic/js/slashCommands.js:1182_cmdSessionClear/clearcommandstatic/js/sessions.js:2680User-visible symptom (New Chat path)
Open Odysseus with a restored session of N messages, then click New Chat. The header shows "New Chat · N msgs" — a stale count leaking from the previous session — instead of a clean "New Chat".
Root cause
The header counter (
static/app.js:344-351) treatswindow.chatHistory.messageCount()as authoritative and recomputes on every#chat-historymutation.messageCount()returns_serverTotal + _liveMsgs. BecausecreateDirectChatclears the DOM withoutreset(),_serverTotal(= previous session's row count) survives, so theinnerHTML=''mutation re-fires the counter and it reads the stale total.reset()sets_serverTotal = null, which makesmessageCount()returnnull, and the counter then falls back to the (now empty) DOM count → the badge clears.The
/clearand archived-view paths have the same defect: stale header count and a live MutationObserver tracking a DOM it no longer matches.Fix
Insert
if (window.chatHistory) window.chatHistory.reset();immediately before theinnerHTML=''at each of the three sites, matching the six existing compliant sites. Add a source-assertion regression guard that assertsreset()precedes the wipe in each function.Scope / classification
Regression introduced by #2 (the message-window feature). Fix belongs on
fix/dom-oom-virtualization, cherry-picked todevelop. No separate upstream PR — folds into #2.