Found by /code-review on PR #310 (score 75, sub-threshold, relayed informally).
The prepend scroll-preservation introduced in PR #308 reads scrollHeight before ctx.$set(asKey, accumulated) and compensates immediately after, relying on the loop's re-render being synchronous. When the loop element carries animate-leave, loops.js defers renderItems() behind animationend/setTimeout, so the post-$set read sees a zero height delta and the compensation silently does nothing — the user sees a scroll jump once the deferred render lands. The code comment at src/directives/http.js:~533-542 overclaims that the rebuild is "both synchronous".
Fix direction: make compensation robust to deferred renders (e.g. one-shot MutationObserver on the container's childList that performs the delta adjustment when the render actually lands, with disposal guard per CLAUDE.md safety rules), or an equivalent deterministic signal from the loop. Correct the comment either way. Tests must cover prepend WITH and WITHOUT animate-leave.
Found by /code-review on PR #310 (score 75, sub-threshold, relayed informally).
The prepend scroll-preservation introduced in PR #308 reads scrollHeight before
ctx.$set(asKey, accumulated)and compensates immediately after, relying on the loop's re-render being synchronous. When the loop element carriesanimate-leave,loops.jsdefersrenderItems()behindanimationend/setTimeout, so the post-$set read sees a zero height delta and the compensation silently does nothing — the user sees a scroll jump once the deferred render lands. The code comment at src/directives/http.js:~533-542 overclaims that the rebuild is "both synchronous".Fix direction: make compensation robust to deferred renders (e.g. one-shot MutationObserver on the container's childList that performs the delta adjustment when the render actually lands, with disposal guard per CLAUDE.md safety rules), or an equivalent deterministic signal from the loop. Correct the comment either way. Tests must cover prepend WITH and WITHOUT animate-leave.