fix(webui): require an actual captured topPadBefore before the gone-anchor topPad-delta (greptile P1)

When the anchor row is gone and a virtual top-spacer is present but the snapshot
carries no captured topPadBefore (null), Number(null) is 0, so the topPad-delta
branch would add the ENTIRE current spacer height to scrollTop and fling the reader
far from their content. Guard on an actual (non-null) captured topPadBefore; else
keep the raw fallback target. Mutation-checked (drop the null guard -> the reader is
flung 1300px and the test fails).
This commit is contained in:
allenliang2022
2026-07-08 01:54:23 +08:00
committed by t
parent 7164847255
commit fbfb6da8fe
2 changed files with 24 additions and 2 deletions
+7 -2
View File
@@ -13641,8 +13641,13 @@ function _restoreMessageScrollSnapshotSameFrame(snapshot){
const s=el.querySelector('[data-virtual-spacer="before"]');
return s?(parseFloat(s.style.height||'0')||0):NaN;
})();
const _padBefore=Number(snapshot.anchor&&snapshot.anchor.topPadBefore);
if(Number.isFinite(_padNow)&&Number.isFinite(_padBefore)){
const _padBeforeRaw=snapshot.anchor&&snapshot.anchor.topPadBefore;
const _padBefore=Number(_padBeforeRaw);
// Require an ACTUAL captured topPadBefore (not null/undefined): Number(null) is 0,
// which would otherwise add the ENTIRE current spacer height to scrollTop and fling
// the reader far from their content (greptile P1). Only apply when it was really
// captured; else keep the raw fallback target.
if(_padBeforeRaw!=null&&Number.isFinite(_padNow)&&Number.isFinite(_padBefore)){
_fbTarget=Math.max(0,Math.min(el.scrollTop+(_padNow-_padBefore), maxTop));
}
// else: no measurable anchor and no topPad geometry -> keep raw target.
@@ -407,6 +407,23 @@ def test_realign_genuinely_gone_anchor_no_geometry_keeps_raw_desktop():
assert m["writes"] == [1200]
def test_realign_gone_anchor_null_toppadbefore_does_not_fling_desktop():
"""greptile P1: anchor row gone, a virtual top-spacer IS present (padNow=1300), but the
snapshot carries NO captured topPadBefore (null). Number(null) is 0, so a naive
isFinite(padBefore) check would treat padBefore as 0 and add the ENTIRE 1300px spacer
to scrollTop (1000 -> 2300), flinging the reader far from their content. The guard
requires an ACTUAL captured topPadBefore, so with null it keeps the raw snapshot.top.
Mutation: drop the `_padBeforeRaw!=null` term and this FAILS (writes 2300, the fling)."""
m = json.loads(_run_node(_fallback_harness(
snapshot_scroll_height=90000, cur_scroll_height=90500, snapshot_top=1200,
active_intent=False, touch_like=False,
anchor={"key": "gone", "sessionIdx": 999, "topOffset": 1000, "topPadBefore": None},
anchor_row_content_pos=None, container_top=0, init_scroll_top=1000,
top_pad_now=1300,
)))
assert m["writes"] == [1200]
def _predicate_harness(*, pointer_coarse, computed_overflow_anchor, has_matchmedia=True,