docs(ddl): runbook 首步强制「迁移前像 dump 哈希」(--apply 之前)
ci/woodpecker/push/main Pipeline was successful

CMA-DDL-RUNBOOK-20261005 / parent: CMA-KPI-20261003-D-T1
- docs/db-migration-runbook.md 新增 §3.0:任何 --apply 之前对每张受影响表落
  全表有序 (PK, 受影响列) dump,记录 sha256 + 行数 + 字节数,归档 backups/pre-ddl-<task>/
- 含可直接复制的一行命令(ORDER BY 主键保证字节级确定性)
- §4 发布 checklist 第 4 条(列级 ALTER)指向 §3.0

仅文档;零生产库/零部署/零重启。
This commit is contained in:
wecom-fullstack
2026-10-05 13:02:02 +08:00
parent 4f9bab6bc0
commit b58513c48d
+23 -1
View File
@@ -30,6 +30,27 @@
## 3. 迁移步用法(`backend/scripts/db_migrate.py`)
### 3.0 强制前置步 —— 任何 `--apply` **之前**:迁移前像 dump 哈希
> 来源:`CMA-KPI-20261003-D-T1` 只读回读复核(2026-10-05)。落地前两侧(设计 10:11 / 执行 10:38)**只留了行数/计数基线**,
> 未留全表 `(PK, 受影响列)` 有序 dump 哈希 ⇒ **迁移前像不可得**,事后只能用「四时点基线谓词对拍 + 值域指纹 + 时间戳 +
> `MODIFY` 类型保持」四路**替代取证**。本步是事后自证「**存量取值零改写**」的**唯一直接依据**,不可省、不可推迟到 `--apply` 之后。
对本任务**每一张受影响表**,在 `--apply` **之前**落一次全表有序 `(PK, 受影响列)` dump,记录 `sha256 + 行数 + 字节数`;
产物归档 `backups/pre-ddl-<task>/`(与 `backups/pre-ddl-entity-dim-20260923/` 同约定),随任务件留痕。
可直接复制(把 `DB / TBL / COLS` 换成任务值;`COLS` **首位必须是主键**):
```bash
DB=cma TBL=treasury_limits COLS='id,status,limit_amount' D="backups/pre-ddl-$(date +%Y%m%d-%H%M%S)" sh -c 'mkdir -p "$D"; mysql -N -B --default-character-set=utf8mb4 "$DB" -e "SELECT $COLS FROM $TBL ORDER BY ${COLS%%,*}" > "$D/$TBL.before.tsv"; sha256sum "$D/$TBL.before.tsv"; wc -lc < "$D/$TBL.before.tsv"'
```
- `ORDER BY ${COLS%%,*}`(即主键)保证字节级确定性:同一份数据两跑,`sha256` 必须一致。
- 行数与 `SELECT COUNT(*)` 对账:`wc -l` 即行数(`-N` 无表头;末行缺换行符时 ±1 属正常)。
- 多表:每张受影响表各跑一次,逐表记录「表名 + sha256 + 行数 + 字节数」。
- 现成实现可复用 ops 探针 `wecom-ops/scripts/probe_cma_kpi_t1_readback_20261005.py --check`(自动落 `02b-current-id-tv.json` 全量行值基线)。
- 本步只用**只读**语句(`SELECT` + `sha256sum`),零生产写;`--apply` 与回滚命令见下。
```bash
cd /root/cma-management/backend
./venv/bin/python3 scripts/db_migrate.py --check # 只读预检(默认动作)
@@ -53,7 +74,8 @@ cd /root/cma-management/backend
2. 本地 `--check` 应能列出该表缺失(证明 ORM 已注册)。
3. 提交推送 → 部署链 `[4b]` 用特权账号建表 → 重启 → 冒烟 `schema_check` 通过。
4. 若模型**改列**(新增/改名/改类型):`create_all` 不处理 → 必须写独立迁移脚本/`ALTER`(参考
`backend/scripts/migrate_ext_input_ledgers_20260915.py`、`treasury_migrate.py` 的 `up()/down()` 模式)。
`backend/scripts/migrate_ext_input_ledgers_20260915.py`、`treasury_migrate.py` 的 `up()/down()` 模式);
**执行任何 `ALTER` 前先走 §3.0 迁移前像(全表有序 dump 哈希)**。
5. **不要**让运行库账号重新获得 CREATE 来「绕过」:那正是事故根因。
## 5. `cma_api` 的 CREATE 授权回收(项目Bot 执行)