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.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# 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-deflected` styling, 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 `localStorage` access 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
|
||||
1. `frontend/assets/app.js`: conversation model + save/restore/clear as
|
||||
above; wire into `handleSend` (push+save user on send; push+save
|
||||
brain on `done`); "New chat" handler.
|
||||
2. `frontend/index.html`: `#new-chat-btn` in `.header-inner` after the
|
||||
nav (chat page only); live-region text reuse for clear confirmation.
|
||||
3. `frontend/assets/styles.css`: `.new-chat-btn` (Phase-08 tokens,
|
||||
focus-visible, ≥44px, hover like `.nav-link`).
|
||||
4. **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.py` per 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.py` green in isolation (fresh contexts start
|
||||
with the empty state exactly as before).
|
||||
- Coverage gate unchanged (frontend-only phase).
|
||||
|
||||
## Commit
|
||||
```bash
|
||||
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"
|
||||
```
|
||||
Reference in New Issue
Block a user