从一个 commit 到下一版:这本书怎样更新并收束
这本书锁死在某个 commit,但 DSH 是活的。锁 commit 不是为了停在旧版,是让每一条 SourceEvidence、每一个 bash 实验、每一张图都有一个可复核的具体对象。更新有五维度比较与四类证据刷新,不是批量替换字符串。这是全书最后一章。
Written in Chinese
第 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 的全部意义。
本节源码依据(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 处)
四类证据分别刷新
更新不是全量重写,是四类证据各自验证:
- 源码引用:所有 SourceEvidence 的 path、lines 在新 commit 上重新验证——文件还在吗?行号范围在文件长度内吗?符号名变了吗?函数 rename 时不只是改 note,要确认新名字的使用场景和旧名字一样。
- 可复现实验:所有只读 bash 命令在新 commit 上重跑——命令还能执行吗?grep pattern 还命中吗?sed 行号范围还在文件长度内吗?
- 叙事审计:每章核心叙事——「谁拥有状态」「失败后留下什么」「恢复从哪里开始」——变了吗?owner 变了、恢复路径变了、失败边界变了,整个故事要重写,不是改行号。这是最容易忘、误导最严重的一类漂移。
- 最小更新闭包: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——解剖运行时,让你看到每个决策背后的权衡、每个边界存在的理由、每个安全措施防的是什么故障。
这本书的可信度不来自作者的权威。它来自两样东西:
- 可复核性——你能 checkout 那个 commit,自己验证每一条证据;
- 机器守卫——doc-sync gate 在 CI 里跑,任何可检测的漂移都无法合入。
最好的验证不是相信我写的每一个字。最好的验证是:
git checkout 477b4f420553e8a52c2fbccc464d7561b239c443
然后自己跑命令、自己看代码、自己得出结论。如果你发现我写错了——那就是我写错了,不是「版本不同」、不是「你理解不对」。Fixed commit 的意义就在于消灭这种模糊地带。
这本书只是地图。真正的理解在源码里。
全书完。