Files
brain-of-reese/.agents/skills/restore-test-db/SKILL.md
T
ducoterra 7fce6572d0
Build and Push Containers / build-and-push-app (push) Successful in 1m45s
Build and Push Containers / build-and-push-db (push) Successful in 13s
feat: phases 77–80 — navbar view refresh, static background, API tokens, history suggestion chips
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
2026-09-07 12:39:01 -04:00

135 lines
5.8 KiB
Markdown

---
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.