TODO.md L5: "Get rid of the chat reply autoscroll, it's breaking things
like making it impossible for the user to scroll while a reply
generates." Owner direction 2026-08-27 (roadmap A1) revises the
phase-18 follow-the-bottom choice: the page NEVER auto-scrolls while a
turn streams. Kept (owner decision): the submit reveal (the user's own
message) and the one-shot phase-14 restore landing.
- frontend/assets/app.js: delete NEAR_BOTTOM_PX + isNearBottom;
scrollReveal becomes the one unconditional scrollIntoView (still
smooth, still "auto" under prefers-reduced-motion via SCROLL);
addMessage(who, html, scroll = false) carries an explicit scroll
intent — only the submit (", true") and the two restore landings
scroll. The thinking/tool/delta handlers and the typing indicator
drop their page-scroll calls; the thinking block's INTERNAL
bottom-pin (textEl.scrollTop, phase 17 — reworked separately in
phase 43) and the turn-end focus({ preventScroll: true }) survive.
- tests/unit/test_frontend_scroll.py: rewritten pin for the new
contract — phase-18 gate absent, helper unconditional, explicit
intent at submit/restore, no page-scroll call in the streaming
handlers, typing bubble scroll-free, SCROLL reduced-motion intact.
- tests/unit/test_chat_persistence.py: restore-landing pin updated to
the new signature (the old forced "auto" is gone; the landing
rides the default SCROLL — noted at the call site).
- tests/e2e/test_no_reply_autoscroll.py (new, replaces the deleted
test_follow_bottom_scroll.py): no autoscroll across >=10 samples
(1px tolerance) during a long answer and during the thinking stream;
submit-from-the-top still reveals the user message; the restore
landing lands one-shot on the latest message and stays; long answer
+ sources and the collapsed thinking block persist and restore.
E2E (isolation): test_no_reply_autoscroll.py 5/5; regressions
test_chat_rag 3/3, test_thinking_display 5/5,
test_chat_persistence 4/4, test_long_answers 2/2, test_smoke 3/3;
unit+integration 723 passed, app/ coverage 99%; ruff + pyright clean.