HARNESS / 代理工程下载 EPUB ↓
24 / 32

第二十三章:实验三,让恢复器承认不知道

23.1 读取日志时先验证结构

Journal 为每项事件记录递增 seq、前一项哈希、类型、数据和当前哈希。加载时重新计算链,发现缺失字段、顺序不符或内容变更便失败。若文件尾部没有完整换行,也不会悄悄丢弃半行继续运行。

这是一个检测意外损坏的教学机制,不是抗恶意攻击的日志签名。能同时修改所有事件及哈希的人仍可伪造整条链。若需要审计可信性,还要设计外部签名、访问控制与不可变存储。

23.2 一个写入者,明确的锁文件

进入运行时用 O_EXCL 创建锁文件,已有锁则拒绝第二个写入者。锁内重新读取日志,避免沿用进入前的旧缓存。追加记录后 flush 和 fsync,使教学环境中的持久顺序可观察。

正常异常退出会进入 finally 释放锁,操作系统强制终止则可能留下它。恢复时不能按年龄直接删锁,因为 PID 可能复用,长任务也可能仍在运行。实验没有实现跨进程所有权仲裁,读者必须先确认相关进程停止,保存现场,再按核查流程处理。

23.3 人为制造不确定窗口

测试先保存 session.started、user.input、model.reply 和 tool.started,然后模拟外部文件已改变,却没有 tool.result。下一次 Engine 启动时,会记录 unknown,抛出 ReviewRequired,不再调用模型,也不重复写入。

这个场景是在受控测试里构造出的“写入已发生但结果缺失”状态,不是声称模拟了操作系统所有断电行为。它准确检验恢复器面对缺少结果证据时的决策。

重要的是,unknown 会留在日志里。本版不会仅加一条“继续”消息就绕过去,也没有提供自动解决未知结果的命令。生产实现可以加入人工裁决事件,但必须记录核查依据与允许的后续动作。

23.4 已接受但未开始的调用

另一种情况是完整 model.reply 已落盘,里面的调用尚无 tool.started。此时恢复器可以在同一工作区与策略下推进这些待执行调用,不必重新请求模型。因为它没有记录进入执行,结果未知窗口尚未从这条宿主路径打开。

仍然要核对当前外部状态。旧模型回复可能依赖旧文件,所以写入工具还要使用哈希前置条件。日志顺序只解决宿主知道什么,不保证外部环境在停机期间保持不变。

23.5 建立新的任务,不篡改旧事实

若目标、策略或工作区发生变化,实验拒绝沿用同一会话。一个新任务应有新的会话身份,旧日志保留原始事实。读者可以在新的临时工作区重做练习,不要为了让演示通过而手工把失败事件改成成功。

扩展练习:设计 review.resolved 事件。它至少应包含关联 call ID、核查方式、外部状态证据、裁决者和允许的恢复动作。然后分别测试“确认已执行”“确认未执行”和“仍无法判断”,而不是只测试一项继续标记。

非官方学习读物 · 固定源码快照 · 原始代码保留各自许可。GitHub · 源码依据 · 实验代码