Files
brain-of-reese/.agent/phases/complete/49_retry_answer/00_phase.md
T
ducoterra 4971e2859d
Build and Push Containers / build-and-push-app (push) Successful in 12s
Build and Push Containers / build-and-push-db (push) Successful in 10s
chore(agent): track .agent/ planning tree in git
Remove the blanket .agent/ gitignore so the phase roadmap, user
stories, reports, and PLAN.md are versioned with the code. Only
runtime artifacts (.agent/phase-sessions/, .agent/pipeline.log)
remain ignored. Update AGENTS.md git protocol rule to match.
2026-09-01 10:18:22 -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 .agent/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 .agent/ frontend/ tests/ && git commit --no-gpg-sign -m "feat(chat): retry the last answer — redo-in-place Retry button on the latest brain bubble"