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 记录都接受):

字段类型含义
idstring检查点 id(git provider 为对象 sha,copy provider 为 UUID)
sessionIdstring归属会话
cwdstring归属工作区(绝对路径)
seqint ≥ 0会话内序号
timeint ≥ 0epoch 毫秒
provider'git' | 'copy'快照载体
triggerToolstring触发该检查点的工具名
turn / stepint > 0触发位置(会话轮次/步)
files / bytesint ≥ 0快照规模(文件数/字节)
refstringprovider 引用(git: 40/64 hex;copy: UUID)
stepEndSeq?int ≥ 0v1/v2:步结束序号
forkSeq?int ≥ 0仅 v1:fork 血缘序号(v2 移除,血缘改用时间锚定,见 §1.4)
kind?'manual'|'auto'|'guard'|'mutation'v2(rewind 必填,我们容错):快照来源分类;guardtriggerTool==='rewind' 一样标记保护检查点
config? / tree? / note? / sessionBoundary?v2:rewind 的配置快照/树 sha/备注/重放边界,本插件不消费(只容忍)

归属键 = (sessionId, cwd),工作区按 workspaceKeyOf(cwd) 归一化(跨会话合并的基础)。

1.2 快照语义

  • 快照是变更前状态:/diff <from> <to> 呈现 from 快照 → to 快照的差异,to 不含 to 之后的变更。
  • git provider:未引用对象(git stash create/commit-tree),只经只读原语访问(diff-tree/show/ls-tree/cat-file -e);ref 入参前按 ^[0-9a-f]{40,64}$ 校验。
  • copy provider: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:按工作区键合并全部会话,沿 /rewind fork 血缘(可选服务 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)

  1. 只覆盖写,绝不删除——节点之后新建的文件保留并报告(leftovers),回滚不删除任何东西。唯一例外见 §2.4(撤销删除恢复自己刚创建的文件)。
  2. 不越界——不写出工作区根;拒绝穿越(..)与绝对路径;路径上任何一环是符号链接即拒绝;/\.git|\.dsh/ 段在任何深度都拒绝。
  3. 不碰别的存储——绝不写快照存储、git(索引/工作树/历史)、会话;git provider 只用只读原语。
  4. git provider 前置条件——会话 cwd 必须是仓库根(快照树路径是根相对),否则响亮拒绝。
  5. 预览先行——应用前必须能产出 dry-run 计划(将恢复/不变/跳过 + 遗留文件清单);HTTP 端点 dryRun: true/rollback --dry-run 均不写盘。
  6. 每工作区串行——同一工作区的恢复操作串行执行,不做并发交错。

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 的私有上报。