feat: phases 77–80 — navbar view refresh, static background, API tokens, history suggestion chips
Build and Push Containers / build-and-push-app (push) Successful in 1m45s
Build and Push Containers / build-and-push-db (push) Successful in 13s

Single consolidated commit for four completed, validated phases (77, 78,
79, 80). The pipeline run left all work uncommitted because the harness
commits only with PHASE_COMMIT=1 while child executors are forbidden from
committing; the phases themselves all passed validation and moved to
.agents/phases/complete/.

Phase 77 — navbar view refresh
- router.js dispatches bor:view-refresh on re-show / active re-click /
  popstate (gated on wasMounted; first show and boot exempt)
- History / RAG / Sources / Tuning re-fetch on refresh (admin branch);
  Chat deliberately excluded (stream survival)
- History "Refresh" button (admin-only, in-flight disable + status line)
- New story suite tests/e2e/test_navbar_refresh.py (7 tests)

Phase 78 — static background
- Removed the animated glow layers; static 44px grid over the flat --bg
  canvas; default and reduced-motion renders byte-identical
- Updated background/theme E2E suites; removed bg-glow test pins

Phase 79 — API tokens
- api_tokens model + migration 0012; hash-only token service
- Admin tokens API + Tokens admin view; POST /api/token-auth;
  live-revoking require_user on chat / suggestions / document content
- Frontend token gate with localStorage cache; anonymous E2E suites
  migrated to token login
- New story suite tests/e2e/test_api_tokens.py (9 tests)

Phase 80 — history suggestion chips
- last_questions() endpoint with SEED fallback; startNewChat() refetch
- Seed-semantics docs (config.py, .env.example, README)
- Integration state matrix + E2E suite rewritten to the 4 chip states

Also included: phase-76 report artifacts and the repo restore-test-db
skill (previously untracked), scripts/* ruff fixes from phase 77.

Final gate state (phase 80 final pass, covers everything above):
- uv run pytest --cov=app → 1637 passed, 0 failed, app/ coverage 99%
- uv run ruff check . && uv run pyright → clean, 0 errors
- Per-phase story E2E suites green in isolation
This commit is contained in:
2026-09-07 12:39:01 -04:00
parent 495d042a98
commit 7fce6572d0
215 changed files with 10142 additions and 1643 deletions
@@ -0,0 +1,12 @@
All gates green. This was the final verification pass — every task (01–03) was already implemented in the working tree and its task files were already staged in `.agents/phases/complete/77_navbar_refresh/`; I verified the implementation against the task specs, the E2E suite, and the unit pins, and ran every completion criterion. No defects found; no fixes needed.
**Phase 77 — final verification report**
- Verified (already implemented in working tree): `bor:view-refresh` dispatch in `router.js` (re-show + active re-click + popstate, `wasMounted` pre-mount gate, first-show/boot exempt); re-entrant re-fetch in History/RAG/Sources/Tuning (admin-branch listeners, Chat excluded with pinning comment); `#history-refresh` button (page-head, admin-only, in-flight disable + `#history-status` announce); unit pins in `test_frontend_router.py`; new story suite `test_navbar_refresh.py` (7 tests incl. sentinel, no-pushState, request-log, stream-survival control).
- `uv run pytest tests/e2e/test_navbar_refresh.py -v --no-cov` → **7 passed** (17.6s, isolated, DB up). ✅
- `uv run pytest tests/e2e/test_nav_switch_keeps_stream.py -v --no-cov` → **4 passed**; file byte-identical (no git diff). ✅
- `uv run pytest --cov=app --cov-report=term-missing` → **1575 passed**, TOTAL coverage **99%** (>90% floor). ✅
- `uv run ruff check . && uv run pyright` → clean (0 errors). ✅
- Commit/phase-dir move: left to the harness per executor rules (task files already in `complete/`; no `git add`/`commit` run by me).
- Notable: pre-existing uncommitted changes to `scripts/*` and phase-76 report artifacts are in the tree from earlier work — untouched, will ride along in the harness commit.
- Next pending phase: `78_static_background`.
@@ -0,0 +1,78 @@
........................................................................ [ 4%]
........................................................................ [ 9%]
........................................................................ [ 13%]
........................................................................ [ 18%]
........................................................................ [ 22%]
........................................................................ [ 27%]
........................................................................ [ 32%]
........................................................................ [ 36%]
........................................................................ [ 41%]
........................................................................ [ 45%]
........................................................................ [ 50%]
........................................................................ [ 54%]
........................................................................ [ 59%]
........................................................................ [ 64%]
........................................................................ [ 68%]
........................................................................ [ 73%]
........................................................................ [ 77%]
........................................................................ [ 82%]
........................................................................ [ 86%]
........................................................................ [ 91%]
........................................................................ [ 96%]
............................................................... [100%]
=============================== warnings summary ===============================
.venv/lib/python3.13/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.13.13-final-0 _______________
Name Stmts Miss Cover
-----------------------------------------------
app/__init__.py 1 0 100%
app/api/__init__.py 0 0 100%
app/api/auth.py 22 0 100%
app/api/chat.py 177 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 7 0 100%
app/api/doc_drafts.py 93 0 100%
app/api/docs.py 50 0 100%
app/api/git_sources.py 212 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 101 0 100%
app/config.py 140 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 108 0 100%
app/core/debugging.py 29 2 93%
app/core/docs_push.py 39 0 100%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 60 0 100%
app/models.py 86 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 222 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 180 3 98%
app/rag/llm.py 216 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 88 0 100%
app/rag/retriever.py 150 3 98%
app/rag/scaffolding.py 55 0 100%
app/rag/source_removal.py 41 0 100%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 210 0 100%
-----------------------------------------------
TOTAL 2997 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK
@@ -0,0 +1,19 @@
Task 01 complete. All gates green.
**Implemented**
- `frontend/assets/router.js`: `switchTo` captures `const wasMounted = mounted[name]` before the mount block and dispatches `bor:view-refresh` on the view's section after show + head/nav state (before the focus tail), gated on `wasMounted` — first show and boot never fire it; popstate inherits the gate. The `name === current` re-click branch now dispatches the event on `viewEls[name]` and returns (no `pushState`, menu-close unchanged). Header contract comment updated.
- `frontend/assets/history.js`: `loadChats()` is re-entrant (drops every `tr` except `#history-empty-row` before fetching — replaces, never duplicates); the ADMIN branch (after the whoami gate) arms `root.addEventListener("bor:view-refresh", () => { if (started) loadChats(); })` with `started` flipping true at the first `loadChats()`; anonymous branch never arms a listener.
- `tests/unit/test_frontend_router.py`: 3 new source pins — event literal + dispatch inside the pre-mount `wasMounted` capture with visible→refresh→focus ordering; re-click branch dispatches (no pushState/switchTo); history listener admin-branch-only + gated + row-clearing precedes fetch.
- Fixed 9 pre-existing ruff errors in `scripts/` (left by commit f221b10) so the gate is green.
**Results**
- `uv run pytest tests/unit/test_frontend_router.py -v` → 16 passed
- `uv run pytest` → 1568 passed
- `uv run pytest --cov=app --cov-report=term-missing` → TOTAL 99% (>90% floor)
- `uv run ruff check . && uv run pyright` → clean
- `uv run pytest tests/e2e/test_nav_switch_keeps_stream.py -v --no-cov` → 4 passed (phase-76 stream-survival contract holds with the hook live, runs the new router code in a real browser)
- `node --check` on both edited JS files → OK
**Decisions**: followed the phase design exactly (gate on `wasMounted` only — boot-onto-chat dispatch is harmless since Chat never listens); optional manual spot-check covered by the phase-76 E2E + syntax checks (the dedicated freshness E2E lands in task 03). No deviations.
**Next pending task**: `.agents/phases/todo/77_navbar_refresh/02_refresh_other_views.md`
@@ -0,0 +1,78 @@
........................................................................ [ 4%]
........................................................................ [ 9%]
........................................................................ [ 13%]
........................................................................ [ 18%]
........................................................................ [ 22%]
........................................................................ [ 27%]
........................................................................ [ 32%]
........................................................................ [ 36%]
........................................................................ [ 41%]
........................................................................ [ 45%]
........................................................................ [ 50%]
........................................................................ [ 55%]
........................................................................ [ 59%]
........................................................................ [ 64%]
........................................................................ [ 68%]
........................................................................ [ 73%]
........................................................................ [ 78%]
........................................................................ [ 82%]
........................................................................ [ 87%]
........................................................................ [ 91%]
........................................................................ [ 96%]
........................................................ [100%]
=============================== warnings summary ===============================
.venv/lib/python3.13/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.13.13-final-0 _______________
Name Stmts Miss Cover
-----------------------------------------------
app/__init__.py 1 0 100%
app/api/__init__.py 0 0 100%
app/api/auth.py 22 0 100%
app/api/chat.py 177 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 7 0 100%
app/api/doc_drafts.py 93 0 100%
app/api/docs.py 50 0 100%
app/api/git_sources.py 212 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 101 0 100%
app/config.py 140 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 108 0 100%
app/core/debugging.py 29 2 93%
app/core/docs_push.py 39 0 100%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 60 0 100%
app/models.py 86 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 222 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 180 3 98%
app/rag/llm.py 216 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 88 0 100%
app/rag/retriever.py 150 3 98%
app/rag/scaffolding.py 55 0 100%
app/rag/source_removal.py 41 0 100%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 210 0 100%
-----------------------------------------------
TOTAL 2997 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK
@@ -0,0 +1,18 @@
All green. Final report:
**Implemented (task 02 — RAG/Sources/Tuning join the refresh, Chat stays out):**
- `sources.js`: `loadDocs()` re-entrant — `tbody.replaceChildren()` moved to the top (before fetch; removed the redundant populated-path clear) so populated→empty refreshes leave no ghost rows; `bor:view-refresh` listener armed in the admin branch after the whoami gate
- `git-sources.js`: listener `() => loadSources()` in admin branch; verified a re-call resets all three states (success path runs `hideLoadError()` before `renderSources`, which replaces the tbody)
- `tuning.js`: listener `() => loadNotes()` in admin branch; failed-refresh keeps last rendered list (documented contract, unchanged)
- `app.js`: NO listener — one-line comment at the module-scope state pinning the deliberate exclusion (phase-76 stream survival)
- `tests/unit/test_frontend_router.py`: 4 new pins — per-view listener + gate ordering + re-entrancy checks, plus the app.js negative pin (targets the listener, not the literal, since the exclusion comment carries the literal)
**Results:**
- `uv run pytest tests/unit/test_frontend_router.py -v --no-cov` → 20 passed
- `uv run pytest --cov=app --cov-report=term-missing` → 1572 passed; `app/` coverage 99% (>90%)
- `uv run ruff check . && uv run pyright` → clean (0 errors)
- `uv run pytest tests/e2e/test_nav_switch_keeps_stream.py -v --no-cov` → 4 passed (unchanged, stream-survival holds)
**Decisions:** git-sources listener placed before `await loadSources()` to preserve the existing "LAST statement" unit pin; no `started` flag needed (listener armed post-gate, per task text).
**Next pending task:** `77_navbar_refresh/03_history_refresh_button.md` (History Refresh button + story E2E suite + regression sweep).
@@ -0,0 +1,78 @@
........................................................................ [ 4%]
........................................................................ [ 9%]
........................................................................ [ 13%]
........................................................................ [ 18%]
........................................................................ [ 22%]
........................................................................ [ 27%]
........................................................................ [ 32%]
........................................................................ [ 36%]
........................................................................ [ 41%]
........................................................................ [ 45%]
........................................................................ [ 50%]
........................................................................ [ 54%]
........................................................................ [ 59%]
........................................................................ [ 64%]
........................................................................ [ 68%]
........................................................................ [ 73%]
........................................................................ [ 77%]
........................................................................ [ 82%]
........................................................................ [ 87%]
........................................................................ [ 91%]
........................................................................ [ 96%]
............................................................ [100%]
=============================== warnings summary ===============================
.venv/lib/python3.13/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.13.13-final-0 _______________
Name Stmts Miss Cover
-----------------------------------------------
app/__init__.py 1 0 100%
app/api/__init__.py 0 0 100%
app/api/auth.py 22 0 100%
app/api/chat.py 177 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 7 0 100%
app/api/doc_drafts.py 93 0 100%
app/api/docs.py 50 0 100%
app/api/git_sources.py 212 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 101 0 100%
app/config.py 140 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 108 0 100%
app/core/debugging.py 29 2 93%
app/core/docs_push.py 39 0 100%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 60 0 100%
app/models.py 86 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 222 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 180 3 98%
app/rag/llm.py 216 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 88 0 100%
app/rag/retriever.py 150 3 98%
app/rag/scaffolding.py 55 0 100%
app/rag/source_removal.py 41 0 100%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 210 0 100%
-----------------------------------------------
TOTAL 2997 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK
@@ -0,0 +1,19 @@
Everything is complete and verified. Final state of all gates (run in the final file state):
**Implemented (task 03):**
- `frontend/index.html` — History `.page-head` is now a flex row (title block left, actions right): `#history-refresh` button with the house inline-SVG refresh glyph (`aria-hidden`) + visible "Refresh" label, `aria-label="Refresh saved chats"`, outside the table wrap
- `frontend/assets/history.js` — admin-branch binding: click → disable → `loadChats()` → announce `Saved chats refreshed.` (0-row = success) / failure lines (`Couldn't load saved chats — is the app reachable?` / `— try again.` now live inside `loadChats`, so every caller sees them) → re-enable in `finally`; anonymous branch hides the button (no dead control)
- `frontend/assets/styles.css` — `.history-refresh` reuses the `.new-chat-btn` language (brand pill 5.2:1, ≥44px, hover, `:disabled`, global focus-visible); `#view-history .page-head` flex row scoped (other four views untouched); icon-only ≤640px (phase-46 convention)
- `tests/unit/test_frontend_router.py` — 3 new source pins (markup placement, admin-only binding + outcome lines, CSS language/mobile)
- `tests/e2e/test_navbar_refresh.py` — new story suite, 7 tests: re-show re-fetch (+ no-duplicates + same-doc sentinel), active re-click (no pushState, `history.length` unchanged), refresh button (disabled in-flight via the house request-hold pattern, status line, re-enable, keyboard focus), popstate re-fetch, four-views request-log (+History row-delta), stream-survival control (full mock answer + settled `query_log`), API row-shape sanity
**Test / lint / coverage results:**
- `uv run pytest tests/e2e/test_navbar_refresh.py -v --no-cov` → 7 passed (isolated, DB up)
- `uv run pytest tests/e2e/test_nav_switch_keeps_stream.py -v --no-cov` → 4 passed, unchanged
- `uv run pytest --cov=app --cov-report=term-missing` → 1575 passed, TOTAL 99% (>90% floor)
- `uv run ruff check . && uv run pyright` → clean
- Regression sweep green: `test_chat_history`, `test_share_chat`, `test_history_copy` (10), `test_stale_saved_chats`+`test_llm_history` (6), header/nav/cache/persistence (23), `test_hidden_tab_stream`+`test_stop_generation` (7)
**Decisions/deviations:** failure announce moved into `loadChats` (no existing load-failure copy existed — house "reachable?/try again." family reused, and the §7.4 contract improved for all callers); anonymous hides the button (task's "admin branch only" read as gate-gated control, not a dead button); E2E request-log polling must use `page.wait_for_timeout` (sync API starves `page.on` events under raw `time.sleep` — documented in `_wait_until`); per harness rules the atomic commit + phase-dir move are left to the harness (task's commit item intentionally not executed).
**Next pending task:** none in phase 77 (task 03 was the last); next phase in `todo/` is `78_static_background`.
@@ -0,0 +1,78 @@
........................................................................ [ 4%]
........................................................................ [ 9%]
........................................................................ [ 13%]
........................................................................ [ 18%]
........................................................................ [ 22%]
........................................................................ [ 27%]
........................................................................ [ 32%]
........................................................................ [ 36%]
........................................................................ [ 41%]
........................................................................ [ 45%]
........................................................................ [ 50%]
........................................................................ [ 54%]
........................................................................ [ 59%]
........................................................................ [ 64%]
........................................................................ [ 68%]
........................................................................ [ 73%]
........................................................................ [ 77%]
........................................................................ [ 82%]
........................................................................ [ 86%]
........................................................................ [ 91%]
........................................................................ [ 96%]
............................................................... [100%]
=============================== warnings summary ===============================
.venv/lib/python3.13/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.13.13-final-0 _______________
Name Stmts Miss Cover
-----------------------------------------------
app/__init__.py 1 0 100%
app/api/__init__.py 0 0 100%
app/api/auth.py 22 0 100%
app/api/chat.py 177 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 7 0 100%
app/api/doc_drafts.py 93 0 100%
app/api/docs.py 50 0 100%
app/api/git_sources.py 212 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 101 0 100%
app/config.py 140 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 108 0 100%
app/core/debugging.py 29 2 93%
app/core/docs_push.py 39 0 100%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 60 0 100%
app/models.py 86 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 222 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 180 3 98%
app/rag/llm.py 216 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 88 0 100%
app/rag/retriever.py 150 3 98%
app/rag/scaffolding.py 55 0 100%
app/rag/source_removal.py 41 0 100%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 210 0 100%
-----------------------------------------------
TOTAL 2997 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK