# Round 67 工作计划:审批迁移 Fail-Closed 与 Grant Digest 归一化 日期:2026-08-03 ## 1. 方向选择 Round 66 已完成并通过独立复审。并行候选审计发现: - 审批文件迁移把原始 grant token 直接写入数据库 token_hash,迁移后 P3 grant 无法被数据库后端消费; - 损坏 JSON/非法结构会被当成空审批源并报告迁移成功; - 数据库 TTL 仍依赖应用主机时钟,留到后续 R67-B2; - SAP outbound P3 evidence envelope、folder.schedule TOCTOU 与 Automation G4 payload 绑定列入后续 P0。 本轮选择 R67-B1,因为两个 CRITICAL 缺陷可在本地 SQLite 完整复现和闭环,且写边界最小。 ## 2. GitNexus 门禁 - `load_file_store`:LOW,1 个直接调用、6 个总影响,无执行流。 - `migrate_file_to_db`:MEDIUM,5 个直接测试调用,无执行流。 - 不修改审批 API、Harness、数据库 consume/TTL 或真实 MySQL 部署路径。 ## 3. 目标 1. 迁移 grant 时只存 `token_digest(raw_token)`,不持久化原始 token。 2. 文件不存在维持空源语义;文件存在但 JSON/schema/记录损坏必须明确失败。 3. 所有源记录先完成规范化与交叉引用预检;grant 缺 pending request 时依据 grant/history 重建终态 APPROVED request,满足数据库外键。 4. 全部请求、grant 修复和事件在一个 SQLAlchemy Session 事务中 flush/commit;后段异常整体回滚。 5. 幂等比较拆分为不可变身份字段与单调状态:允许数据库端合法前进到 APPROVED/CONSUMED/EXPIRED,禁止状态回退或覆盖。 6. 同时预检 expected digest、历史 raw-token 主键与 confirm_id;一致 legacy 行在事务内原子修复为 digest,冲突则 fail-closed,禁止对 DB 中已知 digest 再哈希。 7. history 使用完整 canonical event digest 去重;同秒同状态但 approver/note/payload 不同的事件必须保留。 8. 迁移要求 `APS_APPROVAL_MIGRATION_QUIESCED=1`,并持有与文件后端相同的 `.lock` 到事务提交;读取、flush 后复核 source SHA-256 一致,再 commit。 9. 迁移后 active P3 grant 可成功消费一次,重放失败。 ## 4. 写边界 - 业务实现:`server/agent_core/approval_migrate.py` - 黄金测试:`tests/golden/test_approval_migration.py` - 文档:本计划、并行计划、状态/运行证据、plan/matrix/changelog ## 5. Out of scope - 数据库权威时钟、TTL/CAS 跨主机语义(R67-B2)。 - 真实 MySQL 多主机、网络断连/死锁恢复。 - SAP outbound、folder.schedule、Automation G4 evidence envelope。 - 提交、推送、合并、发布或修改现场审批文件。 ## 6. 验收 - 文件后端 active P3 grant -> 迁移 -> 数据库后端 consume 一次成功、第二次失败。 - DB 仅包含 64 位 SHA-256 digest,不包含 raw token。 - 损坏 JSON、错误顶层 schema、非法 pending/grant/history 均失败且三张审批表不变。 - 同键不同不可变身份字段报冲突;数据库端合法状态前进不误报冲突,状态回退不覆盖。 - legacy raw-token 行一致时原子修复,不一致时 fail-closed。 - history canonical digest 保留合法近似事件并保证重跑幂等。 - 后段事件构造/flush 故障注入后,三表及迁移前目标数据整体不变。 - 未设置 quiesced 明确拒绝;锁持有期间 source digest 漂移则回滚。 - dry-run、幂等迁移、缺失文件原有行为保持。 - focused、相关 approval suites、全量黄金、Node/Web(如受影响)、真实临时数据库运行、diff-check、detect_changes 和独立审计通过。 ## 7. 数据保护 所有测试使用临时审批文件和临时 SQLite;fixture 显式设置 quiesced。不得读取后写回 `server/data/approvals.json` 或现场 `master.db`。验收前后记录现场审批文件 hash 与 `server/data/.env` Git 状态。 ## 8. 首轮 Plan Audit 修订 首轮 `PLAN AUDIT: FAIL` 的六项阻断已纳入:终态 request 重建、单调状态幂等、legacy raw-token 修复/冲突、canonical event digest、单事务后段回滚、quiesced + 同锁稳定快照。真实跨主机停写编排仍是部署验收,不在本地 SQLite 冒充完成。 ## 9. 执行结果 - 首轮计划审计 6 项 blocking 已修订,最终 `PLAN AUDIT: PASS`。 - 并行 worker 超时失效后由主 agent 接管其已落入工作区的代码/测试并完成集成。 - 初始 focused 3 failures 已修复;最终 migration 29、approval related 74、full golden 1053 全绿。 - 真实临时 SQLite 迁移/consume/corrupt fail-closed 通过;现场 approvals/world hashes 不变。 - 首轮代码审计发现 legacy payload 身份未校验,补 request/grant payload immutable gate 与正负回归后最终 `AUDIT: PASS`。