OpenVibe.Live/Docs
Source on GitHub

Cutover: migration 006_drop_emotes (T3 N+3)#

PR #1 (merge 70b67309, "T3 N+3: drop Live's emotes copy (Chat owns it)") adds the destructive migration 006_drop_emotes (server/db/migrations.js): on the first boot of the new release Live runs DROP TABLE IF EXISTS emotes on its SQLite database and records 006_drop_emotes as applied in schema_migrations. A database without the table (a fresh install) records it as adopted and drops nothing. The same PR removes emotes from server/db/schema.sql and the two inline emotes migrations from server/db/database.js, so nothing recreates the table.

Preconditions#

Order#

  1. ov access run openvibe-ovh db-backup: back up the databases now. Note the Live backup's stamp
    (<backupDir>/live/<YYYYMMDD-HHMMSS>/live.db, recorded in <stateDir>/backups/live.jsonl) and check that it is
    ok: true. This is the only way back to a database that still has the table.
  2. ov access run openvibe-ovh health live: ready.
  3. ov access run openvibe-ovh deploy live -- --wait-idle: ships the range since the running release (it
    includes 70b67309). The first boot runs 006.
  4. ov access run openvibe-ovh health live: ready.

How to check success#

Rollback#

ov access run openvibe-ovh rollback live alone does not bring the table back: it switches to the previous release's code against the same database, and fb3957f does not need the table, so it runs, but the dropped rows are gone. To get Live's emotes copy back (there is no reason to expect it to be needed: Chat serves emotes and holds newer rows than this copy), the owner restores the step 1 backup with the previous release:

  1. ov access run openvibe-ovh rollback live (back to the previous release).
  2. On the host: stop Live, copy the step 1 backup's live.db over Live's database (as the service user, owner
    and mode as before, with no stale -wal/-shm beside it), start Live.
  3. ov access run openvibe-ovh health live: ready.

Restoring the backup also discards every other Live write made between step 1 and the restore, so prefer leaving the table dropped: a missing emotes table affects nothing that runs.

Rehearsal#

Rehearsal live-emotes-006, 2026-10-01, Node 22.22.1 (production's; the shared node_modules has better-sqlite3 built for it), on exports of the two commits in /tmp/ov-emotes-006/{old,new} (git archive 70b6730^1 = 51f772b, git archive 70b6730). rehearse.js opens DATA_DIR's live.db through the given release's db.initDb() — the call server/index.js boots with, schema plus migrations.run() — then seeds (seed: 2 users, 3 emotes, then writes every table's row count to DATA_DIR/counts.json) or reports (check: the 006 ledger row, whether emotes exists, every other table's count against counts.json).

$ export PATH=~/.local/share/fnm/node-versions/v22.22.1/installation/bin:$PATH; R=/tmp/ov-emotes-006
$ DATA_DIR=$R/data node rehearse.js $R/old seed        # pre-PR code, 70b6730^1
[DB] Rebuilt emotes table: code uniqueness is now per-channel
seeded: emotes=3 users=2 tables=82
ledger: 001_vibes_decimal_to_bits,002_pastes_ai_columns,004_hot_path_indexes,005_drop_chat_staged_tables
$ DATA_DIR=$R/data node rehearse.js $R/new check       # new code, 70b6730: first boot
[DB] migration 006_drop_emotes applied in 1ms
006 ledger rows: [{"id":"006_drop_emotes","mode":"applied"}]
emotes table exists: false
other tables compared: 80, count changes: none, missing: none
schema_migrations rows: 4 -> 5
$ DATA_DIR=$R/data node rehearse.js $R/new check       # second boot: no-op (no "applied" line)
006 ledger rows: [{"id":"006_drop_emotes","mode":"applied"}]
emotes table exists: false
other tables compared: 80, count changes: none, missing: none
schema_migrations rows: 4 -> 5
$ DATA_DIR=$R/fresh node rehearse.js $R/new check      # fresh database
006 ledger rows: [{"id":"006_drop_emotes","mode":"adopted"}]
emotes table exists: false

npm test at 70b6730 (Node 22.22.1):

$ cd $R/new && set -o pipefail && npm test            # the git-less export
✓ account-data.test.js / ✓ chat-staged-tables.test.js / ✓ destructive-migrations.test.js
✓ frozen-tables.test.js / ✓ n-1.test.js
✗ drill-mode.test.js       Error: Command failed: git rev-parse --short=12 HEAD (not a git repository)
✗ release-events.test.js   git rev-parse: '' does not match /^[0-9a-f]{40}$/
152/157 test files passed, 3 skipped (… rollback-newer-writes.test.js: skipped (no git history …))
$ # the three git-dependent files, in the git worktree at 70b6730 (NODE_PATH = the same node_modules)
$ node test/drill-mode.test.js            → drill-mode: all checks passed (21 passed, 0 failed)
$ node test/release-events.test.js        → release events: … — all checks passed
$ node test/rollback-newer-writes.test.js → rollback with newer writes: the release of ae589aca works on this release's database, and back again

The two failures in the export are only the missing .git; in the git checkout all three pass (drill-mode's symlink check also needs the checkout's data/ to exist, as it does in production). The other two skips are environmental (no PostgreSQL URL, no local model).

REHEARSAL: green

This page is rendered from docs/cutover-emotes-006.md in the OpenVibe.Live repository. Found a mistake? Edit it there.