Volume 2 · Chapter 34

工程基础设施:让 1292 个包协同的机器

全书最后一章讲「支撑这一切的机器」:类型图(typert)、运行时诊断(invariants)、守卫策略(guard)、预设与编排(preset / bundle / boot / typert)、以及质量门(scripts)。这些不是产品能力,但没有它们,前面 33 章的每一行都无法可信地存在。

(全书连接点) 03 页 typert 家族 · 各页 invariant.ts 伴生插件 · AGENTS.md 的质量门 → 本域:typert / runtime-diagnostics / guard / preset / attachment / feedback / context → (回心脏) invariants 在 internal/dispatch 拦截验证各页的不变量

示例本次示例:invariant 当场抓错

示例轨迹 34-1 · 违反「模型可见 ⟺ 已记录」时发生什么
# 假设有人写了一个 bug:直接改请求的 messages(绕过日志)
# 开发模式挂载了 dsh-invariants(runtime-diagnostics/invariants)
# → 11 页的 invariant(agent-loop/src/invariant.ts)在 llm/stream 前校验:
#   request frozen ✓ 但 messages ≠ session.deriveMessages() ✗
# → 抛出 INVARIANT 错误 → 当场炸(fail-loud)
# 没有 invariants:这个 bug 会静默通过——模型看到的与日志记录的不一致,
# 回放/恢复/审计全部失真。invariant 把纪律变成可执行断言(34 页 §2)
来源:34 页 §2 + 11 页 invariant.ts
示例轨迹 34-2 · typert 让两端类型不漂移
# apiproxy(32 页)定义 API 契约 → typert/generator(6251 行)生成类型图
# → client 包从类型图消费类型(编译期检查)
# 改 API 契约 → 客户端编译失败 → 漂移在编译期暴露
# 这就是 cordis.patch.yml 里 typert-registry/loader/gateway 三行的作用(34 页 §1)
来源:34 页 §1 + 32 页 apiproxy

§1typert:类型图

packages/typert/(generator 9 文件 / 6251 行)生成 TypeScript 类型图——它是 API 契约(32 页 apiproxy)与 client(33 页)共享类型的机制:一端生成类型,另一端消费类型,两端永不漂移。cordis.patch.yml 里的 typert-registry / typert-loader / typert-gateway 三行就是它的挂载。

§2invariants:运行时断言

全书各页反复出现的「invariant.ts 伴生插件」就在这里定义:packages/runtime-diagnostics/invariants/(2 文件 / 230 行)。各包的 dsh-xxx/invariant 可选入口注册关系断言,经 internal/dispatch 在事件提交前验证:

  • 06 页:seq 单调、turn/step 闭合、工具调用/结果配对
  • 11 页:loop-built 请求 frozen、messages 与 deriveMessages() 一致
  • 14 页:工具流水线阶段顺序、结果冻结
  • 05 页:agent/status 无重复迁移

invariant 的意义:「模型可见 ⟺ 已记录」从一条纪律变成可执行的断言——开发期挂上 invariants,任何违反都当场炸。

§3guard:循环卫生

  • timeout-policy → dsh-tool-call-timeout-policy(111 行)——工具调用超时
  • repeat-tool-reminder → dsh-repeat-tool-reminder(263 行)——重复工具提醒
  • 还有 21 页的 spill、compaction 的 token-meter——guard 域是「循环的卫生巾」:它不管做什么,只管「循环不会跑飞」。

§4其余支撑

  • preset / persona / bundle(04 页的组装层 + 预设):agent-presets(9 文件 / 1684 行)是 per-session 组合的来源;persona(99 行)是提示词人格(12 页 PERSONA_SECTION)。
  • attachment(385 + 1270 行):附件 seam——图片等非文本数据(10 页图片投影的供给侧)。
  • feedback:/feedback 命令与消息反馈。
  • context 域:session-reference(807 行)、tmux-context(277 行)、agent-instructions(23 页)——「上下文注入」的各类来源。
  • scripts/ 质量门(AGENTS.md 的 check:all 家族):verify-* 门、coverage 门、snapshot 门、catalog 生成——「文档与代码同步」本身由脚本强制。

§5全书结语

全书到此结束。回望这条线:

00-04 讲清了「一棵插件树如何从 YAML 活起来」;05-17 讲清了「一条消息如何走过心脏的每个器官」;20-34 讲清了「78 个挂载条目如何各自成为产品的一部分」。每一个能力域都是同一套 seam 语法的重演:Definition 声明、Provider 实现、Consumer 消费、invariant 断言。

读完这本书,你拥有的不是「对某个函数的印象」,而是对整个项目的完整地图——从 argv 到进程树,从一条消息到十五个能力域。改任何一处代码,你都知道它站在哪、连着谁、由谁保证。

最后一条验证:pnpm dsh --profile web --dump-config——现在打印出的每一个条目,你都能说出它是哪一章的什么角色。