Volume 2 · Chapter 34
工程基础设施:让 1292 个包协同的机器
全书最后一章讲「支撑这一切的机器」:类型图(typert)、运行时诊断(invariants)、守卫策略(guard)、预设与编排(preset / bundle / boot / typert)、以及质量门(scripts)。这些不是产品能力,但没有它们,前面 33 章的每一行都无法可信地存在。
示例本次示例:invariant 当场抓错
# 假设有人写了一个 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)
# apiproxy(32 页)定义 API 契约 → typert/generator(6251 行)生成类型图 # → client 包从类型图消费类型(编译期检查) # 改 API 契约 → 客户端编译失败 → 漂移在编译期暴露 # 这就是 cordis.patch.yml 里 typert-registry/loader/gateway 三行的作用(34 页 §1)
§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——现在打印出的每一个条目,你都能说出它是哪一章的什么角色。