docs: backup and recovery, plus units; move host runbook to a private repo

Adds bin/mempalace-backup and docs/backup-and-recovery.md — the mechanism a
palace actually needs, none of it site-specific.

Why a palace cannot be backed up with cp: it is chroma.sqlite3 (authoritative),
knowledge_graph.sqlite3 (usually WAL, so -wal/-shm make a plain copy a
same-instant gamble), derived HNSW segment dirs, hallways.json, the embedder
descriptor, and a HIDDEN .mempalace/origin.json. Both SQLite files are therefore
copied through the online-backup API. Two bugs are documented because both
produce a backup that looks fine: "$PALACE"/*/ silently skips the hidden dir, and
per-directory rsync collides the identically named data_level0.bin in every HNSW
segment. Treating the palace as one tree fixes both and makes a backup a faithful
palace IMAGE, so restore is a copy rather than a procedure.

Two modes: hot (default, zero downtime, ~4 s, index may lag but SQLite is
authoritative and repair --mode from-sqlite rebuilds) and cold (--cold, ~5 s
downtime, byte-consistent, restart trapped so a failed run still brings the
server back). Verification runs on the COPY — quick_check plus row counts — and
the backup is committed by mv only after it passes, with retention pruned only
after a verified commit, so a broken new backup cannot delete the last good one.

Documented because they are easy to get wrong: the sqlite3 CLI is often absent
where the Python module is present; mempalace_embedder.json must be restored with
the drawers or search silently degrades; a tested restore means running status
AND search against the restored copy, since search is what actually exercises the
index; mempalace-serve is a USER unit, so root systemctl reports "not found";
Persistent=true is what makes a missed window run after boot; and installing
against the system Python couples the palace's availability to distribution
upgrades, with the uv-managed-interpreter fix plus the two PATH traps that bite
scripted upgrades.

Also moves docs/synlig-primary-runbook.md out to a private fleet repository,
leaving a stub that explains the split, since a host inventory is operator data
for one deployment rather than part of a public toolkit. The path stays valid so
existing links do not break. Remaining host references in the README, RFCs and
ARCHITECTURE are left alone deliberately: they are load-bearing prose, contain no
secrets, and are best generalised as they are next edited rather than in one
churn-heavy pass.
This commit is contained in:
Joakim Persson
2026-08-17 00:50:16 +02:00
parent b609cf5a69
commit 947604b25d
8 changed files with 641 additions and 310 deletions
@@ -0,0 +1,12 @@
[Unit]
Description=Weekly cold MemPalace backup
Documentation=file:%h/mempalace-toolkit/docs/backup-and-recovery.md
[Timer]
# Half an hour after the daily hot backup, so the two never overlap on the
# palace lock even if the hot run is unusually slow.
OnCalendar=Sun 04:30:00
Persistent=true
[Install]
WantedBy=timers.target