怎样验证本册结论,并看清 Harness v2 的边界
给出 tag、commit、source archive、离线构建、固定测试集与 SourceEvidence 的完整复核路径,并区分 v0.83.0 已交付实现和 Harness v2 设计目标。
前 47 章不断引用同一组版本字段,不是为了让页头显得严谨。源码书最常见的失真不是某行完全看错,而是把不同时间的事实混到一起:用 release tag 的 API、main 分支的设计文档、npm 包里的生成数据和本机已安装依赖拼出一个从未真实存在过的 Pi。最后一章要做的,是把这几种证据重新分开,并给出一条别人能够独立重复的验证路径。
本册的身份是 tag v0.83.0、commit 845d6ff1f6643aba440341cce877ce1c43ebbc39。章节里的 SourceEvidence 只对这个 commit 的路径和行号负责。实验若需要完整构建,则再引入同版本的 release source archive;讨论 Harness v2 时,只把固定 tag 内的 design documents 当作未来目标,不把文档句子升级成已交付 API。
第一层:先证明“我看的就是这个版本”
tag 是便于人阅读的名称,commit 才是不可变对象。复核者应同时检查两者,并要求工作区干净;否则 tag checkout 上未提交的一个修改,就足以让行号看似相同、行为已经不同。
repo="${PI_RELEASE_SOURCE_DIR:-/path/to/pi-v0.83.0}"
git -C "$repo" rev-parse HEAD
git -C "$repo" describe --tags --exact-match
git -C "$repo" status --short
预期前两行分别为完整 commit 和 v0.83.0,第三条没有输出。本册 verifier 在运行测试前后都会重复这组检查,防止 build、测试或人工操作悄悄污染用作证据的 checkout。测试本身在解压后的临时 source archive 中执行,不在固定源码目录生成 node_modules 或 dist。
仅有一个干净 checkout 仍不够。Pi 把 packages/ai/src/providers/data/ 写进 .gitignore,普通 git clone 或 git archive <commit> 都不会带上这组 provider model data。packages/ai 的 build:offline 又先执行 check:model-data,再编译并把该目录复制进 dist。因此,“这个 commit 能定位全部手写源码”与“这个目录能完成 release 等价的离线构建”是两个不同结论。
这也是为什么验证脚本不应该在普通 checkout 里临时联网生成数据。那会把“固定 release 产物”换成“验证当天上游源重新生成的产物”,结果可能受远端目录变化影响,且很难再现。
第二层:把发布源码包当成单独的制品
固定发布使用的 source archive 是:
URL: https://github.com/earendil-works/pi/releases/download/v0.83.0/pi-0.83.0-source.tar.gz
SHA256: f225b87ec3b4825dd5b94e922a8629558addca31a1b4d2c206ae598a8e2692c0
仓库里的 create-source-archive.sh 要求 provider data manifest 与 JSON 已存在,然后建立临时 git index:先 read-tree 固定 commit,再以 git add -f 把被忽略的数据加入临时 tree,最后用 commit timestamp 和 gzip -n 生成确定性 archive。脚本还检查必要文件、唯一 root prefix、不得含 node_modules 或 binaries,并在解压目录重新执行 model-data validation。
release workflow 先 hydrate model data,再创建 source archive,随后把它解压到临时目录并用 --offline-model-data 构建 binaries。最后 source archive、各平台 binary、install lock 和其他 release files 一起进入 SHA256SUMS。换句话说,这个 archive 不是 GitHub 自动生成的源码快照,而是发布流程显式构造、且被下游 binary build 消费的输入。
校验哈希的意义是把下载 URL 也纳入证据。文件名相同不保证字节相同;digest 不匹配时应停止,而不是继续解压后凭目录结构判断“应该没问题”。
第三层:跑覆盖主链的固定验证集
博客仓库提供的端到端 verifier 完成以下动作:
- 检查 source checkout 的 tag、commit 和 clean status。
- 下载或读取指定 archive,并验证固定 SHA256。
- 解压到一次性目录,执行
npm ci --ignore-scripts --no-audit --no-fund。 - 执行
npm run build:offline,证明 archive 自带数据足以离线编译。 - 运行 8 个 Vitest 文件,覆盖 provider retry/overflow、agent loop、当前 AgentHarness、session tree、文件 mutation queue 和 extension runner。
- 运行 4 个 TUI Node test 文件,覆盖输入、editor、overlay focus 与 differential rendering。
- 再次检查固定 checkout 未发生变化,并删除临时目录。
执行命令是:
cd /Users/qingyun/Documents/GitHub/qingyun-blog
export PI_RELEASE_SOURCE_DIR=/path/to/clean/pi-v0.83.0
pnpm verify:handbook:pi-e2e -- \
--source-dir "$PI_RELEASE_SOURCE_DIR"
本次固定验证结果为 8 个 Vitest 文件、155 个 tests 全部通过;4 个 TUI test 文件、288 个 tests 全部通过,共 443 个。这个数字不能证明“Pi 没有 bug”,它证明的是列出的调用链在这个 release archive、依赖锁和当前验证环境中通过。真实 provider credentials、所有模型组合、所有终端实现、跨平台 binary 安装和外部容器策略不在这 443 个断言里,结论不能越过覆盖范围。

截图来自本册 verifier 的真实运行结果:固定 tag 与 commit、官方源码包 SHA256、8 个 Vitest 文件 155 项、4 个 TUI 文件 288 项,共 443 项,退出码为 0。它证明这组明确列出的发布输入和测试通过,不代表真实 Provider、所有平台或全部仓库测试都已覆盖。
flowchart TD
accTitle: 本册从源码身份到结论的验证层级
accDescr: tag 与 commit 固定手写源码,release archive digest 固定生成数据和发布输入,离线构建证明制品完整,固定测试集验证关键运行链,章节 SourceEvidence 再把具体表述落到源码范围。设计文档只能支持目标与边界,不能单独证明功能已交付。
ID["tag + commit + clean checkout"] --> ARCHIVE["source archive + SHA256"]
ARCHIVE --> BUILD["npm ci + build:offline"]
BUILD --> TESTS["pinned Vitest + TUI tests"]
TESTS --> CLAIMS["chapter claims + SourceEvidence"]
DESIGN["Harness v2 design docs"] -. "future goals only" .-> CLAIMS
SourceEvidence 证明局部事实,不替代运行验证
每个 SourceEvidence 都记录 sourceVersion、commit、path 和 line interval。它适合证明“这个 switch 在固定版本如何分支”“这个 schema 是否有 operation log”“这个方法在 listener 之前还是之后 append”。站点校验器还能检查路径存在、行号未越界、引用片段与固定源码匹配。
它不适合证明外部效果。例如源码里调用 killProcessTree(),不能仅凭一段引用证明每个 OS、每种后代进程都被正确终止;release workflow 里写了 build command,也不能替代实际运行。可靠的章节应把证据分级:类型与控制流由源码引用支持,可观察行为由测试支持,发布完整性由 archive digest 和离线构建支持,外部平台能力则保留未验证边界。
同样,一张终端截图只能记录一次运行的可见结果。它能帮助读者辨认 UI,却不能证明事件顺序、持久化时点或差分写入范围。第 43 至 46 章选择 headless terminal tests 和 source call chain,正是为了把“看起来如此”推进到“可以重新执行并断言如此”。
Harness v2 在固定版本里是设计,不是暗藏的稳定能力
packages/agent/docs/harness-v2.md 标题就是 “Durable AgentHarness design”。Goals 提出 durable runs、lanes、no partial outcomes、snapshot + live events 和 single writer;Non-goals 又明确排除 provider partial stream resumption、multiple writers 与 replication。后续 session model 增加 shared append-only tree、per-lane operation logs 和 global facts,并把 execution record 与 conversation entry 分开。
这些概念可以用来理解为什么第 24 章强调“持久会话不等于持久运行”,却不能反过来说 v0.83.0 已经提供 crash-resumable operation。固定版本的 shipped boundary 必须回到实际 SessionStorage 联合类型、SQLite schema、AgentHarness constructor、公开方法和 tests。设计文档描述的是作者准备怎样填补当前缺口。
另一个设计笔记甚至把目标称为 semi-durable:工具实现、模型与认证 provider、extensions、resource loaders、system prompt callbacks 和 hooks 是宿主提供的 runtime JavaScript,无法只靠 session 序列化。恢复只能从 durable boundary 继续,而不是接回一个进行中的 provider stream;宿主还必须重建兼容依赖。
这条边界也规定了未来更新本册的顺序。先选择新 tag 和 commit,重新下载并校验对应发布 archive;再运行离线 build 与固定测试;然后让所有 SourceEvidence 指向新源码,逐章检查行为差异。若 Harness v2 从文档进入实现,应在 schema、API、recovery tests 和 Coding Agent 接入层都找到证据,再改写第 19 至 24 章。只看到 main 分支多了一个设计文件,或者某个类型名先落地,都不足以宣布能力已经完成。
48 章讲完的是责任链,不是文件清单
Pi 的子包确实很多:AI provider、Agent、Harness、storage、Coding Agent、TUI、Web UI、MOM、pods、server、Evals 和大量 examples。一本源码书若按目录机械地“一包一章”,章节会快速膨胀,却仍解释不清一次 prompt 怎样跨包移动。本册采用的是责任链:模型边界、两层 agent loop、工具批次、会话树、控制面、扩展、产品入口、终端投影和安全部署。子包在承担这些责任时进入主线;examples 和辅助包则作为实现或验证证据出现。
所以,48 章的“讲完”不是声称解释仓库每个 export,而是让读者能够回答三个问题:一次行为由哪条调用链产生,状态由谁持有,失败后哪一层还能重建。遇到未展开的子包,可以沿同样方法定位入口、事件、持久边界和测试,而不必从目录第一行重新读起。这比把所有文件写进目录更接近“深入浅出”的含义:主线足够连续,边界足够诚实,细节又能随时回到固定源码复核。