refactor(agents): migrate .agent/ planning tree to .agents/
Standardize on the .agents/ directory (shared with project skills): phases/, user_stories/, reports/, screenshots/, validate.sh, and phase-sessions/ + pipeline.log all move to .agents/ (git mv preserves history; runtime artifacts move alongside). Updates every reference in AGENTS.md, README.md, .gitignore, app docstrings, and test story headers. Historical KB content in data/ and the runtime pipeline.log transcript are left untouched.
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# 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"
|
||||
```
|
||||
@@ -0,0 +1,57 @@
|
||||
# Task 01 — styles.css: `.thinking-text` overflow hidden (no user scroll)
|
||||
|
||||
**Phase:** `21_thinking_no_scroll` · **Source:** `TODO.md` L4 —
|
||||
*"Disable scroll in the thinking window. Users don't need to scroll back
|
||||
through thinking, just see it live."*
|
||||
|
||||
## Objective
|
||||
One CSS property change makes the Thinking window a live-tail-only view:
|
||||
`overflow-y: hidden` instead of `auto`, keeping the 320px clip. The
|
||||
phase-17 JS bottom-pin (which keeps working under `overflow: hidden`) is
|
||||
the sole scroller.
|
||||
|
||||
## Work
|
||||
1. `frontend/assets/styles.css` — in the phase-17 thinking block
|
||||
section (~line 444):
|
||||
```css
|
||||
details.thinking .thinking-text {
|
||||
padding: 0 0.75rem 0.75rem;
|
||||
color: var(--ink-soft); /* 6.9:1 on --surface */
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.55;
|
||||
max-height: 320px;
|
||||
overflow-y: hidden; /* no scroll back (owner choice 2026-08-24):
|
||||
the window is a live tail only — the phase-17
|
||||
JS bottom-pin (scrollTop = scrollHeight per
|
||||
chunk) is the sole scroller */
|
||||
}
|
||||
```
|
||||
(Only the `overflow-y` value + comment change; every other declaration
|
||||
stays byte-identical.)
|
||||
2. `frontend/assets/app.js` — **no change expected.** Verify the pin is
|
||||
intact: the streaming `thinking` branch still does
|
||||
`textEl.scrollTop = textEl.scrollHeight` on every chunk (~line 886).
|
||||
If (and only if) the pin were missing/broken, fix it — do not remove
|
||||
or alter any other scrolling behavior.
|
||||
3. `tests/unit/test_thinking_no_scroll.py` (new — repo source-pin
|
||||
pattern):
|
||||
- `styles.css`: the `details.thinking .thinking-text` rule contains
|
||||
`overflow-y: hidden` and `max-height: 320px` (no `overflow-y: auto`
|
||||
left in that rule).
|
||||
- `app.js`: the bottom-pin line
|
||||
`textEl.scrollTop = textEl.scrollHeight` is still present (the
|
||||
live-tail mechanism).
|
||||
4. Manual smoke (dev server): stream a long thinking turn; try to wheel /
|
||||
drag / Tab+ArrowDown inside the Thinking block — it must not move;
|
||||
the newest chunk is always the one visible at the bottom.
|
||||
|
||||
## Testing & Quality
|
||||
- `uv run pytest tests/unit/test_thinking_no_scroll.py -v` green.
|
||||
- `uv run ruff check . && uv run pyright` clean.
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] `.thinking-text` is `overflow-y: hidden`, `max-height: 320px`, with
|
||||
the owner-choice comment.
|
||||
- [ ] The JS bottom-pin is verified intact (no app.js diff unless the
|
||||
pin was broken).
|
||||
- [ ] Unit pins green; lint/types clean; manual smoke passed.
|
||||
Reference in New Issue
Block a user