Phase 17: run the migration, and fix the guard that locked out its own backup
Claire's writing — 8 documents, 33 snapshots, 103 suggestions, 3 vocabulary words and an image — now belongs to her account rather than to the pre-auth 'local' user, and the VPS is canonical. millenia was left running and untouched as a frozen fallback; it diverges the moment either side is written to, so it wants retiring rather than syncing. The plan's stated prerequisite, that she log in once so her subject exists, turned out to be false. Authentik's hashed_user_id sub is the user's uid, derived from her id and the instance secret, so it can be read in advance — which means the data moves first and she signs in to find her writing already there, instead of to an empty Petal that fills in later. The fix here is to the liveness guard, and it is the second attempt at it. PRAGMA locking_mode = EXCLUSIVE goes on holding its lock after being set back to NORMAL — SQLite only lets go on that connection's next database access — so against a real WAL database the script locked itself out of its own VACUUM INTO backup. It passed locally because the test database had come out of VACUUM INTO and so was never in WAL mode: the fixture didn't look like production, the same way the stub identity provider's slashless issuer didn't. The probe now runs on its own connection and closes it. Claude-Session: https://claude.ai/code/session_016y6gyuHkQXPiEuW8RGQyua
This commit is contained in:
+43
-5
@@ -4,12 +4,16 @@ Two deployments exist right now:
|
||||
|
||||
| | host | shape | status |
|
||||
|---|---|---|---|
|
||||
| **millenia** | `192.168.1.212` / `100.64.0.2` | bare binary in a screen session on `:8088`, Piper as user systemd units | **canonical** — her real writing lives here |
|
||||
| **parodia** | `petal.parodia.dev` / `100.64.0.1` | docker compose behind the host's Traefik | staging; empty database |
|
||||
| **parodia** | `petal.parodia.dev` / `100.64.0.1` | docker compose behind the host's Traefik | **canonical** since 2026-07-27 — she signs in here |
|
||||
| **millenia** | `192.168.1.212` / `100.64.0.2` | `petal.service`, bare binary on `:8088`, Piper as user systemd units | frozen fallback: a copy of her writing as it stood at the move, still owned by the pre-auth `local` user |
|
||||
|
||||
millenia stays canonical until Phase 16's auth lands, so she only moves accounts
|
||||
once. Everything below is the VPS side; the millenia Piper notes are kept in the
|
||||
appendix because that instance still runs them.
|
||||
Her writing moved to the VPS when sign-in landed (Phase 16/17): it is the
|
||||
instance that actually authenticates, its data directory is LUKS-encrypted, and
|
||||
it is reachable from anywhere. millenia was left running and untouched as a
|
||||
fallback — but the two diverge the moment anything is written on either, so it
|
||||
should be retired rather than kept in step. Everything below is the VPS side;
|
||||
the millenia Piper notes are kept in the appendix because that instance still
|
||||
runs them.
|
||||
|
||||
---
|
||||
|
||||
@@ -239,6 +243,40 @@ with `htpasswd -nbB petal 'your-password'` in `.env` as `PETAL_BASIC_AUTH`.
|
||||
|
||||
---
|
||||
|
||||
## 4a. Moving an account (`scripts/migrate_local_user.py`)
|
||||
|
||||
Petal ran as one hardcoded user (`users.id = 'local'`) before sign-in existed.
|
||||
Moving that writing onto a real account is a deliberate, one-off operation:
|
||||
|
||||
```bash
|
||||
docker compose stop petal
|
||||
python3 scripts/migrate_local_user.py data/petal.db --to <oidc-sub> # dry run
|
||||
python3 scripts/migrate_local_user.py data/petal.db --to <oidc-sub> \
|
||||
--email her@example.com --name "Her Name" --apply
|
||||
docker compose up -d petal
|
||||
```
|
||||
|
||||
The subject id is **knowable before she has ever logged in**. With authentik's
|
||||
default `hashed_user_id` sub mode it is the user's `uid`:
|
||||
|
||||
```bash
|
||||
docker exec authentik-server-1 ak shell -c \
|
||||
"from authentik.core.models import User; print(User.objects.get(username='claire').uid)"
|
||||
```
|
||||
|
||||
so the data can move first and she signs in to find it already there.
|
||||
|
||||
**Start Petal once on the incoming database before migrating.** A database
|
||||
carried over from another instance may be a schema behind, and the app applies
|
||||
migrations at startup; the script moves rows and does not touch the schema.
|
||||
|
||||
The script is dry-run by default, takes its own `VACUUM INTO` backup, runs as
|
||||
one transaction with foreign keys off, and verifies the row counts before it
|
||||
commits. It refuses to run while anything else has the database open, and
|
||||
refuses to merge into an account that already owns writing.
|
||||
|
||||
---
|
||||
|
||||
## 5. Backups
|
||||
|
||||
### On the VPS — folded into `parodia-backup`
|
||||
|
||||
Reference in New Issue
Block a user