DeepSeek Harness 源码精读 10:看不见却异常结实的骨架

第 10 章 看不见却异常结实的骨架

代码基线:commit 8f86b979a1(2026-10-01)| 0.2.0-rc.1 | 本系列讲次:M9

本章导读

这一章讲这个仓库凭什么可信。

前三章讲"它是什么",这一章讲"它为什么值得信"。三个数量级:42 个门禁脚本、17 个生成器、38 个发布运行时不变式的包。贯穿的纪律是一句话:凡是靠人自觉的约定,都会被写成一个 verify-*.ts。

先看七层测试阶梯:Unit、覆盖率门禁、真实 API e2e、期望输出、性能基准、快照重放、浏览器快照。然后是本章第一处深刻——覆盖率门禁的官方立场:

An uncovered line is often dead code the gate flags for deletion, not a missing test to bolt on.
Line coverage is necessary, never sufficient.

大多数团队把覆盖率当成"要补的洞",dsh 把它当成"该删的尸"。 而且它自己声明覆盖率是最弱的一层,上面还叠了六层。

本章还有一件正事:兑现方法论 L-12。 第 8 章发现那张生成的接缝表之后,我们说过"手写脚本应改造成对生成表的交叉验证"。本章就做了,结果同时暴露了手写表的三处错和生成表的一处漏——如果你只是改用生成表,会一直相信那张表;如果只是继续用手写表,会带着三处错错下去。交叉验证比任选其一更有价值。

学习要点

  • 覆盖率门禁是用来删死代码的,不是用来补测试的
  • 门禁可以豁免,但豁免必须环境性、且在更强的环境补齐
  • 运行时不变式只发布给"独立观察会分叉"的关系,不是每个包都该有
  • 手写与生成都不是免检的,必须互为对照

本章目标

  1. 摸清工程纪律的三个数量级:门禁、生成器、invariant
  2. 理解 per-file 100% 覆盖率门禁的真实立场(不是为了补测试,是为了删死代码)
  3. 看一个真的运行时不变式长什么样
  4. 兑现 L-12:把 M6 的手写体检表拿去和 docs/capability-seams.md 交叉验证

一、工程纪律的三个数量级

类别 数量 说明
门禁脚本 scripts/verify-*.ts 42(另有 28 个配套 .spec.ts,共 70 个文件) 每条约定都有一个可执行检查
生成器 scripts/gen-*.ts 17 产物受新鲜度门禁(verify-* 之一)保护
发布 ./invariant 的包 38 运行时关系也有守门人

一条贯穿的纪律:凡是靠人自觉的约定,都会被写成一个 verify-*.ts。 从 M2 的 verify-cordis-config(!!js 只能在 disabled)到 M5 的包级规范,全是这个模式。


二、测试阶梯的七层

从 docs/testing.md §Tiers 实测抽出:

层 命令 覆盖什么
Unit pnpm run test 包级 tests/** + scripts/**/*.spec.ts;每个注册表都要有 HMR 安全测试(dispose 贡献 fiber,断言清理)
Coverage gate pnpm run test:coverage packages/*/*/src 按文件 100%
Real-API e2e pnpm run test:e2e 带 key 打真实供应商 API,缺 key 自跳过
Owner-local expected output pnpm run test:expected 无 key 的组装 CLI/进程期望
Performance benchmarks pnpm run test:bench Linux PR 门禁;计时代码跑纯 Node,绝不 TSX
Snapshot pnpm run test:snapshot 录制会话重放;父文件名 session[.vN].jsonl
Web browser snapshot pnpm run test:web Chromium 比对 snapshots/web/;模型选择器另跑 WebKit

三、★ 覆盖率门禁的立场:它是为了删死代码

这是本章第一处深刻。docs/testing.md 的原文(脚本第 3 项抽出):

An uncovered line is often dead code the gate flags for deletion, not a missing test to bolt on.
Line coverage is necessary, never sufficient — it proves lines ran, not that the feature works as shipped.

大多数团队把覆盖率当成"要补的洞",dsh 把它当成"该删的尸"。 这个立场差异是根本性的:

  • 补测试的思路:未覆盖 → 写用例 → 覆盖率上升
  • 删代码的思路:未覆盖 → 这行可能是没人走的路 → 删掉 → 覆盖率自然上升

第二条更狠:行覆盖证明"这行跑过",不证明"这个功能以发布形态работает"。 所以 dsh 在覆盖率之上还叠了七层阶梯 —— 覆盖率只是其中一层,而且是最弱的那层。

3.1 一个诚实的例外

Per-file 100% on packages/shell/pwsh-local/src needs a real pwsh: without one its executor suites self-skip and vitest.config.ts exempts the file so pwsh-less hosts stay green, while CI runners ship pwsh and enforce the full bar.

没有 pwsh 的机器豁免这个文件,有 pwsh 的 CI 执行全量标准。 门禁可以豁免,但豁免必须是环境性的、且在更强的环境里补上,不是永久降低标准。


四、运行时不变式:session-invariant

packages/core/session/src/invariant.ts:

模块文档: Package-owned relational invariants for the session event log.  
         Load this companion beside `@deepseek-ai/dsh-invariants` to enable the checks.  
name : session-invariant  
inject: ['invariants']  
行数  : 259  

三个设计点:

  1. 它是 companion,不是主包——必须显式加载。38 个包各自发布一个
  2. inject: ['invariants']——它自己也是一个 Cordis 插件,遵守 M1 讲的那套
  3. AGENTS.md 的纪律:"Publish ./invariant only when independent observations can diverge... Otherwise omit wiring and give the package-specific README reason."

不是每个包都该有不变式。 只有"两个独立观察会分叉"的关系才配。

跨讲回调:M3 §3.9 讲的"派生历史必须等于实际请求"、M4 讲的 turn/step 配平检查,都住在这类 companion 里。它们不是测试断言(跑一次就完),而是在活的运行时持续比对两个本该相等的观察。


五、★★ 兑现 L-12:交叉验证抓到了我自己的三处错

M8 发现 docs/capability-seams.md 是 scripts/gen-doc-graphs.ts 生成的 94 行接缝权威表。我当时立了 L-12:手写脚本应改造成对生成表的交叉验证。

M9 就做了。结果(脚本第 5 组):

5.1 逐键查证结果

ctx 键 Role Owner 实现 消费者
ctx.shell seam shell 3 4
ctx.subprocess seam subprocess 2 7
ctx.terminals seam terminal 1 1
ctx.sandbox seam sandbox 2 2
ctx.lsp seam lsp 1 1

5.2 ★ 三处分歧

① 我的错:tool-bash-persistent 不是 ctx.shell 的消费者

实测 export const inject = ['tools', 'terminals'] —— 它消费的是 ctx.terminals。我在 M6 E-24 把它算成 shell 的 Consumer,错了。

② 我的错:pwsh-sandbox 是替换者,不是并列实现

它自述:"Registers as ctx.shell in place of the local pwsh executor"。生成表也确实只列了 bash-local / bash-sandbox / pwsh-local 三个实现。"4 个 Provider 并存"的说法不准确。

③ 我的错(最严重):ctx.subprocess 与 ctx.sandbox 的 Provider/Consumer 数全错

接缝 我 M6 写的 实测
ctx.subprocess Provider=1,Consumer=0 Provider=2(含 subprocess-ssh),Consumer=7
ctx.sandbox Provider=2(sandbox-local + sandbox-windows-acl) Provider=2(sandbox-local + sandbox-ssh)

ctx.subprocess 的 7 个消费者里包括 bash-local、terminal-bash、lsp-stdio、subagent-acp、subagent-codex、subagent-claude-code —— 我在 M6 写"Consumer=0",等于对这条接缝的理解完全错了。

而且暴露了一个我根本没看过的包组:packages/ssh/(subprocess-ssh、sandbox-ssh)。M6 我逐个组枚举时跳过了它。

④ 生成表的漏:tool-bash-persistent 在整张表里出现 0 次

它确实是 ctx.terminals 的消费者(实测代码),但 ctx.terminals 那行的 Direct consumers 只列了 tool-terminal。生成表在这一处不完整。

5.3 这一节的结论

交叉验证比"任选其一"更有价值——它同时暴露了手写表的三处错和生成表的一处漏。

如果我只是改用生成表(M8 的做法),我会一直相信那张表;如果我只是继续用手写表(M6 的做法),我会带着三处错一直错下去。两个都不够,必须对质。

M6 讲义的勘误见下表。



本章实验(附录)

六、动手验证

export PATH="/opt/homebrew/bin:$PATH"  
cd /Users/ygs/ygs/deepseek-harness  
node --import tsx/esm "ygsdoc/学习笔记/labs/M9-quality-lab.ts"  

五组输出:① 三个数量级;② 七层测试阶梯;③ 覆盖率门禁的三句官方立场原文;④ session-invariant 的形态;⑤ 交叉验证与三处分歧。

M9 通过标准:能说出 ctx.subprocess 的 7 个消费者里为什么会有 lsp-stdio 和 subagent-codex——因为它们都需要拉起真实子进程,接缝之间互相消费(这正是 M6 E-25 记录的那条,只是我当时找错了例子)。


实验脚本:labs/M9-quality-lab.ts

运行(在仓库根目录):

export PATH="/opt/homebrew/bin:$PATH"  
cd /Users/ygs/ygs/deepseek-harness  
node --import tsx/esm "dsh-源码精读/labs/M9-quality-lab.ts"  

预期输出(本机实测,任何一行对不上就说明基线变了):

1) 工程纪律的三个数量级  
────────────────────────────────────────────────────────────────────────  
   门禁脚本 scripts/verify-*.ts   : 42  
   生成器   scripts/gen-*.ts     : 17  
   发布 ./invariant 的包         : 38  
2) 测试阶梯(docs/testing.md §Tiers)  
────────────────────────────────────────────────────────────────────────  
   Unit                           pnpm run test  
     Every registry gets an HMR-safety test (dispose the contributing fiber, as…  
   Coverage gate                  pnpm run test:coverage  
     An uncovered line is often dead code the gate flags for deletion, not a mi…  
   Real-API e2e                   pnpm run test:e2e  
     …  
   Owner-local expected output    pnpm run test:expected  
     Drivers use `*.expected.e2e.ts` beside `tests/expected/`; CI runs built ex…  
   Performance benchmarks         pnpm run test:bench  
     It builds libraries and workers; timed code runs under plain Node, never T…  
   Snapshot                       pnpm run test:snapshot  
     Parent filenames are `session[.vN].jsonl`; child roles are `session.<ordin…  
   Web browser snapshot           pnpm run test:web  
     CI enforces read-only `DSH_SNAPSHOT=replay`; record/refresh stay local, wi…  
   共 7 层  
3) per-file 100% 门禁的官方立场(原文抽取)  
────────────────────────────────────────────────────────────────────────  
   An uncovered line is often dead code the gate flags for deletion, not a missing test to bolt on.  
   Line coverage is necessary, never sufficient — it proves lines ran, not that the feature works as shipped.  
   Per-file 100% on `packages/shell/pwsh-local/src` needs a real `pwsh`: without one its executor suites self-skip and `vitest.  
4) 运行时不变式:session-invariant  
────────────────────────────────────────────────────────────────────────  
   模块文档: Package-owned relational invariants for the session event log. Load this companion beside `@deepseek-ai/dsh-invariants` to enable the checks.  @module @deepseek-ai/dsh-session/invariant  
   name : session-invariant  
   inject: ['invariants']  
   行数  : 259  
   发布形态: package.json exports["./invariant"] → 构建产物已存在  
   → 38 个包各自发布一个 ./invariant companion;AGENTS.md 规定只在"独立观察会分叉"时才发布  
5) ★★ 交叉验证:M6 手工体检表 vs docs/capability-seams.md(生成物)  
────────────────────────────────────────────────────────────────────────  
   生成表列: ctx key | Role | Owner | Implementations | Direct consumers | Companion plugins | Note  
   全量接缝行数: 94  
   M6 手工枚举的 5 个执行接缝,逐个到生成表里查证:  
   …(完整输出见运行脚本)  

本章的勘误条目见 附录 A · 勘误总表。