0132887cb9
A 到 H 八档由这里唯一执行,每档的判定住在 _stopping。三处容易写错的地方都有测试钉着: 恰好用满预算完成记成目标达成而不是预算耗尽(结算在下一次迭代开头);规模超限不写步也不写 意图(唯一一种真的一步都没走的终止);未执行与环境故障两档的观察取库合成的那段,执行器 给的不进历史。 写入序列断言成一条流水:模型意图 → 模型结果 → 动作意图 → 步记录,模型调用失败也落一条 结果记录(不落的话恢复会把一次已知的失败判成状态未知走重放)。结果 ID 从运行标识与序号 推出来而不是随机数——重放同一步拿到同一个 ID,轨迹里也少一列每次都不同的值。 写这块时修掉的两个自己的坑: - 重放时会重复写意图,而同一步两条同种意图被 _recovery 判成「日志被并发写过」,一次成功的 重放反倒把日志弄坏。加了两个一次性开关跳过已经落过盘的那条。 - _recovery 数连续解析失败时把模型调用失败那一步也算进去了。它压根没走到解释器,判据改成 「解释器给了一段回喂文本」——解析失败必定带着那段说明,模型调用失败没有。 取消:CancelledError 原样重抛、run 不返回结果,但结束标记要在宽限期内尽力写下去,写不完 只记日志不再抛(再抛会把取消这件事本身盖掉)。并发隔离:全部可变状态住在每次运行一个的 _Driver 里,定义与请求都是 frozen 的,有一条并发跑两次的测试。 Budget 加了构造期校验(四项都必须为正):零或负数会产出一次「零步、预算耗尽」的运行, 那和一次真的跑满上限的运行在停止原因上完全一样,混进统计里分不出来。 事件出口收下了但没有调用点——Event 还没有字段,发一条内容为空的事件既没用又会变成一份 要兼容的形状。