深入浅出 DeepSeek Harness 第八部:证明与守卫——怎样知道系统真的成立 Chapter 56

从一个 commit 到下一版:这本书怎样更新并收束

这本书锁死在某个 commit,但 DSH 是活的。锁 commit 不是为了停在旧版,是让每一条 SourceEvidence、每一个 bash 实验、每一张图都有一个可复核的具体对象。更新有五维度比较与四类证据刷新,不是批量替换字符串。这是全书最后一章。

Written in Chinese

Source version
dsh-v0.1.7-rc.2
Verified on
Commit
477b4f420553e8a52c2fbccc464d7561b239c443

第 0 秒,你可能在想:这本书锁死在某个 commit,但 DeepSeek Harness 是活的项目,代码一直在前进。我现在读的这些内容,会不会已经过时了?

这是所有技术文档的终极问题。这本书的答案不是「我们会持续更新」这种空话——它有一套严格的更新方法论和一条机器验证链。锁 commit 不是为了永远停在旧版,而是让每一章的每条 SourceEvidence、每个只读 bash 实验、每张 SVG 都有一个可复核的具体对象。

这是全书最后一章。

锁 commit 的意义:可复核性

每一章 frontmatter 都有 sourceVersion、verifiedCommit、lastVerified 三个字段,verifiedCommit 都钉在同一个哈希:477b4f420553e8a52c2fbccc464d7561b239c443。这是一个承诺:这一章里所有 SourceEvidence 引用的路径、行号范围、符号名,在这个 commit 上都对得上。

你不信我?三步验证:

repo="${DSH_SOURCE_DIR:?set DSH_SOURCE_DIR to the official fixed checkout}"
git -C "$repo" rev-parse HEAD

输出应该是 477b4f420553e8a52c2fbccc464d7561b239c443。跑章节里那些只读的 grep/sed 命令,对照 SourceEvidence 的行范围,看内容是否和注释一致。对不上,要么我写错了,要么你 checkout 了别的 commit——不存在「可能是版本不同」的模糊地带。这就是 fixed commit 的全部意义。

更新方法论:建 detached checkout → 五维度比较(graph/symbols/events/config/入口)→ 四类证据刷新(源码引用/可复现实验/叙事审计/最小更新闭包)→ doc-sync gate → 真实 dogfood。三类声明证据等级不同:配置小于类型小于调用点与状态写入。

本节源码依据(2 处)

更新不是批量替换字符串

很多文档更新的做法是:把所有 verifiedCommit: "旧哈希" 批量替换成新哈希,行号大概调调,完事。这是制造漂移最快的方式。

正确的更新第一步:建一个新的 detached checkout,记录新 commit 哈希、版本号、日期;确认它干净——没有未提交修改、没有 stash、工作目录清洁;并且不在老 checkout 上直接改——你需要同时能访问新旧两个 commit 做对比。

然后做五维度比较:

维度比什么
package graph包的依赖关系变了吗?有新增/删除的包吗?
public symbols每个包导出的 API 变了吗?函数改名了吗?参数变了吗?
event vocabulary事件类型有增删吗?envelope schema 变了吗?
config schema配置项有增删改吗?默认值变了吗?
产品入口CLI flag、Web 入口、SDK API 变了吗?

Owner 变化通常跨多章。如果某个模块从一个包移到另一个包,不只是那一章行号变——所有引用它的章节都要更新。这就是为什么「最小更新闭包」要单独成一类证据。

本节源码依据(2 处)

三类声明的证据等级

读源码有三个层次,它们能证明的东西不一样:

声明类型能证明不能证明
配置声明(cordis.yml/package.json)系统可以怎样组合运行时实际用了哪些配置
类型声明(TS 类型)函数允许传什么形状运行时实际传了什么值、错误路径怎么走
调用点 + 状态写入这版实际怎样运行——

配置声明只能证明「可以怎样组合」;类型声明只能证明「允许传什么」;只有调用点与状态写入能证明这版实际怎样运行。 谁调用了这个函数、传了什么参数、事件在哪里 append、状态在哪里改、失败路径留了什么痕迹、恢复从哪里开始——这些才是 internals 书真正要写的东西。

写这本书的每一章,都是从调用点和状态写入反推的,不是从类型签名和配置声明正推的。因为类型正确的代码可能运行时完全错误——类型只承诺形状,不承诺行为。

本节源码依据(4 处)

doc-sync gate:机器验证文档一致性

DSH 项目自带 doc-sync 运行模式,跑 20+ 个验证子任务。这不是 lint 空格——是验证文档与源码的结构一致性:

gate验证什么
verify-cordis-catalog文档里 Cordis API 签名与源码 generated catalog 一致
verify-type-equiv文档里的类型 fence 与源码类型结构等价
verify-md-links所有 markdown 内部链接指向存在的 target
verify-doc-graphs文档图结构一致
verify-package-readme-limitations各包 README 的限制声明合规

这些 gate 跑的是已生成产物与源码的比对——不是「看起来对不对」,而是「机器能证明一致」。任何一个 gate 失败,doc-sync 整体 fail,PR 不能合入。

但机器查不出叙事漂移。 「谁 own 这个状态」变了、恢复路径变了,但代码结构没变——机器查不出来。叙事审计靠人。这是为什么更新流程里,人的判断永远是最后一道。

本节源码依据(5 处)

四类证据分别刷新

更新不是全量重写,是四类证据各自验证:

  1. 源码引用:所有 SourceEvidence 的 path、lines 在新 commit 上重新验证——文件还在吗?行号范围在文件长度内吗?符号名变了吗?函数 rename 时不只是改 note,要确认新名字的使用场景和旧名字一样。
  2. 可复现实验:所有只读 bash 命令在新 commit 上重跑——命令还能执行吗?grep pattern 还命中吗?sed 行号范围还在文件长度内吗?
  3. 叙事审计:每章核心叙事——「谁拥有状态」「失败后留下什么」「恢复从哪里开始」——变了吗?owner 变了、恢复路径变了、失败边界变了,整个故事要重写,不是改行号。这是最容易忘、误导最严重的一类漂移。
  4. 最小更新闭包:56 章的 sourceVersion/verifiedCommit/lastVerified 全部指向新 commit;所有 SourceEvidence 能在新 commit 上命中;部与部、章与章的承接正确;doc-sync gate 全套通过;最后真实 dogfood,不碰源码。

不是每个 commit 都需要更新。 如果新 commit 只改了测试、只修了一个 tool 的 output 格式、只加了一个 CLI flag——只要没改变本书任何一章的核心叙事,更新就是可选的。必须更新的情况是:event vocabulary 变了、核心数据流变了、架构级重构、surface 语义变了。

更新的粒度不是「全书」。 如果只有某一章涉及的实现变了,只需更新那一章;但全部 verifiedCommit 要一起指向新 commit——因为这个字段的含义是「在这个 commit 上已验证过」,不是「在这个 commit 上有变化」。

本节源码依据(2 处)

为什么叙事审计不能省

机器 gate 能查路径存在、行号越界、类型不等价、链接断裂。它查不出的是「叙事漂移」——代码结构没变,但谁拥有状态变了、失败后留的痕迹变了、恢复从哪里开始变了。

举个例子:某个事件原本由 session 包 append,重构后改由 projection 包 append。行号都还在文件里、符号名也没改、类型完全等价——机器 gate 全绿。但「谁拥有这个事件」这个叙事已经是假的。读者按旧叙事去追 ownership,会追错包。

这种漂移机器看不见,只有人逐章核对「谁拥有状态、失败留什么痕迹、恢复从哪里开始」才能抓住。 这就是为什么更新流程里,叙事审计被单列为一类证据,而且排在机器 gate 之后——机器先把能自动查的全查了,人再补机器看不见的那一层。

漂移类型机器能查吗谁来查
路径不存在能doc-sync gate
行号越界能doc-sync gate
类型不等价能verify-type-equiv
链接断裂能verify-md-links
谁拥有状态变了不能叙事审计(人)
失败痕迹变了不能叙事审计(人)
恢复路径变了不能叙事审计(人)
本节源码依据(3 处)

这本书怎么用

最后给读者一张使用地图:想搞懂某个机制,从它的章节读起;想验证某个说法,跳到该章 <details> 里的 SourceEvidence,按行号去 checkout 出来的源码里复跑;想改代码,先读它所在包的 README 与 run-gates 里对应的 gate,确认改完哪些文档会跟着漂移。

这本书不是终点——它是让你在源码里少迷路的那张纸。真正的理解永远在源码里,这本书只是路标。

本节源码依据(2 处)

全书收束

你读完了全书 56 章。从 CLI 入口到 Cordis 组装,从 Turn 循环到工具调度,从事件账本到持久化恢复,从遥测镜像到轨迹重放,从快照测试到包级守卫,从四层安全防线到这一部的「证明与守卫」。

有件事最后再钉一下:这本书不是「教你怎么用 Harness」的用户手册。它是一本 internals——解剖运行时,让你看到每个决策背后的权衡、每个边界存在的理由、每个安全措施防的是什么故障。

这本书的可信度不来自作者的权威。它来自两样东西:

  1. 可复核性——你能 checkout 那个 commit,自己验证每一条证据;
  2. 机器守卫——doc-sync gate 在 CI 里跑,任何可检测的漂移都无法合入。

最好的验证不是相信我写的每一个字。最好的验证是:

git checkout 477b4f420553e8a52c2fbccc464d7561b239c443

然后自己跑命令、自己看代码、自己得出结论。如果你发现我写错了——那就是我写错了,不是「版本不同」、不是「你理解不对」。Fixed commit 的意义就在于消灭这种模糊地带。

这本书只是地图。真正的理解在源码里。

全书完。