From c8a6bf2f77738603892696bf65793b26c353de1c Mon Sep 17 00:00:00 2001 From: Daniel Gordon Date: Mon, 27 Jul 2026 16:04:27 +0000 Subject: [PATCH] =?UTF-8?q?docs(ops):=20fix=20rollback=20runbook=20?= =?UTF-8?q?=E2=80=94=20no=20sqlite3=20CLI=20on=20the=20deploy=20host?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every command in the runbook shelled out to `sqlite3`, which is not installed here. Replaced with Node 24's built-in node:sqlite, and switched the database backup from `.backup` to `VACUUM INTO`, which is safe against a live WAL database and yields a consistent single-file snapshot. Verified end to end by taking the actual pre-deploy backup: ~/backups/t3-pre-sidebarv2-2026-07-27/ — 334 MB snapshot reading back at ledger 33/ProjectionThreadRestartRequest with 202 threads, plus settings.json, keybindings.json and secrets/ (none of which are in git). --- docs/operations/rollback-2026-07-27-sync.md | 44 +++++++++++++++------ 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/docs/operations/rollback-2026-07-27-sync.md b/docs/operations/rollback-2026-07-27-sync.md index 0b7efc86e69..9aa720ff5f5 100644 --- a/docs/operations/rollback-2026-07-27-sync.md +++ b/docs/operations/rollback-2026-07-27-sync.md @@ -20,14 +20,25 @@ Rolling **back** is possible but has one hard constraint, documented below. settings problem presents as "all my providers reset themselves", not as an error. + There is **no `sqlite3` CLI on this host** — use Node 24's built-in + `node:sqlite` instead. `VACUUM INTO` is safe against a live WAL database and + produces a consistent single-file snapshot: + ``` - mkdir -p ~/backups/t3-pre-sidebarv2-2026-07-27 + DEST=~/backups/t3-pre-sidebarv2-2026-07-27 + mkdir -p "$DEST" cp -a ~/.t3/userdata/settings.json ~/.t3/userdata/keybindings.json \ - ~/.t3/userdata/secrets ~/backups/t3-pre-sidebarv2-2026-07-27/ - sqlite3 ~/.t3/userdata/state.sqlite \ - ".backup '$HOME/backups/t3-pre-sidebarv2-2026-07-27/state.sqlite'" + ~/.t3/userdata/secrets "$DEST"/ + mise exec node@24 -- node -e " + const {DatabaseSync}=require('node:sqlite'); + const db=new DatabaseSync(process.env.HOME+'/.t3/userdata/state.sqlite',{readOnly:true}); + db.exec(\"VACUUM INTO '\"+process.env.HOME+\"/backups/t3-pre-sidebarv2-2026-07-27/state.sqlite'\"); + " ``` + Verify the snapshot before trusting it — read its ledger tail and thread count + back and compare against the live database. + Back up **outside** `userdata/`. A copy placed inside it gets swept into every later `--seed copy` test-deploy and every curated snapshot. @@ -37,8 +48,11 @@ Verify the migration ledger advanced as expected — 33 is this fork's, 34 and 3 are upstream's renumbered pair: ``` -sqlite3 ~/.t3/userdata/state.sqlite \ - "SELECT migration_id, name FROM effect_sql_migrations ORDER BY migration_id DESC LIMIT 3;" +mise exec node@24 -- node -e " + const {DatabaseSync}=require('node:sqlite'); + const db=new DatabaseSync(process.env.HOME+'/.t3/userdata/state.sqlite',{readOnly:true}); + console.log(db.prepare('SELECT migration_id,name FROM effect_sql_migrations ORDER BY migration_id DESC LIMIT 3').all()); +" ``` Expect `35|ProjectionThreadsSnoozed`, `34|ProjectionThreadsSettled`, @@ -47,8 +61,13 @@ Expect `35|ProjectionThreadsSnoozed`, `34|ProjectionThreadsSettled`, Then confirm the columns exist and the live unit still matches the committed copy: ``` -sqlite3 ~/.t3/userdata/state.sqlite "PRAGMA table_info(projection_threads);" \ - | grep -E "settled_override|settled_at|snoozed_until|snoozed_at|requesting_restart" +mise exec node@24 -- node -e " + const {DatabaseSync}=require('node:sqlite'); + const db=new DatabaseSync(process.env.HOME+'/.t3/userdata/state.sqlite',{readOnly:true}); + const cols=new Set(db.prepare('PRAGMA table_info(projection_threads)').all().map(c=>c.name)); + for (const c of ['requesting_restart','restart_request_reason','settled_override','settled_at','snoozed_until','snoozed_at']) + console.log(cols.has(c)?'OK ':'MISS', c); +" diff <(systemctl --user cat t3code.service | tail -n +2) deploy/t3code.service systemctl --user start t3-claude-import.timer ``` @@ -71,9 +90,12 @@ This fork hides the Auto option behind Settings → Features open. If it was ever enabled, run this **before** redeploying an older build: ``` -sqlite3 ~/.t3/userdata/state.sqlite \ - "UPDATE projection_threads SET runtime_mode='full-access' - WHERE runtime_mode NOT IN ('approval-required','auto-accept-edits','full-access');" +mise exec node@24 -- node -e " + const {DatabaseSync}=require('node:sqlite'); + const db=new DatabaseSync(process.env.HOME+'/.t3/userdata/state.sqlite'); + const r=db.prepare(\"UPDATE projection_threads SET runtime_mode='full-access' WHERE runtime_mode NOT IN ('approval-required','auto-accept-edits','full-access')\").run(); + console.log('rows normalized:', r.changes); +" ``` To roll the code back, force-push `main` to the pre-merge commit