From 93f30ecfda42aea724f89e6812077d0896f44efe Mon Sep 17 00:00:00 2001 From: nesquena-hermes Date: Wed, 6 May 2026 08:21:42 +0000 Subject: [PATCH] fix(scroll): reset _lastScrollTop on session switch (Opus stage-302 follow-up) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opus advisor on stage-302 (#1732 verification Q5) flagged that _lastScrollTop is module-global and persists across chat switches. When the user switches sessions, the new chat's first user scroll compares against the previous chat's last scrollTop. If the previous was deep- scrolled (e.g. 5000) and the new chat starts at top=0, scrolling down to 100 would evaluate as movedUp=true → false-unpin, blocking auto- scroll on the new chat's first incoming token. Fix: expose _resetScrollDirectionTracker() from static/ui.js on window so static/sessions.js loadSession() can reset _lastScrollTop=null when S.session is reassigned. The scroll listener's existing _lastScrollTop!==null guard then handles the first sample after reset correctly (no false-trigger on the very first scroll event in the new chat). Absorb-in-release per Opus stage-302 verdict — small, defensive, ≤20 LOC. --- static/sessions.js | 6 ++++++ static/ui.js | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/static/sessions.js b/static/sessions.js index 849ee30c..183342ef 100644 --- a/static/sessions.js +++ b/static/sessions.js @@ -392,6 +392,12 @@ async function loadSession(sid){ S.session=data.session; S.session._modelResolutionDeferred=true; S.lastUsage={...(data.session.last_usage||{})}; + // Reset scroll-direction tracker on session switch so the new chat's + // first scroll doesn't compare against the previous chat's scrollTop + // and false-trigger an unpin (#1731 follow-up — Opus stage-302 SHOULD-FIX). + if (typeof window !== 'undefined' && typeof window._resetScrollDirectionTracker === 'function') { + try { window._resetScrollDirectionTracker(); } catch (_) {} + } // Sync workspace display immediately so the chip label reflects the new session's workspace // before any async message-loading begins (mirrors how model is handled). if(typeof syncTopbar==='function') syncTopbar(); diff --git a/static/ui.js b/static/ui.js index 2e226515..bef64a22 100644 --- a/static/ui.js +++ b/static/ui.js @@ -1401,6 +1401,11 @@ let _scrollPinned=true; let _programmaticScroll=false; let _nearBottomCount=0; let _lastScrollTop=null; +// Reset hook for session-switch — called from sessions.js loadSession() to +// prevent the new chat's first scroll comparing against the previous chat's +// scrollTop (Opus stage-302 SHOULD-FIX, #1731 follow-up). +function _resetScrollDirectionTracker(){ _lastScrollTop=null; } +if (typeof window !== 'undefined') window._resetScrollDirectionTracker = _resetScrollDirectionTracker; (function(){ const el=document.getElementById('messages'); if(!el) return;