fix(approval): replay immutable action responses

This commit is contained in:
caoxiaozhu
2026-07-16 15:49:43 +08:00
parent 4940ebc419
commit 28b834edd3
20 changed files with 552 additions and 60 deletions

View File

@@ -8,3 +8,8 @@
- 2026-07-16 15:33:03 CST交叉审查后修复三项并发绕过审批动作不再调用会隐式提交的读取修复逻辑列表/分页 GET 也不再修改审批节点;审批中心保留服务端原始状态并单独生成展示标签;门禁将持久化风险观察与未匹配原始高风险合并,重大观察持久化失败时 fail-closed。
- 2026-07-16 15:33:03 CST审批、风险处置和 Hermes 扫描统一以 Claim 行锁为公共协调点,锁顺序固定为 Claim → Observation → DispositionHermes 锁外计算、锁内刷新并核对状态和更新时间,旧快照被丢弃。一次性 PostgreSQL 并发用例证明风险重新打开与审批竞争时审批等待后读取最新风险并阻断Claim 节点和动作账本均保持无副作用。
- 2026-07-16 15:33:03 CST最终容器回归为审批/风险/费用服务 174 项、迁移/所有权 54 项、前端审批/风险 73 项通过Vite 生产构建通过;一次性 tmpfs PostgreSQL 17 上 13 项迁移和 1 项真实并发测试通过,临时数据库自动清理。再次执行 Git 拉取检查,上游仍无新增提交,本地 ahead 14。
- 2026-07-16 15:44:39 CST提交后交叉审查发现“副作用幂等”不等于“响应幂等”动作账本虽然已有 `response_json`,重放却重新读取当前 Claim后续节点变化会返回新状态。现改为首次动作在同一事务保存完整 `ExpenseClaimRead`,首次和重放均从该快照构造响应;快照缺失、单据/状态/节点身份不一致时 fail-closed 返回冲突,不再退回当前投影。
- 2026-07-16 15:44:39 CST新增“首次批准 → 单据继续推进并写入后续内部状态 → 旧 request_id 重放”服务和 HTTP 回归,确认响应逐字段等于首次结果、后续风险字段不泄露、数据库当前状态不被回退;审批动作与报销接口组合 29 项通过。
- 2026-07-16 15:44:39 CST再次完成 Git 拉取检查,上游无新增提交,本地 ahead 15新增 ahead 为 `4940ebc4` 审批风险安全底座;用户维护的财务规则工作簿和历史日志继续保持未暂存。
- 2026-07-16 15:48:38 CST扩大回归范围后发现两个兼容边界首次动作若直接返回 Pydantic 快照会破坏既有服务层 ORM 可变语义,因此首次执行继续返回已提交并刷新的 ORM只有重放从不可变快照构造HTTP 首次与重放仍逐字段一致。另为风险门禁增加申请/报销阶段匹配,显式错阶段风险不阻断当前流程,未知阶段重大风险仍 fail-closed。
- 2026-07-16 15:48:38 CST路由型重大风险统一使用显式 `route_review`,它允许当前审批进入预算/财务复核,但不会被标记为已解决;普通无 actionability 的原始重大风险继续阻断。容器内费用服务、审批路由、租户/Case、动作协议、接口和风险处置组合 182 项通过。

View File

@@ -8,3 +8,6 @@
- 2026-07-16 15:33:03 CST交叉审查后收紧处置动作语义误报、补件和豁免申请必须提供服务端校验的说明完成处置必须提供处理结果版本冲突返回明确消息并触发前端刷新已完成生命周期不再展示重复动作。
- 2026-07-16 15:33:03 CST处置服务在 Claim 公共锁内重新确认当前审批人Observation 和 Disposition 使用租户范围行锁及固定顺序;风险观察写入同样获取 Claim 锁。完整证据、风险池和处置权限分别执行最小授权,跨租户和无权资源继续以 404 隐藏。
- 2026-07-16 15:33:03 CST最终验证全部在 `local-x-financial-linux` 容器完成并设置 60 秒超时;相关后端 174 项、迁移/所有权 54 项、前端 73 项与生产构建通过,一次性 PostgreSQL 17 的结构和并发验证 14 项通过。规则工作簿和历史未跟踪日志未被改动或纳入提交。
- 2026-07-16 15:44:39 CST交叉审查发现风险处置重放在权限复核前读取当前 Disposition 及全部事件,旧 request_id 可能看到首次动作之后的处置状态。新增 `20260716_0012`:完整响应在 append-only Event 的 INSERT 前原子写入 `response_json`,重放只返回该不可变快照并将 `replayed=true`;不得通过 UPDATE 补写审计事件。
- 2026-07-16 15:44:39 CST兼容 0012 前历史事件时,不回读当前 Disposition只使用目标 Event 的 `after_json``version <= target` 的只追加事件重建;快照身份、租户、观察、处置、请求和版本任一不一致均 fail-closed。新增后续补件/整改后重放首个裁决的服务与 HTTP 回归,确认只返回版本 1 和当时事件。
- 2026-07-16 15:44:39 CST容器内风险处置、迁移和前置检查 69 项通过、1 项条件跳过,审批快照与报销接口 29 项通过;一次性 tmpfs PostgreSQL 17 的 0012 Head 迁移与审批风险真实并发共 17 项通过,临时数据库自动清理且持久开发库未修改。