# Rehearsal: the launch's database replace and the chain from 0.35.0 (Stream K7, 17 Sep)

Where: `dfp-devdb` (127.0.0.1:5433) only. Production was never contacted; no collection ran; no deploy.
Code: the refactor branch at `cf8061f` (the replace) and `baa9876` (its fixes), migration head `d2e3f4a5b6c7`.

## Inputs
- **Production-like:** `dfp_prod_like` and `dfp_prod_like2`, each restored with errors fatal from
  `backups/production/dfp-nightly-2026-09-17.dump` (production's nightly of 16 Sep, 23.4 MB):
  schema `b5c6d7e8f9a0`, 4 live sessions, 17,389 product rows (the pre-K1 table name `products`).
- **Staging at the branch head:** `dfp_k7_staging` = a template copy of `dfp_k3_final` (the 16 Sep staging
  nightly with K1, K2 and K3's after-deploy chain, 0 drift). `deploy/launch-dump.sh --db-container dfp-devdb
  --db dfp_k7_staging --out backups/launch/staging-rehearsal.dump`: 25 MB, 54 tables, 130,290 rows, head
  `d2e3f4a5b6c7`, 23 sources (23 enabled), 5.0 s; the counts before and after the dump agreed.

## The replace (`deploy/production.sh --replace-db ... --local --db-container dfp-devdb`)
| run | database | result | time |
|---|---|---|---|
| argument refusals | none | `--seed-db` removed (2); `--local` alone (2); `--local` on `dutyfreeprofessor-db` (2); a missing dump (1); `--replace-db` with `--caddy` (2) | under 1 s |
| dry run | `dfp_prod_like` | three heads equal; every command printed; `dry run: nothing ran`; the copy still `b5c6d7e8f9a0` | 0.4 s |
| real | `dfp_prod_like` | rollback dump taken; restored with `--exit-on-error`; head `d2e3f4a5b6c7`; **54 tables, 130,290 rows: equal**; revoked 13 sessions, 0 links expired; 23 sources identical side by side | 13.3 s |
| deliberate mismatch | `dfp_prod_like2` from `staging-mismatch.dump` (a copy of the staging copy with `feature_priorities`, 8 rows, dropped; the good dump's sidecars) | **REFUSED at the counts**: `< feature_priorities 8`; sessions left alone (13 live, from the restore); rollback command printed | 13.4 s |
| the printed rollback, run by hand | `dfp_prod_like2` | back to `b5c6d7e8f9a0`, 4 live sessions, 17,389 products | 6.8 s |
| dry run, then real, fixed script | `dfp_prod_like2` | dry: nothing changed; real: head equal, 54 tables and 130,290 rows equal, revoked 13, 0 live after | 15.1 s |
| unused link expiry | `dfp_prod_like2` | one inserted unused reset token expired by the script's statement (1 row), 0 unused after | under 1 s |

Found and fixed by the rehearsal (`baa9876`): the first mismatch run exited silently after the rollback
dump (a command substitution in an assignment under `set -e`); an ERR trap now names any failing line.
Two runs in one minute reused one rollback file name; the stamp now has seconds and an existing file is
refused. The production rollback line now names the droplet's own copy of the dump.

## The chain from 0.35.0 (RUNBOOK Production), on `dfp_prod_chain` from the same production dump
Every line exit 0, 292 s: `alembic upgrade head` ten migrations to `d2e3f4a5b6c7`; `threads` 64 threads, 146
comments; `thread_reads_seed` 192; `quantities` 17,340 (169 filled, 1 cleared); `suggestion_decisions` 0;
`attribute_keys` 0; `places` 21; `options` 3,363 named by title, 915 option fields; `attributes` 1,979;
`lines` 13,890 created; `rederive` 17,389 keys, then 0/0/0; `merges` 191 groups (201 rows forward), 201 left
for a person; `listed` 11,115 listings; `suggest` 21 brand, 2,508 line, 530 variant pairs; `prune_lines` 8;
`rule_proposals` 1,249 written, none applied; `decisions verify` 0 checked, 0 drift.

## Kept for the next session
`dfp_prod_like` and `dfp_prod_like2` (staging's content), `dfp_prod_chain` (production after the chain),
`dfp_k7_staging`, `dfp_k7_staging_bad`; the dumps in `backups/launch/` and `backups/rehearsal/` of the
worktree (gitignored). Drop them when the launch is done.
