# Story: Chat Survives a Refresh (localStorage) **Phase:** `14_chat_persistence.md` · **E2E:** `tests/e2e/test_chat_persistence.py` ## Narrative As **a user**, I want my conversation to **survive a browser refresh** and a trip to another page — the previous session should be waiting for me when I come back. - **Given** I have asked a few questions - **When** I refresh the page (or go to Sources and come back) - **Then** the whole conversation is restored: my questions, Brain's answers (rendered markdown), the source chips, and deflected answers with their "Maybe try" chips — amber style included. ## Acceptance criteria 1. Conversation state (user + brain messages, with sources/deflection/ suggestions metadata) is stored in `localStorage` under a versioned key; user messages are saved when sent, brain answers when the turn completes. 2. On load, stored messages are re-rendered (markdown, source chips, deflected styling + maybe-try chips); the empty state is hidden when a conversation exists. 3. "New chat" control (chat header) clears the stored conversation and returns to the empty state with suggestions. 4. Storage failures (private mode / quota) degrade silently — chat still works, nothing throws. 5. Size-bounded: oldest messages are dropped if the serialized conversation outgrows the quota budget. 6. Unit + integration green, `app/` coverage >90%, story E2E green in isolation, one `--no-gpg-sign` commit. ## Playwright Mapping Rule **Test Scenario → `tests/e2e/test_chat_persistence.py`** (mock LLM, seeded KB): 1. `test_conversation_survives_reload` — ask → answer with source chip → `page.reload()` → both bubbles restored (text + chip href), empty state hidden. 2. `test_deflected_turn_restores_styling` — off-topic question → deflected answer → reload → amber bubble + "Maybe try" chips back. 3. `test_new_chat_clears_conversation` — with a conversation, "New chat" → messages gone, empty state + suggestions back, storage key cleared. 4. `test_persists_across_page_navigation` — ask → go to Sources → back to `/` → conversation still there.