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
+134
View File
@@ -0,0 +1,134 @@
---
name: restore-test-db
description: Restores the large 1,000-document test knowledge base (the live-KB replica snapshot at data/bor_live_kb_replica.dump.sql) into the app's Postgres database in one atomic transaction — wipes the database's current contents, no re-embedding, no app code changes. Use when the user asks to restore the test database, the 1,000-document KB, or the big/live replica KB (e.g. "restore the test database", "put the 1000-doc KB back"). Do not confuse with the 8-document tool-calling fixture KB, which scripts/restore_test_kb.py restores.
---
# Restore the 1,000-Document Test KB
Load `data/bor_live_kb_replica.dump.sql` (a full 99 MB `pg_dump` —
schema **and** data — of the live KB replica) into the app database
(`brain_of_reese`, per `BOR_DATABASE_URL` in `.env`). The embeddings come
with the dump, so there is **no re-embedding, no git clone, no app code
change** — the whole known state (documents, chunks + embeddings, source
registry, KB overview, alembic version) lands in a few seconds.
The dump is a local artifact: `data/` is gitignored and the dump is
**never committed**. It is not in git — if it is missing on a fresh
clone, stop and ask the user for it (it can only be made by `pg_dump`ing
the live/`bor_eval` KB).
## Rules (non-negotiable)
- **The restore is destructive** — it wipes the current contents of the
app database. Always take the disposable backup in step 2 first, even
when the database looks empty.
- **Do not edit app code** (`app/`, `tests/`, `alembic/`). This skill
swaps database contents, nothing else.
- **Run `psql` inside the db container** (`brain-of-reese_db_1`), not
with a host `psql` — the container's psql is 17.x, matching the dump
(newer dumps use the `\restrict` metacommand that old host psqls
choke on).
- This KB and the 8-document tool-calling fixture KB
(`scripts/restore_test_kb.py`) share the same database and overwrite
each other. Say which one is loaded in the summary.
## Procedure
All commands run from the repo root.
### 1. Preconditions (fast fail)
```bash
podman compose up -d db
ls -lh data/bor_live_kb_replica.dump.sql # must exist, ~99 MB
```
Check the dump's schema version against the current head:
```bash
grep -A1 '^COPY public.alembic_version' data/bor_live_kb_replica.dump.sql | tail -1
uv run alembic heads
```
The two must match (the 2026-09-05 snapshot carries `0011`). If the dump
is **older** than head, proceed and run `uv run alembic upgrade head`
after step 3. If the dump is **newer** than head, the local code is
behind — stop and flag it to the user.
### 2. Disposable safety backup
Seconds, in `/tmp` (never committed):
```bash
podman exec brain-of-reese_db_1 pg_dump -U reese brain_of_reese -Fc \
> /tmp/pre_restore_$(date +%Y%m%d_%H%M%S).dump
```
### 3. Reset the schema, load the dump (one transaction)
```bash
podman exec brain-of-reese_db_1 psql -U reese -d brain_of_reese -c \
"DROP SCHEMA public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO PUBLIC;"
podman exec -i brain-of-reese_db_1 psql -U reese -d brain_of_reese \
-v ON_ERROR_STOP=1 --single-transaction -q -f /dev/stdin \
< data/bor_live_kb_replica.dump.sql
```
Why the schema reset: the dump contains plain `CREATE TABLE` (no
`IF NOT EXISTS`, no `--clean`), so it can only load into an empty
`public` schema. Why `--single-transaction` + `ON_ERROR_STOP`: a failed
load rolls back instead of leaving a half-loaded KB. Known failure mode:
the `DROP SCHEMA` is its own committed statement, so a failed load leaves
an **empty** schema — that is fine, fix the cause and re-run step 3
(the reset is idempotent).
### 4. Verify the fingerprint
```bash
podman exec brain-of-reese_db_1 psql -U reese -d brain_of_reese -tAc \
"select 'docs='||count(*) from documents
union all select 'chunks='||count(*) from chunks
union all select 'sources='||string_agg(distinct source, ',' order by source) from documents
union all select 'alembic='||(select version_num from alembic_version);"
```
Expected for the 2026-09-05 snapshot: **docs=1000, chunks=8866,
sources=deploy,homelab,homepage,ServMon,skills,vibe-bot, alembic=0011**.
If any number differs, the dump file is a different snapshot — report the
actual numbers to the user; do not guess.
### 5. Dev-server check (only if it is running)
```bash
pgrep -af "uvicorn app.main" && curl -s http://localhost:8000/api/health
```
Expect `"db":"up"` — the SQLAlchemy pool reconnects fine across the
schema reset, so no restart is normally needed. If the server misbehaves
after the restore, restart it (`uv run uvicorn app.main:app --reload`).
### 6. Summary
One line per verified number (docs / chunks / sources / alembic), the
wall time, and a reminder of which KB is loaded: this is the
**1,000-document live replica**; the 8-document tool-calling fixture is
brought back separately with `uv run python -m scripts.restore_test_kb`.
## Troubleshooting
- **`database unreachable` / connection refused** — the db container is
down; `podman compose up -d db`, then re-run from step 1.
- **`relation "public.<table>" already exists`** — the schema was not
reset (or a previous load failed after the reset rolled back); re-run
the `DROP SCHEMA` command from step 3.
- **`psql: /dev/stdin:N: unknown command '\restrict'`** — you ran a host
`psql`; use the container's, per the rules.
- **load succeeds but counts are wrong** — compare the dump's
`alembic_version` (step 1) and `documents` row count
(`sed -n '/^COPY public.documents/,/^\\./p' data/bor_live_kb_replica.dump.sql | wc -l`,
minus 2) against the loaded numbers; a mismatch means the dump was
truncated in transfer — ask the user for the original file.
- **`schema not applied`-style errors from the app afterwards** — run
`uv run alembic current`; if the dump was older than head, step 1's
`alembic upgrade head` was the missing piece.