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,42 @@
# Phase 78 — Static background (the animated glow layers are removed)
**Source:** `TODO.md` L4 — "Remove the animated css background, it's too resource intensive"
**Story:** n/a (TODO-derived — supersedes the fading-glow contract of `.agents/user_stories/background-no-motion.md` (phase 25), which itself superseded `background-animation.md` (phase 08))
**Context:** `frontend/assets/styles.css` (the background block, ~lines 70–155: the STATIC grid texture on `body::before`, the three opacity-fading glow spots on `body::after` / `html::before` / `html::after`, the `@keyframes bg-glow-a/b/c` blocks, and the `prefers-reduced-motion` rule that stills those layers), `tests/unit/test_background_animation.py` + `tests/unit/test_background_no_motion.py` (source-level pins of the glow contract), `tests/e2e/test_background_no_motion.py` (the phase-25 suite — computed-style fade assertions) + `tests/e2e/test_background_animation.py` (the phase-22 E2E repurposed as the phase-25 no-motion regression — same story, `background-no-motion.md` — its fade assertions directly contradicted by the new contract), `tests/e2e/test_dark_tech_theme.py` (palette assertions — must stay green UNCHANGED), `frontend/assets/themes/` (configurable theme files — the built-in palette is the scope; verify they carry no glow rules).
## Objective
Delete the animated background: the three opacity-fading glow pseudo-layers and their keyframes stop existing — the owner reports they are too resource-intensive (the infinite CSS animations run continuously on every page, in every tab). The background becomes fully static: the 44px grid texture stays (it is static — zero animation cost).
## Owner decisions (chat, 2026-09-06 — recorded per AGENTS.md rule 3)
- **A2 confirmed:** "the animated css background" = the three fading glow spots (the ONLY animated part of the background). The static grid (`body::before`) STAYS. If the owner later wants the grid gone too, that is a one-line follow-up — out of scope here.
- Other UI animations (the mobile nav slide, modal fades, typing dots, …) are NOT the background — they stay untouched.
## Design (shared by both tasks)
- `body::before` (the grid) stays BYTE-IDENTICAL: 44px cells, 1px lines at 60% `--line` alpha, the widened radial mask.
- Deleted from `styles.css`: the `body::after`, `html::before`, and `html::after` glow rules; the three `@keyframes bg-glow-*` blocks; the `prefers-reduced-motion` rule whose only job was stilling these background layers — FIRST verify it references nothing else (if any non-background selector sits in it, strip only the background selectors).
- The block's comment header (the phase-08/25 owner-direction prose) is replaced with a 3–4 line phase-78 note: the animated layers were removed at owner direction (TODO.md L4) as too resource-intensive; the static grid remains.
- **Test rewrites (the house pattern — the premise changed, so the suites pin the NEW contract; the phase-76 precedent rewrote the phase-20 suite the same way):**
- `tests/unit/test_background_no_motion.py` → rewritten as the static-contract source pin: no `@keyframes bg-glow-*` in `styles.css`; none of the four pseudo-element selectors (`body::before/after`, `html::before/after`) carries an `animation:` declaration; `body::before` (the grid) is present with its 44px `background-size` and no animation.
- `tests/unit/test_background_animation.py` → **DELETED** (the phase-25 unit source-pin suite — its entire premise, three fading glows / exactly three `bg-glow-*` keyframe blocks, is gone; superseded chain 08 → 25 → 78).
- `tests/e2e/test_background_no_motion.py` → rewritten: Playwright computed-style checks — the three glow pseudo-elements report `animation-name: none` and no background-image; `body::before` still carries the grid background. Docstring updated to the phase-78 contract.
- `tests/e2e/test_background_animation.py` → **DELETED** (the phase-22 E2E repurposed as the phase-25 regression — its premise, that the glow layers fade, is removed; its story (`background-no-motion.md`) is carried on by the rewritten `test_background_no_motion.py`, the single story suite going forward).
- `tests/e2e/test_dark_tech_theme.py` must stay green UNCHANGED — the PALETTE is untouched; only the light spots go.
- `tests/unit/test_themes.py` + `frontend/assets/themes/indigo.css` — verify no glow/keyframe carry-over; if a theme file re-introduces animated background layers, the owner's direction applies to the whole background (report before deviating — the built-in palette is the confirmed scope).
## Dependencies
— (none)
## Tasks
1. `01_remove_glow_layers.md` — the CSS deletion + the four test-file rewrites/deletions.
2. `02_regression_sweep_commit.md` — theme + smoke E2E, the visual check, the full gate, the atomic commit.
## Testing & Quality
- Unit: the rewritten source-pin file + `tests/unit/test_themes.py` green.
- E2E: the rewritten static-background suite in isolation (DB up) + `test_dark_tech_theme.py` + `test_smoke.py` unchanged-green.
- Coverage: **>90%** on `app/` (CSS-only phase — the floor is preserved).
## Completion Criteria
- [ ] No `animation` / `@keyframes` remains for the background in `styles.css` (`rg "bg-glow" frontend/ tests/ app/` → zero hits); the grid renders as before (visual check in a real browser).
- [ ] The rewritten suites are green; the deleted suites are gone; `test_dark_tech_theme.py` green UNCHANGED.
- [ ] `uv run pytest` green; `uv run pytest --cov=app --cov-report=term-missing` >90%; `uv run ruff check . && uv run pyright` clean.
- [ ] One atomic `--no-gpg-sign` Conventional-Commits commit (e.g. `perf(ui): remove the animated background glow layers — static grid only`); phase dir moved to `.agents/phases/complete/`.
@@ -0,0 +1,25 @@
# Task 01 — Delete the glow layers + keyframes; re-pin the background contract
**Phase:** `78_static_background` · **Source:** `TODO.md:4` — "Remove the animated css background, it's too resource intensive"
**Story:** n/a (TODO-derived)
## Objective
The animated background no longer exists: the three glow pseudo-layers, their keyframes, and their reduced-motion rule are deleted from `styles.css`, and the unit/e2e background suites are rewritten to pin the new static contract (or deleted where the premise is gone).
## Work
1. `frontend/assets/styles.css` — delete the three glow rules (`body::after`, `html::before`, `html::after`), the `@keyframes bg-glow-a` / `bg-glow-b` / `bg-glow-c` blocks, and the `prefers-reduced-motion` block that stills the background — the file carries EIGHT `@media (prefers-reduced-motion: reduce)` blocks; delete the ONE that contains only `body::before, body::after, html::before, html::after { animation: none; }` (~line 1353) whole, and leave the other seven (typing dots, spinner, toasts, nav slide, etc. — unrelated UI) untouched. Keep the `body::before` grid rule byte-identical (44px cells, the 60% `--line` alpha gradients, the radial mask). Replace the large phase-08/25 comment header with a 3–4 line phase-78 note: owner direction (TODO.md L4) — the animated background was removed as too resource-intensive; the static grid remains.
2. `tests/unit/test_background_no_motion.py` — rewrite to the static contract (source-level, house pattern): `styles.css` contains no `@keyframes bg-glow-*`; none of `body::before` / `body::after` / `html::before` / `html::after` carries an `animation:` declaration (assert the three glow selectors are ABSENT or animation-free — they will be absent); `body::before` is present with `background-size: 44px 44px` and no animation. Update the docstring to the phase-78 contract.
3. DELETE `tests/unit/test_background_animation.py` (the phase-25 unit source-pin suite — its premise, exactly three fading glows with named keyframe cycles, is removed; superseded chain 08 → 25 → 78).
4. `tests/e2e/test_background_no_motion.py` — rewrite: Playwright computed-style checks on a loaded page — `body::before` still carries the grid (background-image non-empty, animation-name `none`); `body::after`, `html::before`, `html::after` report no background-image and `animation-name: none` (or the pseudo-element has no box). Update the docstring.
5. DELETE `tests/e2e/test_background_animation.py` (the phase-22 E2E repurposed as the phase-25 no-motion regression — its fade assertions contradict the new contract; the story `background-no-motion.md` is carried on by the rewritten `test_background_no_motion.py`).
6. Verify nothing else references the removed names: `rg "bg-glow" app/ frontend/ tests/` → zero hits; `tests/unit/test_themes.py` and `frontend/assets/themes/*.css` do not re-introduce glow/animated-background rules (grep for `bg-glow` / `@keyframes` on background selectors — report before deviating if a theme file carries them).
## Testing & Quality
- Unit: the rewritten pin file (item 2) + `tests/unit/test_themes.py` green.
- E2E: the rewritten suite (item 4) in isolation (DB up): `uv run pytest tests/e2e/test_background_no_motion.py -v --no-cov`.
- Coverage: n/a (CSS only) — the `app/` floor preserved.
## Completion Criteria
- [ ] `rg "bg-glow" frontend/ tests/ app/` → no hits; the three glow rules + keyframes are gone from `styles.css`; the grid rule is untouched.
- [ ] Rewritten unit + e2e suites green; the two animation suites deleted; `tests/e2e/test_dark_tech_theme.py` green UNCHANGED.
- [ ] `uv run ruff check . && uv run pyright` clean — the gate runs after this task.
@@ -0,0 +1,20 @@
# Task 02 — Regression sweep + the commit
**Phase:** `78_static_background` · **Source:** `TODO.md:4` — "Remove the animated css background, it's too resource intensive"
**Story:** n/a (TODO-derived)
## Objective
Prove the deletion regressed nothing (palette, theme, smoke, full pipeline) and land the atomic commit.
## Work
1. E2E (DB up, each in isolation): `uv run pytest tests/e2e/test_background_no_motion.py -v --no-cov`, then `uv run pytest tests/e2e/test_dark_tech_theme.py -v --no-cov` (UNCHANGED file — if it breaks, the deletion touched the palette; fix the deletion, not the test), then `uv run pytest tests/e2e/test_smoke.py -v --no-cov`.
2. Visual check in a real browser (real server, not the mock): the page background is the static grid over the flat `--bg` canvas — no pulsing light spots at the top-left / bottom-right / bottom-left corners; a `prefers-reduced-motion` browser profile sees the same static page; the theme CSS (indigo) still applies cleanly if set.
3. Full gate: `uv run pytest --cov=app --cov-report=term-missing` (>90% on `app/`), `uv run ruff check . && uv run pyright`.
4. ONE atomic `--no-gpg-sign` Conventional-Commits commit — e.g. `perf(ui): remove the animated background glow layers — static grid only` — body cites TODO.md L4 + the resource-intensity reason + the confirmed scope (glow spots gone, static grid stays). Move the phase dir to `.agents/phases/complete/`.
## Testing & Quality
- The full suite IS the test; coverage **>90%** on `app/`.
## Completion Criteria
- [ ] Items 1–3 all green.
- [ ] Committed; phase dir in `.agents/phases/complete/`.