From e0e2465e0c7d7ddd449acfa0e5ebbbd75964d680 Mon Sep 17 00:00:00 2001 From: shunli Date: Tue, 25 Aug 2026 20:29:27 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=B0=E5=BD=95(08-23-isolated-backup-restor?= =?UTF-8?q?e-drill):=20=E5=9B=BA=E5=8C=96Attempt=205=E5=89=8D=E6=8E=A2?= =?UTF-8?q?=E9=92=88=E4=B8=8ERTO=E5=8F=A3=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../design.md | 3 +++ .../implement.md | 15 +++++++++++ .../research/restore-drill-evidence.md | 25 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/.trellis/tasks/08-23-isolated-backup-restore-drill/design.md b/.trellis/tasks/08-23-isolated-backup-restore-drill/design.md index 639ba7a6..ca813f69 100644 --- a/.trellis/tasks/08-23-isolated-backup-restore-drill/design.md +++ b/.trellis/tasks/08-23-isolated-backup-restore-drill/design.md @@ -63,6 +63,9 @@ ARM 正式日归档(只读) - `RPO = drill_started_at - manifest.createdAt`。它表示使用该最新批次恢复时最多回退的数据时间窗口。 - `data_restore_RTO = all_data_checks_passed_at - restore_copy_started_at`。起点位于全部只读前置门禁通过后、复制正式批次到临时工作区之前;终点为 DB、附件及关联检查全部通过。 +- `data_restore_RTO` 不只输出总秒数,还必须按 runner 的实际串行边界输出八个非负整数阶段:`batch_copy`、`postgres_container_start`、`dump_list`、`target_confirmation`、`restore_apply`、`database_verify`(migration 与 12 类表)、`storage_attachment_verify`(附件恢复、文件数与业务关联)和 `final_integrity`(源/副本末次身份复核)。总数应与八段之和一致;若因秒级取整存在误差,差值必须为 `0`,不另设无法归属的隐藏开销。 +- 阶段计时以 runner 内连续边界为准:每一段结束时立即关闭本段并开始下一段。最长 60 秒的 TCP 目标确认轮询只计入 `target_confirmation`;1 秒轮询粒度是当前演练器实现成本,不与实际 restore apply 混算。失败时已完成阶段输出实测秒数,当前失败阶段输出从其起点到失败的秒数,未运行阶段为 `NOT_RUN`。 +- 阶段分解用于区分批次复制、容器与演练器等待、数据库/附件实际恢复及一致性校验成本;它们仍共同属于“数据恢复演练 RTO”。本轮未启动 OA 应用、未验证登录或业务 smoke,因此总数和任何阶段都不得称为完整 OA 灾难恢复 RTO,也不形成 SLA。 - `same_build_recovery_point_lag` 的正式口径需要可审计的发布完成时刻与 ARM 原子归档完成时刻;当前证据不具备后者,因此不得输出精确正式值。内部诊断可记录 `manifest_creation_after_contract_dropin = manifest.createdAt - automatic-backup service 构建 drop-in 最大 mtime`,但必须明确它既不是应用发布时刻,也不是 ARM 到达时刻。首次严格构建门禁失败仍证明发布后存在一段没有当前构建同源恢复点的窗口;该画像独立于数据 RPO 和数据恢复 RTO,即使恢复没有开始也保留。 - 前置访问准备、等待人工输入和任务文档整理不计入 RTO;镜像拉取、批次复制、实际恢复和验证命令计入。 - 本轮不启动应用,因此不得称为“完整 OA 恢复 RTO”;生产 `/ready` 只证明演练未影响在线服务。 diff --git a/.trellis/tasks/08-23-isolated-backup-restore-drill/implement.md b/.trellis/tasks/08-23-isolated-backup-restore-drill/implement.md index 6a8518bf..d9e1aeab 100644 --- a/.trellis/tasks/08-23-isolated-backup-restore-drill/implement.md +++ b/.trellis/tasks/08-23-isolated-backup-restore-drill/implement.md @@ -124,6 +124,21 @@ - [x] `scripts/restore-db.sh` 相对生产构建字节未改;runner、成对备份/恢复、自动异机备份 74 项、task、Trellis、process、docs、敏感扫描和空白门禁均通过。 - [ ] 本地修复阶段不连接 ARM、不生成或安装 Attempt 5 现场入口。提交后重新选择最新批次并执行只读探针、重新渲染候选和核对 SHA-256;实际恢复须再次单独批准。 +### Attempt 5 前只读身份探针结果 + +- [x] 用户批准后仅安装并执行最新正式批次只读探针;未复制、解包、启动容器、读取业务数据或执行恢复。 +- [x] 最新批次来源与当前生产构建相同,探针时年龄 `64625` 秒且不超过 24 小时;run id 配对、DB/附件大小与 SHA-256、source digest 均通过。 +- [x] 来源/当前 migration 目录为 `65/65`、差异 `0`;仓库 HEAD 相对生产构建的应用代码漂移文件数 `0`。 +- [x] 探针 root 入口与普通用户暂存残留均为 `0`;按已验证私有配置取得的 dead-man/健康 timer 实际 unit 状态为 `active/active`。 +- [ ] RTO 八阶段实现尚未批准,因此未渲染 Attempt 5 最终候选、未生成最终候选 SHA-256,也未执行实际恢复。 + +### Attempt 5 前 RTO 分阶段提案(待单独批准实现) + +- [x] 设计口径已固定为总 RTO 加八段串行秒数:批次复制、容器启动、dump list、目标确认、restore apply、migration/12 类表、附件恢复与关联校验、最终源/副本复核。 +- [ ] runner 增加固定 allowlist 阶段字段,成功时八段均为非负整数且精确加总为 `data_restore_rto_seconds`;失败时已完成段和当前失败段保留数字,后续段为 `NOT_RUN`。 +- [ ] 合同注入各阶段成功/失败,验证最长 TCP 轮询只进入目标确认阶段、后续 `NOT_RUN`、总数精确加总、输出不含路径/SQL/凭据;原有清理与恢复合同继续通过。 +- [ ] 未经单独批准,不修改 runner、重新渲染 Attempt 5 候选或执行实际恢复。 + ## 验证命令类别 - 本地/仓库:`bash -n` 覆盖备份、DB 恢复、附件恢复和 receiver 脚本;只读统计 migration 目录。 diff --git a/.trellis/tasks/08-23-isolated-backup-restore-drill/research/restore-drill-evidence.md b/.trellis/tasks/08-23-isolated-backup-restore-drill/research/restore-drill-evidence.md index 33676bd8..0b86dac1 100644 --- a/.trellis/tasks/08-23-isolated-backup-restore-drill/research/restore-drill-evidence.md +++ b/.trellis/tasks/08-23-isolated-backup-restore-drill/research/restore-drill-evidence.md @@ -427,3 +427,28 @@ Attempt 4 前后探针的最新构建短标识、run id 配对、产物完整性 完整复跑结果:runner 合同全部 `PASS`,既有成对备份/恢复演练 `PASS`,自动异机备份合同 `74/74 PASS`;task validate、Trellis governance、process baseline、默认/定向敏感扫描和 `git diff --check` 均通过。文档审计错误 `0`,仅保留既有未登记文件 warning;`scripts/restore-db.sh` 相对生产构建无字节漂移,测试容器和生成缓存残留均为 `0`。 本地合同通过只证明演练器修复与组件路径,不回答最新正式备份是否可恢复。下一步仍须先提交可追溯变更,再动态选择最新正式批次、执行只读身份探针并重新渲染候选;Attempt 5 实际恢复必须另行批准。 + +## Attempt 5 前最新正式批次只读身份探针 + +日期:2026-08-25 + +本节仅追加用户批准的最新正式批次只读探针与本地仓库关系核对;未执行恢复、未复制或解包正式归档、未启动 Docker、未读取数据库或附件内容。 + +| 检查项 | 结果 | +| --- | --- | +| 探针结果 | `PASS`;退出码未单独输出 | +| 最新批次构建短标识 | `7b86ffb3` | +| 来源与当前生产构建关系 | `SAME` | +| 探针时批次年龄 | `64625` 秒,约 17 小时 57 分,`within_24h=yes` | +| run id 与目录配对 | `PASS` | +| DB/附件大小与 SHA-256 | `PASS` | +| source image digest | 存在 | +| manifest 脱敏摘要前缀 | `ee1f97a5b42d` | +| 来源/当前 migration 目录 | `65/65`,差异 `0` | +| 仓库 HEAD 相对生产构建的应用代码漂移 | 文件数 `0` | +| 探针 root 入口/普通用户暂存残留 | `0/0` | +| ARM dead-man/健康 timer | `active/active` | + +timer 状态只采用已验证私有配置中的实际 unit 名只读取得;一次使用猜测名称得到的无效读数已当场撤销,未进入证据结论。探针结果表明该最新批次继续满足构建、新鲜度、身份和完整性前置门禁,但仍不是恢复成功证明。 + +Attempt 5 最终候选尚未渲染。原因是用户提出的 RTO 分阶段记录已进入设计、但 runner 实现尚未另行批准;若先渲染,后续计时代码会改变候选字节和 SHA-256。必须先裁决并完成 RTO 八阶段本地合同,再从跟踪模板重新确定性渲染候选并核对 SHA-256,实际恢复仍须单独批准。