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