恢复不只得到消息数组;它还要找出最近一个存活且完成的用户 Turn 设置,并恢复 compaction window number/ID 链,才能让下一 Turn 正确比较配置和延续请求缓存作用域。
本节解决的不是“把对象存一下”这种抽象问题,而是把问题限定在:研究 PreviousTurnSettings、reference TurnContext 与窗口 ID 的选择优先级。输入:TurnContext、Turn terminal events、SessionMeta 与 CompactedItem window 字段;状态所有者:RolloutReconstructionResult 和 Session state;成功结果:previous settings、reference context、window_number 与 first/previous/current IDs。先把这些边界钉住,后面的顺序、失败和恢复才不会混成一句“持久化失败后重试”。
状态边界
| 问题 | 本节答案 |
|---|---|
| 输入 | TurnContext、Turn terminal events、SessionMeta 与 CompactedItem window 字段 |
| 状态所有者 | RolloutReconstructionResult 和 Session state |
| 成功产物 | previous settings、reference context、window_number 与 first/previous/current IDs |
| 研究范围 | 研究 PreviousTurnSettings、reference TurnContext 与窗口 ID 的选择优先级 |
正常路径:先看顺序点
这条路径可以压缩成五步:
- 排除 rollback/incomplete segments。
- 选择最新完成用户 TurnContext。
- 选择最新有效 compact window。
- 必要时回退 SessionMeta/legacy count。
- 安装到新 Session。
图中的箭头不是“可能调用”的依赖图,而是源码中决定可见性和所有权转移的先后关系。前一步没有确认时,后一步不能替它作出更强的成功承诺。
源码机制拆解
Previous settings 服务差异比较
它保留上个有效 Turn 的 model、effort、approval/sandbox 等设置。下一 Turn 能据此判断 model switch、上下文更新和警告,而不是把当前 config 误当成过去事实。
Reference context 有三态
NeverSet 表示历史从未建立 diff 基线;Cleared 表示 compaction/rollback 明确要求下次全量注入;Latest(item) 才允许相对 TurnContext 计算增量。用 Option 无法完整表达扫描中的未知与明确清除。
窗口身份来自新式 CompactedItem
checkpoint 可携带 window_number、first_window_id、previous_window_id、window_id。恢复优先采用最新 surviving checkpoint 的完整组合,使后续 Responses metadata 延续正确窗口。
SessionMeta 是初始窗口后备
从未 compact 的 Thread 可以使用 SessionMeta 的 initial context window identity。若发现 Legacy compaction 缺 window number,旧记录的身份链不可靠,算法退回以 compact 次数估算窗口编号。
Rollback 同时回退设置和窗口相关基线
被排除 Turn 的 TurnContext、WorldState 和 compaction metadata 不能继续影响结果。反向 segment 选择把这些元数据与有效历史一起裁剪。
Python 风格伪代码
下面的伪代码只保留设计职责、状态和失败顺序;它不逐行翻译 Rust,也不借 Python 语法虚构源码中不存在的事务:
def recover_settings_and_window(segments, session_meta):
previous = None
reference = NEVER_SET
latest_checkpoint = None
legacy_compact_count = 0
for segment in surviving_segments_newest_first(segments):
if previous is None and segment.is_completed_real_user_turn:
previous = PreviousTurnSettings.from_context(segment.turn_context)
reference = update_reference_state(reference, segment)
if latest_checkpoint is None and segment.compacted:
latest_checkpoint = segment.compacted
legacy_compact_count += segment.legacy_compaction_count
if latest_checkpoint and latest_checkpoint.has_window_identity():
window = latest_checkpoint.window_identity()
elif legacy_compact_count == 0:
window = session_meta.initial_window_identity
else:
window = legacy_window_fallback(legacy_compact_count)
reference = CLEARED
return previous, reference, window
阅读时要特别看三处:哪个对象拥有可变状态,哪一个 await 是可观察屏障,以及失败后保留的是已提交前缀、未提交后缀,还是完全独立的外部副作用。
失败、取消与恢复
| 故障点 | 已留下的状态 | 可观察结果 | 恢复责任 |
|---|---|---|---|
| 最新 Turn 未完成 | TurnContext 已写但无可靠终态 | 不能作为 previous settings | 继续找更旧完成用户 Turn |
| Rollback 删除最新用户 Turn | 其设置仍在物理日志 | 不得泄漏到恢复结果 | segment skip 同时排除元数据 |
| Legacy compact 缺 window number | 窗口 ID 链不完整 | 不能伪造新式 identity | 计数 fallback 并清除不可靠 reference |
| 把 Cleared 当 NeverSet | 两者下一步都可能全量注入但原因不同 | 调试和后续选择失真 | 内部保留三态再映射 |
这里没有统一的“回滚一切”。内存状态、日志行、SQLite 投影、父子拓扑和工具造成的文件/网络变化分别有自己的提交点。恢复代码只能根据已经存在的权威证据继续,不能用较弱的投影替较强的事实背书。
必须保持的不变量
- previous settings 来自最新存活完成用户 Turn
- 被 rollback 的 metadata 不参与恢复
- 新式 checkpoint 优先于 SessionMeta 初始窗口
- 不完整窗口身份不能被标记为可靠 cache lineage
这些不变量比“最终能 Resume”更严格:正常路径要成立,Writer 竞争、任务取消、坏尾行、投影落后和旧格式兼容时也必须成立。
设计取舍
记录窗口 ID 与设置快照增加 Rollout 元数据,但让恢复后的第一条请求延续与热 Session 相同的差异计算和缓存语义。
源码可以直接证明字段、分支、调用顺序和测试期望;“为什么这样设计”的表述是基于这些事实作出的工程归纳,不把它包装成未公开的产品承诺。
Mini Codex 复刻
在 checkpoint 中保存 window tuple;恢复器把 settings/reference/window 作为一个结果对象返回,测试 rollback 和 incomplete turn 不污染任何字段。
复刻时先验证协议不变量,再补性能优化。一个能在故障注入下说明“留下了什么”的小实现,比一个只在正常路径调用 save() 的演示更接近真实 Runtime。
源码导航
- codex-rs/core/src/session/rollout_reconstruction.rs:PreviousTurnSettings、reference state 和 window 选择
- codex-rs/protocol/src/protocol.rs:TurnContextItem、CompactedItem 与 SessionMeta 窗口字段
- codex-rs/core/src/session/context_window.rs:Session 中窗口状态推进
相邻测试也很重要:
- codex-rs/core/src/session/rollout_reconstruction_tests.rs:窗口 ID、Legacy compact、rollback 和 reference context 的组合测试
本节结论
恢复不只得到消息数组;它还要找出最近一个存活且完成的用户 Turn 设置,并恢复 compaction window number/ID 链,才能让下一 Turn 正确比较配置和延续请求缓存作用域。
评论
登录后即可评论