mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-07-15 12:10:19 +00:00
18cd79797f
A residual mobile scroll jump-back remained after #5638: while the reader is up in history during a live stream, the anchor captured for a same-frame restore goes stale as the streaming chunk grows content ABOVE the viewport. The anchor's captured topOffset (and the absolute snapshot.top) no longer map to the same content, so realigning to them yanks a still reader backward by a few hundred px per tick. The existing snapshot.userUnpinned===true fallback skip does not cover it: the scrollHeight-collapse scroll event re-pins the state machine (flips userUnpinned back to false) mid-stream, so both the semantic realign (_restoreMessageViewportAnchor) and the absolute snapshot.top fallback still fire. Fix: two guards, both keyed on content-growth-since-capture + absence of recent real input intent, NOT on a scrollTop diff — on an overflow-anchor:auto container the browser itself writes scrollTop to compensate above-viewport growth, so a still reader's scrollTop is not stationary; _recentMessage*ScrollIntent instead reflects genuine touch/wheel/key input, which the browser's anchor layer never sets. - _captureMessageViewportAnchor records scrollHeightAtCapture (+scrollTopAtCapture). - _restoreMessageViewportAnchor refuses the realign when content grew since capture, there is no recent intent, and the delta would move scrollTop >8px. - the absolute snapshot.top fallback in _restoreMessageScrollSnapshotSameFrame mirrors the same guard. An actively scrolling reader (recent intent) keeps the legitimate restore; a fresh anchor (no growth) and legacy snapshots without the captured geometry are unaffected. Adds tests/test_issue5637_stale_anchor_guard.py (7 node-harness cases; two are mutation-checked to fail if either guard is removed).