fix(release): daily backups no longer replace the recovery point

Product chose to keep the scheduled backup, but the current recovery point must stay the one created by hand. Daily runs still encrypt and restore-verify, then record a separate latest-backup note.

Co-Authored-By: Grok (agent loop)
This commit is contained in:
jesse-ux
2026-10-15 16:16:48 +08:00
co-authored by Grok (agent loop)
parent 6ba63470a9
commit 5c0d895391
7 changed files with 349 additions and 13 deletions
+17 -2
View File
@@ -36268,9 +36268,9 @@
- 修复:新增只从 `main` 运行的每日备份工作流,复用现有加密与还原校验脚本。每日文件用单独前缀,过期清理不会碰到手动恢复点。工作流要等进入 `main` 后才会在北京时间 04:00 跑。本机没有生产主机,没有手动触发。
- 验证:合同测试锁定有每日时刻、只在 `main` 上跑、调用同一个恢复脚本、清理只删过期的每日前缀。虚构目录里,手动恢复点和其他文件都还在。
- 防复发:上述合同测试。清理函数不接受外部传入的前缀。
- 相关记录:BUG-1350、BUG-1356、BUG-1357。
- 相关记录:BUG-1350、BUG-1356、BUG-1357、BUG-1358。
- 复发自:无。
- 修复版本:分支 `codex/beta-safety-net-20261014`。开工时本文件最大号是 BUG-1353,当时写成 BUG-1354。合并 staging 后该号已被更早的答题强度记录占用,按台账规则改为 BUG-1355。
- 修复版本:分支 `codex/beta-safety-net-20261014`。开工时本文件最大号是 BUG-1353,当时写成 BUG-1354。合并 staging 后该号已被更早的答题强度记录占用,按台账规则改为 BUG-1355。每日备份曾会改写当前恢复点,已由 BUG-1358 分开。
## BUG-1356 | 站点打不开或磁盘过满时没有告警
@@ -36302,3 +36302,18 @@
- 复发自:无。
- 修复版本:分支 `codex/beta-safety-net-20261014`。原先写成 BUG-1356,合并 staging 后顺延为 BUG-1357。
## BUG-1358 | 每日自动备份改写了当前恢复点
- 状态:resolved
- 首次发现 / 最近更新:2026-10-15 / 2026-10-15
- 来源:issue #75。产品选 A。修复单 `docs/tasks/TASK-beta-safety-net-fix-20261015.md`。检索本文件的「recovery-baseline」和「每日备份」,没有更早的同类记录。
- 现象:每天凌晨的自动备份会把「当前恢复点」换成当天的自动备份。上线前手动建的恢复点,隔一夜就没了。
- 触发条件:每日备份调用 `deploy/run-production-recovery.sh`,前缀是 `production-daily`。脚本结尾无条件写 `.state/recovery-baseline.env`。发布、迁移、回退都读这份文件。
- 根因:每日备份复用了手动恢复点脚本,脚本不区分「只存档」和「更新当前恢复点」。
- 修复:前缀为 `production-daily` 时仍完成导出、加密和还原核对(含表权限、列权限、属主),并写校验文件,但跳过 `recovery-baseline.env`。另写 `daily-backup-latest.env`,只有文件名、sha256、核对时间和格式版本。手动创建恢复点的路径不变。
- 验证:临时目录加假 docker。已有恢复点的内容和修改时间不变;手动路径仍写出 `RECOVERY_FORMAT=2`。发布、迁移、回退所读的文件不引用 `daily-backup-latest.env`。清理仍只删过期的 `production-daily-` 文件。
- 防复发:上述合同测试。生产工作流不设置测试用的路径开关。
- 相关记录:BUG-1355。
- 复发自:无。
- 修复版本:分支 `codex/beta-safety-net-20261014`。本机没有装到生产主机,也没有点生产按钮。
@@ -39,6 +39,8 @@ Gitea → Create Production Recovery Point。Use workflow from:`main`。`deplo
通过:成功结束,记下三样东西:`recovery_reference`、`recovery_created_at`、以及它已经写明还原验证通过。主机上的 `/opt/jyotisha-production/.state/recovery-baseline.env` 里必须有 `RECOVERY_FORMAT=2`。没有这一行,或者数字小于 2,都不要往下走:先再点一次创建恢复点。8 月以来不带权限的旧备份不能再拿来回退。加密备份在生产主机的备份目录里,不要打开、不要把密钥贴出来。
每日自动备份不是这一步的恢复点。它每天只把加密文件存档并做还原核对,不会改 `recovery-baseline.env`。隔夜的自动备份不会换掉你上线前手动建的恢复点。上线前仍然要点 Create production recovery。
失败:停。不要迁移。
## 5. 在主机上演练迁移
@@ -0,0 +1,34 @@
# 进度 · 内测安全网修复(2026-10-15)
- 分支:`codex/beta-safety-net-20261014`
- 任务书:`docs/tasks/TASK-beta-safety-net-fix-20261015.md`
- 上一轮已推送:`53d8df257ddef8918034acef36df0b4b7daade2c`
- 产品选 A:每天的自动备份照做,但不改当前恢复点。
## 做了什么
- 先合并最新 `origin/staging`,没有改写已经推送的提交。合并时本分支的 BUG-1354 和更早的答题强度记录撞号,安全网三条顺延为 BUG-1355、BUG-1356、BUG-1357。这次的修复是 BUG-1358。
- 用已经存在的 `RECOVERY_BASENAME_PREFIX=production-daily` 当开关,没有另加模式参数。这个前缀下,脚本仍完成导出、加密、还原核对(含表权限、列权限、属主)并写校验文件,但跳过 `recovery-baseline.env`。标准错误打印 `baseline_updated=false`。另写 `.state/daily-backup-latest.env`,只有文件名、sha256、核对时间、`BACKUP_FORMAT=2`。
- 不设这个前缀时,仍写 `recovery-baseline.env`,里面有 `RECOVERY_FORMAT=2`,标准错误打印 `baseline_updated=true`,不改已经存在的每日记录。
- 标准输出仍是原来的 7 行。因此没有改 `.gitea` 里「恰好 7 行」的检查,也没有改四个已有生产工作流。
- 再确认清理脚本只删严格匹配的过期 `production-daily-` 文件。既有测试里的 `production-pre-migration-` 手动恢复点仍被保留。
- `docs/operations/production-release-runbook-20261014.md` 和 `deploy/README.md` 写明:每日备份只是存档和核对,上线前仍要手动点 Create production recovery。
## 跑过的检查
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 安全网与隐私 | `.venv\Scripts\python.exe -m pytest tests/test_beta_safety_net.py tests/test_repo_privacy_markers.py -q` | 78 通过(安全网 16,隐私 62),退出码 0 |
| 前端合同 | `node node_modules/tsx/dist/cli.mjs --test tests/runtime-sources-no-test-imports.test.ts tests/staging-backend-workflows.test.ts` | 46 项:41 通过,5 失败,0 取消。失败是本机缺口,见下方偏离。恢复点工作流的文本检查通过 |
| shellcheck | 无 | 本机没有这条命令 |
| 前端 tsc / lint / 全量测试 | 未跑 | 没有改网页 |
| Python 快速门 | 未跑 | 按本轮约定不跑 |
| 数据库测试 | 未跑 | 没有改数据库 |
## 偏离
- `baseline_updated` 打在标准错误,避免把每日备份和手动恢复点工作流对标准输出「恰好 7 行」的检查撑破。没有改 `.gitea/**`。
- 测试要在临时目录里跑脚本。生产路径检查保持原样;只有 `JYOTISHA_RECOVERY_FIXTURE=1` 时才允许别的目录。会调用恢复脚本的两个工作流都没有设置这个变量。
- 本机 Git Bash 没有 `flock`,pytest 的临时目录也不能改 Unix 权限。测试只在自己的 PATH 里放了假的 `docker`、`sudo`、`df`、`install`、`chmod`、`flock`。生产脚本仍调用真命令。
- 没有在这台 Windows 上安装到生产,没有点任何生产按钮。主机安装和一次恢复演练仍留给产品。
- 前端合同 5 项失败都不是这次改的脚本:本机 Python 没有 yaml 模块(直接跑时退出码 9009)、没有 rsync(退出码 127)、临时目录不能改权限(install 报 Permission denied)、文档范围脚本退出码 49。这四类脚本本次都没改。恢复点脚本的语法检查和文本合同是通过的。
+1 -1
View File
@@ -339,7 +339,7 @@
| `TASK-release-path-production-fix-20261014.md` | `PROGRESS-release-path-production-fix-20261014.md` | **#74 第 1 次打回**:发布规则成立;测试写死 Windows 路径(Linux 全红)、主机演练依赖主机 node 且会留下生产数据副本、docs-only 头时回滚被拒;另补 CHECK_RELEASE_GATE 断言与 OTP 守卫规范化 | 已修,第 2 次仍未过 | `codex/release-path-production-20261014` |
| `TASK-release-path-production-fix2-20261014.md` | `PROGRESS-release-path-production-fix2-20261014.md` | **#74 修复单 2(产品选 A)**:恢复点要带属主与权限,旧格式不得回退;演练按备份里的授权比对,并在真实 PostgreSQL 17 上跑通一次 | 待验收 | `codex/release-path-production-20261014` |
| `TASK-beta-safety-net-20261014.md` | `PROGRESS-beta-safety-net-20261014.md` | **内测安全网**:每日备份 + 恢复演练、探活告警、本地错误汇总、日志轮转、按 requestId 查日志。发布通路与 #58 已在开工时的 `origin/staging` 上。主机安装和一次演练留给产品 | 待验收 | `codex/beta-safety-net-20261014`(BUG-1355~1357) |
| `TASK-beta-safety-net-fix-20261015.md` | — | **#75 产品选 A**:授权新增每日备份定时工作流,但每日备份不得改写 `recovery-baseline.env`(恢复点仍只手动创建);另记 `daily-backup-latest.env` | 待领取 | `codex/beta-safety-net-20261014` |
| `TASK-beta-safety-net-fix-20261015.md` | `PROGRESS-beta-safety-net-fix-20261015.md` | **#75 产品选 A**:每日备份照常做,但不改当前恢复点;另记 `daily-backup-latest.env` | 待验收 | `codex/beta-safety-net-20261014`(BUG-1358) |
| `TASK-beta-capacity-20261014.md` | — | **内测容量**:按用户限流、重计算短排队与对话重试、兑换码当邀请码、staging 10/20 并发压测。**等 #58 合入后开工,压测等 #57 合入** | 待前置 | — |
| `TASK-beta-capacity-fix-20261015.md` | — | **#76 第 1 次打回**:`a54f75e5` 限流与短排队逻辑通过;源码文本断言未跟改、插入新测试使隐私白名单行号错位 | 待领取 | `codex/beta-capacity-20261014` |
| `TASK-special-lagnas-native-20261008.md` | `PROGRESS-special-lagnas-native-20261008.md` | **特殊上升点原生计算(线上缺陷)**:sync6 U6 运行时调 PyJHora,生产镜像没有 PyJHora → staging 上 Hora/Ghati/Sree/Indu/Pranapada 全 blocked;原生实现、PyJHora 只作冻结对照、快速门禁止运行时 import jhora;最先做 | 已验收(已部署 staging `795b8845`,BUG-1273) | `codex/special-lagnas-native-20261008`(未上线;部署以 `/api/health` 为准) |