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.
2.9 KiB
2.9 KiB
Phase 14 — Chat Survives a Refresh (localStorage)
Story: .agent/user_stories/chat-persistence.md
Context: owner report 2026-08-22 — "the chat disappears as soon as
the browser refreshes. It should use local storage to track previous
sessions."
Goal
The conversation is a durable local session: refresh, tab close, or a trip to Sources and back — the chat comes back exactly as left.
Design
- Storage key
bor.chat.v1(versioned; a format bump = clean start). - Value:
{v: 1, messages: [{who: "user"|"brain", text, sources?, deflected?, suggestions?}]}— raw text (re-rendered through the existing escape-first markdown on restore; never stored HTML). - Save points: user message on send; brain message on
done(with sources/deflected/suggestions). A failed turn keeps the user message (the question is not lost) — consistent with the "never stale" contract. - Restore on load: re-render messages (user bubble; brain bubble with
source chips,
is-deflectedstyling, maybe-try chips), hide the empty state when non-empty. - Size bound: if the serialized state exceeds ~700k chars, drop oldest messages until it fits (localStorage quota is ~5MB; stay well under).
- Failure-safe: every
localStorageaccess in try/catch (private mode, quota) — chat keeps working with in-memory state only. - "New chat" button in the chat header (
#new-chat-btn, ghost pill like a nav link, ≥44px, accessible name): clears the key + the message list, restores the empty state with suggestions.
Implementation steps
frontend/assets/app.js: conversation model + save/restore/clear as above; wire intohandleSend(push+save user on send; push+save brain ondone); "New chat" handler.frontend/index.html:#new-chat-btnin.header-innerafter the nav (chat page only); live-region text reuse for clear confirmation.frontend/assets/styles.css:.new-chat-btn(Phase-08 tokens, focus-visible, ≥44px, hover like.nav-link).- PLAN §7.5: new component ids (
#new-chat-btn); §7.4 note: persistence is local-only (A10 stateless API unchanged — no server session).
Locked decisions
A10 (stateless API) untouched — persistence is browser-local only.
A11 untouched (no library — raw localStorage JSON).
Testing & Quality
- E2E:
tests/e2e/test_chat_persistence.pyper the story mapping (fresh page fixture = fresh context, so tests are isolated by construction). - Regression:
test_chat_rag.py,test_suggestion_chips.py,test_loading_feedback.pygreen in isolation (fresh contexts start with the empty state exactly as before). - Coverage gate unchanged (frontend-only phase).
Commit
git add -A .agent/ frontend/ tests/e2e/test_chat_persistence.py && git commit --no-gpg-sign -m "feat(ui): persist the chat conversation in localStorage — survives refresh and navigation, with a New chat reset"