dsh-checkpoint-diff 契约(Contract)
August 17, 2026 · View on GitHub
本文档记录 dsh-checkpoint-diff 0.4.x 对外承诺的实际行为,供其他插件、工具与 AI 参考——它描述的是事实,不是对生态的要求。语义变更会进入 CHANGELOG 并在插件版本号中体现。
上游 dsh-checkpoint-rewind 是快照生产者;本文档是消费侧契约——描述我们如何读它的检查点,以及本插件在"从检查点恢复工作区"这一动作上给自己划的安全底线。它不取代、也不修改 rewind 的规范(域 spec 未从 rewind 包导出,本插件在
lib/domain.mjs中同构重声明)。
1. 检查点消费契约(Checkpoint consumption contract)
1.1 记录模型(checkpoints 域)
域 checkpoints,单表 checkpoints,键为检查点 id。双版本消费:rewind
0.4.0 使用域 version 1,0.5.0 使用 version 2——本插件按 v2 打开(介质不存在时
创建 v2),介质为 v1 时回退 v1 打开;rewind 在场时复用其已打开的域(任意版本)。
记录 schema(zod,容错超集:严格性属于生产者 rewind,本插件是只读消费者,
v1/v2 记录都接受):
| 字段 | 类型 | 含义 |
|---|---|---|
id | string | 检查点 id(git provider 为对象 sha,copy provider 为 UUID) |
sessionId | string | 归属会话 |
cwd | string | 归属工作区(绝对路径) |
seq | int ≥ 0 | 会话内序号 |
time | int ≥ 0 | epoch 毫秒 |
provider | 'git' | 'copy' | 快照载体 |
triggerTool | string | 触发该检查点的工具名 |
turn / step | int > 0 | 触发位置(会话轮次/步) |
files / bytes | int ≥ 0 | 快照规模(文件数/字节) |
ref | string | provider 引用(git: 40/64 hex;copy: UUID) |
stepEndSeq? | int ≥ 0 | v1/v2:步结束序号 |
forkSeq? | int ≥ 0 | 仅 v1:fork 血缘序号(v2 移除,血缘改用时间锚定,见 §1.4) |
kind? | 'manual'|'auto'|'guard'|'mutation' | v2(rewind 必填,我们容错):快照来源分类;guard 与 triggerTool==='rewind' 一样标记保护检查点 |
config? / tree? / note? / sessionBoundary? | — | v2:rewind 的配置快照/树 sha/备注/重放边界,本插件不消费(只容忍) |
归属键 = (sessionId, cwd),工作区按 workspaceKeyOf(cwd) 归一化(跨会话合并的基础)。
1.2 快照语义
- 快照是变更前状态:
/diff <from> <to>呈现 from 快照 → to 快照的差异,to不含to之后的变更。 gitprovider:未引用对象(git stash create/commit-tree),只经只读原语访问(diff-tree/show/ls-tree/cat-file -e);ref 入参前按^[0-9a-f]{40,64}$校验。copyprovider:Harness home($DSH_HOME,缺失时~/.dsh)下dsh-checkpoint-rewind/<workspaceKeyHash16>/<uuid>/快照目录 + manifest;ref 按 UUID 校验。- 混合 provider 两端点配对拒绝(响亮报错),不做隐式转换。
1.3 寻址(Addressing)
- 节点地址:id 前缀(任意长度,最短 1 字符)或字面量
latest(最新节点)。 - 前缀歧义 → 报错(
is ambiguous (N matches)),绝不静默取首条。 - 项目范围下歧义时偏好本会话记录。
- 节点显示名:
#短id(8 字符)+ 相对/时钟时间 + 意图标签(如#a1b2c3d4 14:02 · edit README.md)。
1.4 作用域(Scope)
scope=session(默认):当前会话 + 当前工作区键。scope=project:按工作区键合并全部会话,沿/rewindfork 血缘(可选服务sessionQuery.traceSession)组织分支;服务缺席时退化为扁平合并(不报错)。- fork 标记锚点:v1 记录取父会话中带
forkSeq的最后一条记录(fork 发生于其 turn/end);v2 记录(无forkSeq)取父会话中不晚于子会话createdAt的最后一条记录;父侧无记录时回退子会话首条。
1.5 降级矩阵(Degradation matrix)
| 情形 | 行为 |
|---|---|
| 记录被配额剪枝 / 缺失 | 时间线直接不含该节点;diff/回滚报明确错误 |
git 快照对象被 git gc 回收或重克隆丢失 | 节点标记 ⚠ degraded(只读 cat-file -e 探测),默认选择跳过;时间线显示 "N checkpoint(s) degraded";diff/回滚报错点名死节点(如 checkpoint #9312717a (to side) is missing … (bad object …)) |
| 域介质为 v1 / v2(rewind 0.4.0 / 0.5.0) | 双版本打开:v2 优先,version-mismatch 回退 v1;rewind 在场时直接复用其已打开的域(任意版本) |
| 混合 provider 配对 | 响亮拒绝(400) |
sessionQuery 缺席 | 项目范围退化为扁平合并,无分支标记 |
| 会话日志缺失 | 意图标签回退 triggerTool 原文(不报错) |
降级原则:绝不删除任何记录或数据,永远给出可行动的报错。
2. 回滚安全契约(Rollback safety contract)
以下六条是 dsh-checkpoint-diff 对"从检查点恢复工作区"这一动作自身的承诺,全部有测试与集成测试背书。我们认为这是同类操作应有的底线,供其他插件参考;是否采纳由各项目自行判断。
2.1 定位
回滚是唯一写路径,其余一律只读。回滚 = 把节点快照的文件内容写回会话工作区(整节点或单文件)。
2.2 不变量(Invariants)
- 只覆盖写,绝不删除——节点之后新建的文件保留并报告(
leftovers),回滚不删除任何东西。唯一例外见 §2.4(撤销删除恢复自己刚创建的文件)。 - 不越界——不写出工作区根;拒绝穿越(
..)与绝对路径;路径上任何一环是符号链接即拒绝;/\.git|\.dsh/段在任何深度都拒绝。 - 不碰别的存储——绝不写快照存储、git(索引/工作树/历史)、会话;git provider 只用只读原语。
- git provider 前置条件——会话 cwd 必须是仓库根(快照树路径是根相对),否则响亮拒绝。
- 预览先行——应用前必须能产出 dry-run 计划(将恢复/不变/跳过 + 遗留文件清单);HTTP 端点
dryRun: true与/rollback --dry-run均不写盘。 - 每工作区串行——同一工作区的恢复操作串行执行,不做并发交错。
2.3 预览与计划(Preview)
计划字段:files[{rel, action: 'restore'|'unchanged'|'skip', reason?}]、restored/unchanged/skipped 计数、leftovers(节点之后新建、被保留的文件)。预览状态可附带当前工作区 → 目标快照的逐行 diff(只读),应用前可逐文件核对。
2.4 单次撤销(Undo)
- 撤销最近一次恢复:被覆盖文件写回恢复前内容;恢复新建的文件可以被删除("绝不删除"的唯一例外,且仅限恢复自己创建的)。
- 恢复后被改动的文件跳过不动(全部跳过 → 409,不做事)。
- 进程内存状态,重启失效;无 redo;删除前经过与恢复相同的路径校验。
2.5 为什么(理念)
| 不变量 | 对应理念 |
|---|---|
| 绝不删除 | "退得回"的底线:任何时刻都有完整现场可追究 |
| 不越界 / 不碰别的存储 | 信任边界:只承诺改变你明确授权的一个区域 |
| 预览先行 | "应用前可验证":先看清再动手,不是事后解释 |
| 单次撤销 | 误操作有退路;撤销本身也遵守同样的安全线 |
3. API 表面(Stable API surface)
前缀 /checkpoint-diff/api(harness webServer 同源 JSON):
- 读端点(GET,只读):
/api/timeline、/api/summary、/api/file-diff、/api/preview-diff(可选scope=project)。 - 写端点(POST,唯二):
/api/rollback(dryRun 规划 / 应用)、/api/rollback-undo(撤销)。请求体 ≤ 64 KiB、JSON 校验。 - 错误形状:
{ok:false, error},状态码语义见 README 的 HTTP API 表。
稳定承诺:寻址语义(§1.3)、A/M/D 语义、降级语义(§1.5)与回滚不变量(§2.2)不做破坏性变更;确需变更时先进 CHANGELOG 并随 minor 版本发布。
4. 版本与修订
- 本文档与插件版本同轨(当前 0.4.x);契约修订记录在 CHANGELOG 的 [Unreleased] 中累积。
- 对契约的争议请走 Issues;安全相关走 SECURITY.md 的私有上报。