6.2 KiB
Round 70 工作计划:审批数据库权威 Clock / TTL / CAS
日期:2026-08-04 来源:
plan.mdR67-B2、docs/product/plan-completion-matrix.mdP0 可信试点基线 当前状态:计划完成,待进入实现 外部边界:当前机器 Docker daemon 不可用、无 mysql client、无真实 MySQL 8 测试实例。
1. 背景与问题
DatabaseApprovalStore 已具备共享 DB、revision CAS、一次性 grant、同事务 grant/event 和 InnoDB/Alembic 门禁,但审批和 grant 的有效期仍由 Gateway 进程传入 now_epoch 或 time.time()裁决。两个节点存在正负时钟偏移时,可能对同一请求得出不同 TTL 结论;请求状态转换 CAS 也未把 expiry 条件放入 SQL UPDATE,存在跨过到期边界后的 TOCTOU。
2. 本轮目标
- MySQL 的审批、转派、过期、grant 创建/消费、事件时间全部使用同一写事务连接取得的数据库权威时间。
- MySQL 安全判断忽略调用方绝对
now_epoch;SQLite 继续保留 test-only 注入时间以保证确定性测试。 - 所有 request CAS 增加
expires_at_epoch > db_now,过期 CAS 使用<= db_now。 - grant consume/expire 使用同事务
db_now,状态和 event 不得部分提交。 - 请求 TTL 仅继承调用方给出的持续时间
expiresAtEpoch-createdAtEpoch,起点重锚到 MySQLdb_now;拒绝非有限、非正 TTL。 - MySQL epoch 列由
FLOAT升级为DOUBLE,避免 2026 年 epoch 精度损失。 - 保持文件审批 backend、Harness/API 合同和 SQLite test-only 边界不变。
3. 已确认设计决策
3.1 权威时钟
- MySQL:在实际写事务 session 上执行
SELECT UNIX_TIMESTAMP(CURRENT_TIMESTAMP(6))。 - SQLite:使用测试传入
now_epoch;未传时只为测试/维护兼容使用time.time()。 - 其他数据库:继续失败关闭。
- DB 时钟查询失败:禁止回退应用时钟,操作失败关闭。
3.2 TTL 与边界
now < expires:有效。now == expires:已过期。now > expires:已过期。- request TTL = payload 的
expiresAtEpoch-createdAtEpoch,验证为有限且大于 0,再以db_now重建绝对时间。 - grant TTL 继续使用
grant_ttl_seconds,但起点改为db_now。
3.3 CAS 与事务
每次尝试采用新 session:
BEGIN
→ 获取 db_now
→ 读取当前 row/revision
→ 权限、SOD、payload 校验
→ status + revision + expiry 条件 UPDATE
→ 插入 grant(如有)
→ 插入 event
→ COMMIT
rowcount=0 视为 CAS/TTL 未命中并有限重试;数据库断连、权限、schema 或 DB clock 错误不得伪装为普通冲突。
3.4 Schema
当前 SQLAlchemy MySQL DDL 实测生成 FLOAT。本轮:
- request:
created_at_epoch / expires_at_epoch - grant:
created_at_epoch / expires_at_epoch / consumed_at_epoch - event:
decided_at_epoch
升级为 MySQL DOUBLE(asdecimal=False),SQLite 继续保持现有浮点合同;新增 Alembic revision 20260804_01,并更新数据库后端启动门禁要求。
4. 写边界
允许修改
server/agent_core/approval_db_store.pyserver/db/models.pyserver/db/migrations/versions/20260804_01_approval_database_clock.pytests/golden/test_approval_database_clock.py- 必要时最小更新
tests/golden/test_approval_database_store.py - Round 70 文档、
plan.md、完成矩阵和 CHANGELOG
禁止修改
- 文件审批 backend
approval_store.py - Harness、Gateway API、前端
- approval migration 的 B1 业务逻辑
- SAP/MES/WMS 集成
- Round 69 数据生成器和 canonical 数据包
- 受保护
server/data文件
5. 验收矩阵
5.1 本地必须通过
- SQLite 边界:到期前/等于/到期后审批、转派和 grant 消费。
- SQLite 并发:final approve、approve/reject、approve/expire、consume/expire、consume-once。
- DB clock 查询失败 fail-closed,不回退应用时间。
- grant/event/commit 故障注入整体回滚。
- MySQL mock/编译:权威时间 SQL、CAS expiry 条件、六个 epoch 列为 DOUBLE。
- Alembic upgrade/downgrade 与 ORM 一致。
- 原有 approval database/migration/store/harness 回归。
- 全量 golden、Ruff、compileall、8003/5173 健康和受保护数据哈希。
5.2 外部阻断,不冒充完成
当前无 Docker daemon、mysql client 和真实 MySQL 实例,因此本地不能证明:
- 两个独立 Gateway 节点正负时钟偏移;
- MySQL REPEATABLE READ 下的真实多连接并发;
- deadlock/lock wait timeout、commit 前后断连;
- session timezone、主从/HA 切换;
- 生产账号、代理、连接池和真实部署拓扑。
本轮完成后矩阵可标记 Done (local contract) / Partial (external MySQL),不得标记生产完成。
6. 验证命令
.venv\Scripts\python.exe -m ruff check server/agent_core/approval_db_store.py server/db/models.py server/db/migrations/versions/20260804_01_approval_database_clock.py tests/golden/test_approval_database_clock.py tests/golden/test_approval_database_store.py
.venv\Scripts\python.exe -m compileall -q server/agent_core/approval_db_store.py server/db/models.py server/db/migrations/versions/20260804_01_approval_database_clock.py
.venv\Scripts\python.exe -m pytest -q tests/golden/test_approval_database_clock.py tests/golden/test_approval_database_store.py tests/golden/test_approval_migration.py tests/golden/test_approval_store.py tests/golden/test_harness_p3.py
.venv\Scripts\python.exe -m pytest tests/golden -q
npm run test:node
npm run build:web
完成代码后刷新 GitNexus 并执行 detect_changes(compare main);未经用户授权不 commit/push/merge/publish。
7. 风险门禁
DatabaseApprovalStoreupstream impact:LOW,7 个受影响符号。ApprovalRequestRecordupstream impact:HIGH,127 个受影响符号;修改模型前必须向用户明确预警,并用迁移、DDL 编译和全量回归保护。- 若 implementation 发现需修改 Harness/API 或文件审批 backend,立即停止扩界并重新做 impact/计划审计。
8. Plan Audit
PLAN AUDIT: PASS
Blocking issues:无。 Clarification needed:无;MySQL 真实环境已明确列为外部验收门禁。 Non-blocking improvements:未来取得 MySQL 8 实例后补双节点时钟偏移和故障注入,不影响本地合同实现。