# Phase 21 — Thinking Window: No Scroll Back, Just Live **Source:** `TODO.md` L4 — *"Disable scroll in the thinking window. Users don't need to scroll back through thinking, just see it live."* **Story:** `.agents/user_stories/thinking-no-scroll.md` (created by task 02) **Context:** `frontend/assets/styles.css` — `details.thinking .thinking-text` (today: `max-height: 320px; overflow-y: auto;`, i.e. a user-scrollable 320px window, ~line 444); `frontend/assets/app.js` — the phase-17 thinking block (`ensureThinkingBlock`, the streaming `thinking` branch that appends chunks and already pins the stream to the bottom: `textEl.scrollTop = textEl.scrollHeight`, ~line 886), and the phase-14 restore path (stored `thinking` re-renders a **collapsed** block). ## Objective The live Thinking block is a scratchpad, not a transcript. The user must not be able to scroll back through it — the 320px window always shows the **live tail** of the reasoning stream (the existing per-chunk bottom-pinning stays). Wheel, drag, and keyboard scrolling on `.thinking-text` stop working; the stream itself keeps pinning to the bottom as chunks arrive. ## Owner-confirmed (2026-08-24, roadmap A2) 1. **Keep the 320px clip** — "just see it live" means the window stays a fixed 320px viewport showing the newest lines; no auto-height growth, no "↓ more" affordance. 2. **The answer bubble is untouched** — final answers keep their existing scroll behavior (phase 11 long answers). 3. **Restored (collapsed) Thinking blocks are untouched** — the phase-14 restore renders them collapsed, where overflow is moot. ## Design - **CSS (the whole functional change):** `details.thinking .thinking-text` — `overflow-y: auto` → `overflow-y: hidden`; keep `max-height: 320px`. `overflow: hidden` still permits **programmatic** scrolling (`scrollTop`), so the phase-17 pin (`textEl.scrollTop = textEl.scrollHeight` on every thinking chunk) keeps the window glued to the live tail — no JS change needed. Add a CSS comment: *no user scroll back (owner choice 2026-08-24): the window is a live tail only — the JS bottom-pin is the sole scroller*. - **No JS change** — the pin already exists; nothing else touches `.thinking-text` scroll. - **Non-goals:** no change to the answer bubble, the collapsed restore state, the summary/chevron, or the auto-collapse on first delta (phase 17). ## Dependencies - `17_thinking_display` (complete) — the block, the pin, the restore. - `18_follow_bottom_scroll` (complete) — no overlap (chat-page scroll gate only; the thinking window is a separate inner element). - `11_long_answers` (complete) — the untouched answer-bubble behavior. ## Tasks 1. `01_disable_thinking_scroll.md` — the CSS change + source-level unit pins. 2. `02_e2e_story_suite_commit.md` — `tests/e2e/test_thinking_no_scroll.py` (the story gate, isolated), regression suites, story file, final validation, the single atomic commit, phase move to `complete/`. ## Locked decisions - **A11 untouched** — no CDN, pure CSS. **A16 honored** — one new story E2E suite + adapted regressions. No anchor changed. ## Testing & Quality - **Unit (source-level, new `tests/unit/test_thinking_no_scroll.py`, repo source-pin pattern):** `styles.css` carries `details.thinking .thinking-text` with `overflow-y: hidden` and `max-height: 320px`; the phase-17 pin line (`textEl.scrollTop = textEl.scrollHeight`) still present in `app.js` (the live-tail mechanism must not be lost). - **Integration:** none (no `app/` changes). - **Coverage:** frontend-only; the >90% `app/` gate is unaffected. - **E2E:** `tests/e2e/test_thinking_no_scroll.py` (task 02), green **in isolation** (prereq `podman compose up -d db`). - **Lint/types:** `uv run ruff check . && uv run pyright` clean. ## Completion Criteria - [ ] With a long thinking stream, wheel/mouse-drag/keyboard on `.thinking-text` do **not** move it; the visible content is always the live tail (`scrollTop === scrollHeight` after each chunk, within 1px). - [ ] Computed style: `overflow-y: hidden`, `max-height: 320px`. - [ ] A long **answer** bubble still scrolls normally; a restored collapsed Thinking block still renders (phase 17 regression). - [ ] `uv run pytest` green; `uv run pytest --cov=app --cov-report=term-missing` ≥ today's number. - [ ] `uv run pytest tests/e2e/test_thinking_no_scroll.py -v --no-cov` green in isolation; regressions green in isolation: `test_thinking_display.py`, `test_long_answers.py`. - [ ] `uv run ruff check . && uv run pyright` clean. - [ ] UI Structure Check (AGENTS.md rule 5): no new surface; the block keeps its focus-visible summary, aria contract, and reduced-motion behavior. - [ ] `.agents/user_stories/thinking-no-scroll.md` exists. - [ ] One `--no-gpg-sign` commit (below); `.agents/phases/todo/21_thinking_no_scroll/` moved to `.agents/phases/complete/`. ## Commit ```bash git add -A .agents/ frontend/ tests/ && git commit --no-gpg-sign -m "fix(ui): thinking window no longer scrolls — live 320px view pinned to the stream tail" ```