fix(webui): clear the user-row intrinsic-height cache on session switch (Greptile #5672)
The module-level _userRowIntrinsicHeightBySessionIdx cache is keyed by session-relative index (_messageSessionIndexForRawIdx = _messageSessionIndexBase() + rawIdx). The base is 0 for the common non-offset session, so keys collide across sessions: after switching from a session with tall user rows to one with short rows, the new session's off-screen rows at colliding keys inherited the previous session's remembered heights and inflated scrollHeight until re-measured. Add _clearUserRowIntrinsicHeightCache() and call it from _clearMessageVirtualHeightCache — the existing per-session height-cache clear that _resetMessageRenderWindow invokes on session switch — so the new cache shares the exact same lifetime as _messageVirtualHeightCache. Keys are deleted in place to keep the const binding stable. Guard the call with typeof so the node harnesses that extract _clearMessageVirtualHeightCache without this helper keep running. Adds a mutation-checked regression (test_cache_cleared_on_session_switch_prevents_ stale_height_bleed): a rebuilt row at a colliding key after the clear must fall back to the content estimate, not the stale remembered height; making the clear a no-op fails the test.
This commit is contained in:
1 parent
12a45c655f
commit
a7515d67e8
2 files changed
+61
No files matched your search
@@ -270,3 +270,53 @@ console.log(JSON.stringify({ inline: assistantRow.style.containIntrinsicSize }))
|
||||
"assistant rows must NOT get an inline intrinsic-size writeback; "
|
||||
f"got {m['inline']!r}"
|
||||
)
|
||||
|
||||
|
||||
def test_cache_cleared_on_session_switch_prevents_stale_height_bleed():
|
||||
"""Greptile #5672 review: the module-level height cache is keyed by
|
||||
session-relative index (_messageSessionIndexBase()+rawIdx), and the base is 0
|
||||
for the common non-offset session, so keys collide across sessions. Without a
|
||||
clear on session switch, a new session's off-screen user row at the same key
|
||||
inherits the previous session's remembered height and inflates scrollHeight.
|
||||
|
||||
_clearUserRowIntrinsicHeightCache() (wired into _clearMessageVirtualHeightCache,
|
||||
which _resetMessageRenderWindow calls on session switch) must empty the cache so
|
||||
a rebuilt row at a colliding key falls back to the content estimate, NOT the
|
||||
stale remembered height.
|
||||
|
||||
Mutation: make _clearUserRowIntrinsicHeightCache a no-op and this fails (the
|
||||
rebuilt row reserves the stale 5000px instead of the ~short estimate)."""
|
||||
js = UI_JS_PATH.read_text(encoding="utf-8")
|
||||
source = _extract_func_script(js) + _fake_row_prelude() + r"""
|
||||
eval(extractFunc('_rememberUserRowIntrinsicHeight'));
|
||||
eval(extractFunc('_estimateUserRowIntrinsicHeight'));
|
||||
eval(extractFunc('_applyUserRowIntrinsicHeight'));
|
||||
eval(extractFunc('_clearUserRowIntrinsicHeightCache'));
|
||||
// Session A: a tall user row at session-relative index 3 measured 5000px.
|
||||
_rememberUserRowIntrinsicHeight(3, 5000);
|
||||
const beforeClear = makeRow('user', 3, 0);
|
||||
_applyUserRowIntrinsicHeight(beforeClear, 'x'); // would reserve the remembered 5000
|
||||
// Session switch clears the cache.
|
||||
_clearUserRowIntrinsicHeightCache();
|
||||
// Session B: a SHORT user row at the SAME colliding key 3, never measured here.
|
||||
const afterClear = makeRow('user', 3, 0);
|
||||
_applyUserRowIntrinsicHeight(afterClear, 'hi'); // must fall back to the estimate
|
||||
const estimate = _estimateUserRowIntrinsicHeight('hi');
|
||||
console.log(JSON.stringify({
|
||||
beforeClear: beforeClear.style.containIntrinsicSize,
|
||||
afterClear: afterClear.style.containIntrinsicSize,
|
||||
estimate: 'auto ' + estimate + 'px',
|
||||
}));
|
||||
"""
|
||||
m = json.loads(_run_node(source))
|
||||
assert m["beforeClear"] == "auto 5000px", (
|
||||
"sanity: before the clear, the remembered 5000px must be reserved; "
|
||||
f"got {m['beforeClear']!r}"
|
||||
)
|
||||
assert m["afterClear"] == m["estimate"], (
|
||||
"after a session switch clear, a rebuilt row at the colliding key must fall "
|
||||
f"back to the content estimate ({m['estimate']}), NOT the stale remembered "
|
||||
f"5000px; got {m['afterClear']!r} (buggy: cache not cleared → stale bleed)"
|
||||
)
|
||||
assert m["afterClear"] != "auto 5000px", "stale height must not survive the clear"
|
||||
|
||||
Reference in new issue
Block a user