状态: Draft
组件: Checkpoint 文件快照层、Runtime Restore / CheckpointDiff / RunDiffSummary、Web/TUI 代码变更展示
日期: 2026-05-10
相关技术: Per-Edit Snapshot, Touched Files Rollback, Checkpoint Restore, Run-Scoped Diff, v_next, Guard Checkpoint
1. 摘要
本 RFC 针对 NeoCode Checkpoint 当前语义过重的问题提出收敛方案:将 checkpoint 文件回退与 run 级 diff 从“历史 tracked-files checkpoint 状态”收敛为 Run-Touched agent 文件回退语义。
当前实现中,Finalize 会把 pathToVersions 中所有历史已追踪文件写入 checkpoint meta。这里的“全量”不是全 workspace snapshot,而是 全 tracked files snapshot:它不会扫描整个工作区,但会把所有曾被 checkpoint 系统追踪过的文件都带入后续 checkpoint。这让系统更方便恢复到多轮以前的历史 tracked 状态,但也让语义超出 Claude-like 的 touched-file rollback:未被当前 run agent 触碰的历史文件,可能进入 restore / diff 的候选范围。
本方案选择更明确的产品语义:
- 回退范围:只处理当前 run 中 agent 实际触碰过的文件。
- Diff 范围:只展示当前 run 中 agent touched files 的净变化。
- 用户外部修改保护:未被 agent 触碰的用户修改、删除、创建不被恢复、不进入 run diff。
- 保留 per-edit 核心:继续保留 pre-write capture、post-delete、版本链、文件存在性、目录和 mode 元信息。
- 删除全 tracked 扩张语义:停止把
pathToVersions 作为 checkpoint/restore/diff 范围扩张来源。
2. 背景与问题
当前 checkpoint 系统最初的核心能力是 per-edit capture:工具准备写文件前,先捕获该文件的旧状态。这个模型天然适合 agent-scoped touched-file rollback:agent 改过什么,就能恢复什么;agent 没碰过什么,就不动什么。
后续为了修复恢复到历史 checkpoint 时的新文件残留、guard 路径遗漏、run diff 被外部修改污染等问题,引入了更强的 tracked-files checkpoint 语义:
Finalize 从 pending-only 改成遍历 pathToVersions,每个 checkpoint 记录所有历史已追踪文件的最新版本。
Restore 在部分路径中合并 target / guard / related checkpoint,甚至曾经合并全局 pathToVersions,以避免遗漏历史 tracked 文件。
FinalizeWithExactState 和 DiffCheckpointsToCheckpoint 进一步让 checkpoint diff 更接近“目标 checkpoint 精确结束态查询”。
- run rollback baseline、workspace drift、run-end state 记录被加入,用来支撑更复杂的 diff 和 restore 展示链路。
这些增强不是全 workspace snapshot,但已经超出了“只处理本 run agent touched files”的最小语义。
2.1 当前语义与 Claude-like 语义不完全一致
如果用户理解的 checkpoint 是:
恢复 agent 在本轮 run 中修改过的文件。
那么当前全 tracked-files checkpoint 会显得过重。因为它关注的不只是本 run touched files,而是所有历史已追踪文件在 checkpoint 之间的状态。
2.2 用户外部修改边界变复杂
示例:工作区原本有 A/B/C/D/E。
- 用户手动删除
B。
- 用户手动修改
C。
- agent 在下一轮修改
C。
在 run-touched 语义下:
- agent 首次触碰
C 前捕获的是“用户已修改后的 C”。
- rollback 只恢复
C 到该状态。
B 没被 agent 触碰,所以不会被恢复。
这是符合用户直觉的:checkpoint 不应撤销用户自己对 B 的删除。
2.3 多轮历史恢复能力与 run-touched 语义存在取舍
全 tracked-files checkpoint 的价值是:每个 checkpoint 更像一个“历史已追踪文件集合的状态点”,恢复到多轮以前时,系统有更多上下文去处理历史 tracked 文件。
但 run-touched 语义要求更窄:
- 当前 run 没碰的文件,不应被 restore/diff 处理。
- checkpoint 不表达整个 tracked workspace 的历史状态。
- diff 不回答“世界最后变成什么”,只回答“agent 对 touched files 造成了什么净变化”。
3. 典型用户场景
场景 1:用户手动删除未 touched 文件,restore 不应恢复
当前风险: 旧 tracked 文件可能被纳入 restore / diff 候选,系统需要大量 guard、related checkpoint、drift 逻辑避免误处理。
新行为: 如果本 run agent 没触碰 B,restore run 时不处理 B。用户删除的 B 保持删除状态。
场景 2:用户先修改文件,agent 后修改同一文件
旧行为目标: 系统试图把 checkpoint 表达为历史 tracked 状态,需要推导目标 checkpoint 的结束态。
新行为: agent 修改 C 前捕获 C_before_agent。restore 时写回 C_before_agent。用户在 agent 前做的修改被保留。
场景 3:agent 创建新文件后 restore
新行为: agent 创建 new.go 前捕获 Existed=false。restore run 时删除 new.go。
场景 4:agent 删除文件后 restore
新行为: agent 删除 old.go 前捕获内容、mode 和文件类型。删除后补录 post-delete。restore run 时恢复 old.go 的原内容和权限。
场景 5:run diff 只展示 agent touched files
新行为: run diff 的文件集合来自本 run per-edit checkpoints 的 touched hashes。未 touched 文件的用户修改、删除、创建都不进入 diff。
4. 设计目标
本方案要求同时满足:
- checkpoint restore 默认遵循 agent-touched 语义,不恢复未 touched 文件。
- run diff 只展示 agent 在当前 run 中触碰过的文件净变化。
- 用户外部修改默认受保护:未 touched 文件不进入 affected set。
- 保留 per-edit 版本链和 pre-write capture 的核心优势。
- 保留 undo restore,但 undo 的范围也必须是本次 restore affected set。
- 删除或停止使用全 tracked-files checkpoint 作为范围扩张机制。
- 保持公开 RPC wire shape 尽量稳定,只改变语义和字段填充。
5. 非目标
本 RFC 不处理:
- 不实现全 workspace snapshot。
- 不尝试恢复用户在 run 外或 run 中对未 touched 文件的修改。
- 不保证任意历史 checkpoint 能表达所有历史 tracked files 的完整状态。
- 不删除
pathToVersions 内部索引;它仍用于版本编号、v_next 查询、索引重建。
- 不重做 Web/TUI 的视觉设计,只调整它们消费 diff/restore 语义的预期。
- 不改变 session checkpoint 的消息/head 恢复语义。
6. 核心设计
6.1 Checkpoint 范围:从 tracked-files full snapshot 收敛为 run touched set
当前 Finalize 的“全量”含义是:遍历 pathToVersions,把所有历史已追踪文件写入 checkpoint meta。
新设计将 checkpoint 文件范围收敛为 affected set:
type RunTouchedSet struct {
RunID string
Hashes map[string]struct{}
}
affected set 来源:
- 本 run 中所有
CapturePreWrite 成功的路径。
- 本 run 中所有
CapturePostDelete 记录的路径。
- 由文件工具明确报告的 moved/copied/deleted source/target 路径。
pathToVersions 仍保存全局版本链,但不能作为 restore/diff 范围来源。
这样设计的原因是:范围来源必须是“agent 实际触碰过什么”,而不是“checkpoint 系统历史上知道什么”。这能避免历史 tracked 文件污染当前 run 的 restore/diff。
6.2 Finalize:恢复为 pending / touched-only
Finalize 不再遍历 pathToVersions。
新行为:
Finalize(checkpointID) 只写当前 pending hashes。
FinalizeWithExactState(checkpointID) 只为当前 pending hashes 写 pre-write baseline 和 exact end state。
- 如果 pending 为空,不创建 code checkpoint。
Reset() 清空 pending,避免跨 turn 污染。
保留 FinalizePending 的概念,但语义调整为“为指定 affected set 创建 restore guard”,不能再依赖全 tracked checkpoint fallback。
这样设计的原因是:pending 是本轮工具执行确实捕获到的 touched files。用 pending 作为 checkpoint 范围,可以保证 checkpoint meta 不携带历史无关文件。
6.3 Run restore:只恢复本 run affected files
restore 到 run 起点时:
- 收集目标 run 的 affected hashes。
- 对每个 hash,读取该 run 内首次触碰前的版本作为 before state。
- 写回 before state:
Existed=false → 删除路径。
IsDir=true → 创建目录并恢复 mode。
- 文件存在 → 写回内容和 mode。
- 未出现在 affected set 的文件一律不处理。
restore 到 run 内某个 checkpoint 时:
- affected hashes = 该 run 中从目标 checkpoint 之后到当前仍需要撤销的 touched hashes。
- 对目标 checkpoint 前已经 touched 的文件,恢复到目标 checkpoint 的 exact end state。
- 对目标 checkpoint 后才首次 touched 的文件,恢复到首次触碰前状态。
- 未 touched 文件不处理。
这样设计的原因是:restore 的目标不是重建工作区世界态,而是撤销 agent 对 touched files 的影响。
6.4 Undo restore:对 affected set 做 restore 前精确快照
当前 guard 逻辑依赖 FinalizePending 和 fallback checkpoint,语义复杂。
新设计:执行 restore 前,先对本次 restore 的 affected set 做精确快照:
guardID := NewCheckpointID()
CaptureExactState(guardID, affectedHashes)
undo restore 时:
- 使用
RestoreExact(guardID)。
- 只恢复 guard 中记录的 affected files。
- 不依赖最近 end-of-turn checkpoint fallback。
这样设计的原因是:undo restore 应恢复“restore 前被本次 restore 影响的文件状态”,不需要扩大到历史 tracked files。
6.5 Run diff:before = 首次触碰前,after = run-end touched state
CheckpointDiff(scope=run) 新语义:
- 收集该 run 的 affected hashes。
- before = 每个 hash 在该 run 内首次触碰前的 version。
- after = run 结束时该 hash 的 exact state。
- before 与 after 相同则不展示。
- 未 touched 文件不参与。
RunEndCapture 保留,但只针对 affected hashes。
这样设计的原因是:run diff 应回答“agent 对自己触碰过的文件造成了什么净变化”,不应回答“整个工作区最后世界态是什么”。
6.6 删除跨 run tracked-file 过滤与 drift baseline
停止使用这些逻辑作为 run diff 正确性的基础:
prevFileVersions 过滤历史文件。
- run rollback baseline 持久化。
- workspace drift rebase。
- 通过全 tracked checkpoint 推导 target checkpoint diff。
这些逻辑是为“历史 tracked checkpoint 状态”服务的。run-touched 语义下,affected set 已经把范围限定到当前 run agent touched files,不需要再靠跨 run baseline 修正。
6.7 保留 v_next,但降低其职责
v_next 仍可用于:
- 读取某个 pre-write version 之后的状态。
- 兼容旧 checkpoint 缺少 exact end state 的场景。
- 测试和历史数据迁移时的 fallback。
但新路径优先使用 exact state:
- before 使用首次 pre-write capture。
- after 使用 run-end exact state 或 target checkpoint exact state。
- v_next 只作为兼容 fallback,不再作为主要语义来源。
7. 与现有模块的关系
checkpoint
Finalize 改回 pending-only。
FinalizeWithExactState 仅处理 pending / affected hashes。
Restore 移除 pathToVersions 范围扩张和全 tracked 语义。
RunAggregateDiff 改为 run touched diff,删除 prevFileVersions 过滤和全 tracked 相关分支。
DiffCheckpointsToCheckpoint 若保留,只能基于传入 run affected hashes;否则删除并由 run-touched diff 替代。
runtime
createEndOfTurnCheckpoint 继续只在有 workspace write 时创建 checkpoint,但 checkpoint 内容必须是本 turn pending。
restoreCheckpointCore 先计算 affected set,再创建 exact guard,再 restore。
CheckpointDiff(scope=run) 调用 run-touched diff,不再围绕 target checkpoint 的全 tracked 精确态查询。
EventRunDiffSummary 使用同一套 run-touched diff。
- 删除 run rollback baseline / workspace drift 对 run diff 的核心依赖。
session
- checkpoint record / session checkpoint 结构保持不变。
CodeCheckpointRef 仍指向 per-edit checkpoint。
- session messages/head restore 保持原行为。
gateway
CheckpointDiffInput.Scope / RunID wire shape 保持。
CheckpointDiffResult 尽量保持字段兼容。
- 与 drift/baseline 相关字段若存在,停止填充或返回空值,并更新文档说明。
web / tui
- diff 展示语义改为 agent touched files。
- restore / undo restore 文案应避免暗示“恢复整个工作区”。
- run diff summary 只展示 agent touched files 的净变化。
docs
- 更新
pr-checkpoint-restore-fixes.md,删除“Finalize 全量快照”作为目标设计的表述。
- 更新 award/checkpoint 材料:说明 phantom5099 原始核心是 per-edit touched-file 版本链;全 tracked checkpoint 是后续为历史 restore 完整性引入的增强,不作为最终产品语义。
8. 行为变化
| 场景 |
当前行为 |
新行为 |
| restore 到多轮以前 checkpoint |
尝试恢复历史已追踪文件状态 |
只恢复目标 run / affected set touched files |
| run diff |
可能包含历史 tracked files 的过滤/推导结果 |
只包含本 run agent touched files |
| 未 touched 文件被用户删除 |
可能需要 drift/guard 逻辑避免误恢复 |
永远不处理 |
| checkpoint meta |
可包含所有历史 tracked files |
只包含本 turn/run touched files |
| undo restore |
guard/fallback/related checkpoint 复杂链路 |
exact guard 记录本次 affected set |
| 多轮历史恢复能力 |
更强,能表达历史 tracked 状态 |
减弱,只撤销 agent touched files |
9. 测试场景
- 用户删除未 touched 文件
B,agent 修改 C;restore run 后只恢复 C,不恢复 B。
- 用户先修改
C,agent 后修改 C;restore 后 C 回到用户修改后的状态。
- agent 创建
new.go;restore 后删除 new.go。
- agent 删除
old.go;restore 后恢复 old.go 的内容和 mode。
- agent 移动文件;restore 后源路径和目标路径回到 agent 首次触碰前状态。
- 同一 run 中
cp1 修改 A、cp2 修改 B;restore 到 cp1 时撤销 B,并使 A 回到 cp1 结束态。
- restore 后 undo restore 能恢复 restore 前 affected files。
- run diff 只展示本 run touched files。
- 未 touched 文件的用户修改、删除、创建不进入 run diff。
- 文件在 run 内改了又改回原值,run diff 为空。
- agent 创建后又删除 transient file,run diff 为空或不展示该文件。
- 旧 checkpoint 缺少 exact state 时,v_next fallback 仍可兼容读取。
CheckpointDiff(scope=run) 缺少 run_id 时仍返回参数错误。
- Web/TUI 对
CheckpointDiffResult 的解析测试保持通过。
10. 假设与默认决策
- 产品语义选择 Run-Touched:只回退和展示当前 run 中 agent 实际触碰过的文件。
- NeoCode 不再追求 checkpoint 表达所有历史 tracked files 的完整状态。
- 不实现全 workspace snapshot。
pathToVersions 保留为内部索引,但不能作为 restore/diff 范围扩张来源。
- 新 checkpoint 只保证 agent touched files 的 rollback/diff 正确性。
- 旧 checkpoint 数据需要兼容读取,但可以降级为 best-effort v_next fallback。
- 与 drift/baseline 相关的公开字段如果已经存在,优先保留 wire shape,停止填充复杂语义。
11. 一句话结论
Checkpoint 当前的全 tracked-files checkpoint 设计并不是全 workspace snapshot,但它确实超出了“只回退 agent 本 run touched files”的 Claude-like 语义。新方案将 checkpoint restore 和 run diff 收敛为 Run-Touched agent 文件回退模型:agent 碰过什么,就记录什么、展示什么、恢复什么;agent 没碰过的用户修改不进入系统处理范围。这样会牺牲恢复到多轮以前历史 tracked 状态的能力,但换来更清晰、更安全、更符合用户直觉的 rollback / diff 语义。
状态: Draft
组件: Checkpoint 文件快照层、Runtime Restore / CheckpointDiff / RunDiffSummary、Web/TUI 代码变更展示
日期: 2026-05-10
相关技术: Per-Edit Snapshot, Touched Files Rollback, Checkpoint Restore, Run-Scoped Diff, v_next, Guard Checkpoint
1. 摘要
本 RFC 针对 NeoCode Checkpoint 当前语义过重的问题提出收敛方案:将 checkpoint 文件回退与 run 级 diff 从“历史 tracked-files checkpoint 状态”收敛为 Run-Touched agent 文件回退语义。
当前实现中,
Finalize会把pathToVersions中所有历史已追踪文件写入 checkpoint meta。这里的“全量”不是全 workspace snapshot,而是 全 tracked files snapshot:它不会扫描整个工作区,但会把所有曾被 checkpoint 系统追踪过的文件都带入后续 checkpoint。这让系统更方便恢复到多轮以前的历史 tracked 状态,但也让语义超出 Claude-like 的 touched-file rollback:未被当前 run agent 触碰的历史文件,可能进入 restore / diff 的候选范围。本方案选择更明确的产品语义:
pathToVersions作为 checkpoint/restore/diff 范围扩张来源。2. 背景与问题
当前 checkpoint 系统最初的核心能力是 per-edit capture:工具准备写文件前,先捕获该文件的旧状态。这个模型天然适合 agent-scoped touched-file rollback:agent 改过什么,就能恢复什么;agent 没碰过什么,就不动什么。
后续为了修复恢复到历史 checkpoint 时的新文件残留、guard 路径遗漏、run diff 被外部修改污染等问题,引入了更强的 tracked-files checkpoint 语义:
Finalize从 pending-only 改成遍历pathToVersions,每个 checkpoint 记录所有历史已追踪文件的最新版本。Restore在部分路径中合并 target / guard / related checkpoint,甚至曾经合并全局pathToVersions,以避免遗漏历史 tracked 文件。FinalizeWithExactState和DiffCheckpointsToCheckpoint进一步让 checkpoint diff 更接近“目标 checkpoint 精确结束态查询”。这些增强不是全 workspace snapshot,但已经超出了“只处理本 run agent touched files”的最小语义。
2.1 当前语义与 Claude-like 语义不完全一致
如果用户理解的 checkpoint 是:
那么当前全 tracked-files checkpoint 会显得过重。因为它关注的不只是本 run touched files,而是所有历史已追踪文件在 checkpoint 之间的状态。
2.2 用户外部修改边界变复杂
示例:工作区原本有
A/B/C/D/E。B。C。C。在 run-touched 语义下:
C前捕获的是“用户已修改后的 C”。C到该状态。B没被 agent 触碰,所以不会被恢复。这是符合用户直觉的:checkpoint 不应撤销用户自己对
B的删除。2.3 多轮历史恢复能力与 run-touched 语义存在取舍
全 tracked-files checkpoint 的价值是:每个 checkpoint 更像一个“历史已追踪文件集合的状态点”,恢复到多轮以前时,系统有更多上下文去处理历史 tracked 文件。
但 run-touched 语义要求更窄:
3. 典型用户场景
场景 1:用户手动删除未 touched 文件,restore 不应恢复
当前风险: 旧 tracked 文件可能被纳入 restore / diff 候选,系统需要大量 guard、related checkpoint、drift 逻辑避免误处理。
新行为: 如果本 run agent 没触碰
B,restore run 时不处理B。用户删除的B保持删除状态。场景 2:用户先修改文件,agent 后修改同一文件
旧行为目标: 系统试图把 checkpoint 表达为历史 tracked 状态,需要推导目标 checkpoint 的结束态。
新行为: agent 修改
C前捕获C_before_agent。restore 时写回C_before_agent。用户在 agent 前做的修改被保留。场景 3:agent 创建新文件后 restore
新行为: agent 创建
new.go前捕获Existed=false。restore run 时删除new.go。场景 4:agent 删除文件后 restore
新行为: agent 删除
old.go前捕获内容、mode 和文件类型。删除后补录 post-delete。restore run 时恢复old.go的原内容和权限。场景 5:run diff 只展示 agent touched files
新行为: run diff 的文件集合来自本 run per-edit checkpoints 的 touched hashes。未 touched 文件的用户修改、删除、创建都不进入 diff。
4. 设计目标
本方案要求同时满足:
5. 非目标
本 RFC 不处理:
pathToVersions内部索引;它仍用于版本编号、v_next 查询、索引重建。6. 核心设计
6.1 Checkpoint 范围:从 tracked-files full snapshot 收敛为 run touched set
当前
Finalize的“全量”含义是:遍历pathToVersions,把所有历史已追踪文件写入 checkpoint meta。新设计将 checkpoint 文件范围收敛为 affected set:
affected set 来源:
CapturePreWrite成功的路径。CapturePostDelete记录的路径。pathToVersions仍保存全局版本链,但不能作为 restore/diff 范围来源。这样设计的原因是:范围来源必须是“agent 实际触碰过什么”,而不是“checkpoint 系统历史上知道什么”。这能避免历史 tracked 文件污染当前 run 的 restore/diff。
6.2 Finalize:恢复为 pending / touched-only
Finalize不再遍历pathToVersions。新行为:
Finalize(checkpointID)只写当前 pending hashes。FinalizeWithExactState(checkpointID)只为当前 pending hashes 写 pre-write baseline 和 exact end state。Reset()清空 pending,避免跨 turn 污染。保留
FinalizePending的概念,但语义调整为“为指定 affected set 创建 restore guard”,不能再依赖全 tracked checkpoint fallback。这样设计的原因是:pending 是本轮工具执行确实捕获到的 touched files。用 pending 作为 checkpoint 范围,可以保证 checkpoint meta 不携带历史无关文件。
6.3 Run restore:只恢复本 run affected files
restore 到 run 起点时:
Existed=false→ 删除路径。IsDir=true→ 创建目录并恢复 mode。restore 到 run 内某个 checkpoint 时:
这样设计的原因是:restore 的目标不是重建工作区世界态,而是撤销 agent 对 touched files 的影响。
6.4 Undo restore:对 affected set 做 restore 前精确快照
当前 guard 逻辑依赖
FinalizePending和 fallback checkpoint,语义复杂。新设计:执行 restore 前,先对本次 restore 的 affected set 做精确快照:
undo restore 时:
RestoreExact(guardID)。这样设计的原因是:undo restore 应恢复“restore 前被本次 restore 影响的文件状态”,不需要扩大到历史 tracked files。
6.5 Run diff:before = 首次触碰前,after = run-end touched state
CheckpointDiff(scope=run)新语义:RunEndCapture保留,但只针对 affected hashes。这样设计的原因是:run diff 应回答“agent 对自己触碰过的文件造成了什么净变化”,不应回答“整个工作区最后世界态是什么”。
6.6 删除跨 run tracked-file 过滤与 drift baseline
停止使用这些逻辑作为 run diff 正确性的基础:
prevFileVersions过滤历史文件。这些逻辑是为“历史 tracked checkpoint 状态”服务的。run-touched 语义下,affected set 已经把范围限定到当前 run agent touched files,不需要再靠跨 run baseline 修正。
6.7 保留 v_next,但降低其职责
v_next 仍可用于:
但新路径优先使用 exact state:
7. 与现有模块的关系
checkpoint
Finalize改回 pending-only。FinalizeWithExactState仅处理 pending / affected hashes。Restore移除pathToVersions范围扩张和全 tracked 语义。RunAggregateDiff改为 run touched diff,删除prevFileVersions过滤和全 tracked 相关分支。DiffCheckpointsToCheckpoint若保留,只能基于传入 run affected hashes;否则删除并由 run-touched diff 替代。runtime
createEndOfTurnCheckpoint继续只在有 workspace write 时创建 checkpoint,但 checkpoint 内容必须是本 turn pending。restoreCheckpointCore先计算 affected set,再创建 exact guard,再 restore。CheckpointDiff(scope=run)调用 run-touched diff,不再围绕 target checkpoint 的全 tracked 精确态查询。EventRunDiffSummary使用同一套 run-touched diff。session
CodeCheckpointRef仍指向 per-edit checkpoint。gateway
CheckpointDiffInput.Scope/RunIDwire shape 保持。CheckpointDiffResult尽量保持字段兼容。web / tui
docs
pr-checkpoint-restore-fixes.md,删除“Finalize 全量快照”作为目标设计的表述。8. 行为变化
9. 测试场景
B,agent 修改C;restore run 后只恢复C,不恢复B。C,agent 后修改C;restore 后C回到用户修改后的状态。new.go;restore 后删除new.go。old.go;restore 后恢复old.go的内容和 mode。cp1修改A、cp2修改B;restore 到cp1时撤销B,并使A回到cp1结束态。CheckpointDiff(scope=run)缺少run_id时仍返回参数错误。CheckpointDiffResult的解析测试保持通过。10. 假设与默认决策
pathToVersions保留为内部索引,但不能作为 restore/diff 范围扩张来源。11. 一句话结论
Checkpoint 当前的全 tracked-files checkpoint 设计并不是全 workspace snapshot,但它确实超出了“只回退 agent 本 run touched files”的 Claude-like 语义。新方案将 checkpoint restore 和 run diff 收敛为 Run-Touched agent 文件回退模型:agent 碰过什么,就记录什么、展示什么、恢复什么;agent 没碰过的用户修改不进入系统处理范围。这样会牺牲恢复到多轮以前历史 tracked 状态的能力,但换来更清晰、更安全、更符合用户直觉的 rollback / diff 语义。