Files
brain-of-reese/.agents/phases/complete/49_retry_answer/00_phase.md
T
ducoterra dbf2af26c6 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.
2026-09-05 10:57:07 -04:00

3.3 KiB

Phase 49 — Retry the Last Answer (Redo)

Source: TODO.md L4 — "Need a retry button to retry the last answer, like a redo button" Story: n/a (TODO-derived — owner roadmap confirmation 2026-08-29) Context: frontend/assets/app.js — handleSend owns the whole turn (user-bubble append + conversation push → fetch/SSE → save points), appendTuneButton is the house pattern for a per-bubble meta-row action (reuses the .msg-meta row, the role=list → role=listitem rule, the admin gate), conversation/rememberBrainTurn hold the persisted records, and phase 48's Stop button means the last brain bubble can be a stopped partial — the natural retry candidate.

Objective

A Retry button on the last brain answer re-asks the preceding question in place — the old answer is removed (DOM + persisted record), the fresh answer streams into its place, and the conversation never duplicates the question.

Dependencies

  • 48_stop_generation (todo) — the button/state-machine work it builds on (the meta-row button family, the in-flight guard) and the stopped partials it makes retryable.
  • 14_chat_persistence (complete) — the conversation records the retry edits in place.

Tasks

  1. 01_retry_button.md — the runTurn extraction + the Retry button + redo-in-place semantics + CSS.
  2. 02_e2e_retry_answer.md — the story Playwright suite + regressions + commit.

Testing & Quality

  • Frontend source pins (house pattern): the runTurn(text, {reask}) extraction (reask skips the user append/push), last-bubble-only Retry management, the redo-in-place record edit, the in-flight no-op.
  • Coverage: >90% on app/ (unchanged — frontend-only phase).
  • E2E (mandatory, A16): tests/e2e/test_retry_answer.py, run in isolation.

Completion Criteria

  • The last brain bubble (completed, deflected, empty-fallback, or stopped partial — admin and anonymous alike) carries a Retry button; earlier brain bubbles do not.
  • Clicking Retry removes the old answer (DOM + bor.chat.v1 record), re-sends the preceding question without duplicating it, and streams the fresh answer into its place; the new answer carries the Retry button (it is the new last).
  • While a turn is in flight, Retry does nothing (no double turn).
  • uv run pytest green; coverage TOTAL unchanged (>90%).
  • uv run pytest tests/e2e/test_retry_answer.py -v --no-cov green in isolation (DB up).
  • Regression E2E suites green in isolation: test_chat_rag.py, test_chat_persistence.py, test_stop_generation.py.
  • uv run ruff check . && uv run pyright clean.
  • One --no-gpg-sign commit; phase dir moved to .agents/phases/complete/.

Locked decisions

  • Owner-locked (2026-08-29, roadmap confirmation): redo-in-place (the old answer is replaced, the question is not duplicated); only the last brain bubble is retryable; Retry is available to all visitors (chat is public — unlike Tune, which is admin-only); inert while a turn is in flight.
  • A10 untouched — retry is a fresh POST /api/chat (the API stays stateless).
  • A16/A17 honoured — one story E2E suite, one atomic commit.

Commit

git add -A .agents/ frontend/ tests/ && git commit --no-gpg-sign -m "feat(chat): retry the last answer — redo-in-place Retry button on the latest brain bubble"