DSHarness 系统拆解 固定基线 47f943859b · 36 已复核 / 0 撰写中 / 36 章
English
可靠性与产品面·第 32 章

测试、快照与运行时不变量

它怎样证明插件组合之后仍然满足系统语义

已复核上游 47f943859b范围: 分析 100% per-file gate、keyless snapshot、invariant registry、生成文档校验、配置闭包与平台矩阵。

结论:系统不是靠一次“全绿”证明正确,而是靠互不替代的证据层

DeepSeek Harness 把插件组合后的正确性拆成六类可失败的主张:逐文件覆盖率证明被 coverage 计量且未 inline-ignore 的 statement/branch path 确实执行过;无密钥快照证明真实组装入口能够重放并复现外部 transcript 与持久日志;runtime invariant 在运行时检查跨事件、跨服务的关系;配置闭包在启动前证明插件说明符和 peer 依赖可达;生成文档门禁从源码重新计算公开契约;平台矩阵则把 Node 版本、Linux、Wine 与真实 Windows kernel 的不同信号分开。

这不是一条由弱到强、最后由某个总分取代前面层级的流水线。仓库自己的测试策略明确指出,行覆盖率只证明代码执行过,不证明交付功能有效;快照、真实入口、平台专属检查与运行时不变量因此承担不同的反例空间。TINV-POLICY

1. 证据栈:每一层回答一个不同问题

失败时说明什么单独不能证明什么
单元 + 逐文件覆盖被 coverage 计量且未 inline-ignore 的 statement/branch path 未执行,或断言观察到局部契约回归Loader、发布产物和整棵组合正常
无密钥快照真实进程入口的协议输出或重新持久化日志漂移在线模型质量、所有未录制调用顺序
Runtime invariant活的组合产生了违反跨事件关系的状态未装载 companion 的部署也受保护
配置闭包YAML 中的插件、source-plane 映射或部署 peer 不可达插件启动后的业务语义正确
生成文档检查公开目录、类型粘贴或源码投影已陈旧自然语言中的所有解释都正确
平台 / 版本矩阵某个运行时或 kernel 特有入口不成立未列入矩阵的平台与外部环境
核心判断

“组合后仍满足语义”不是一个可由单一指标观测的命题。这里真正有效的设计是让每一种绿色结果都保持窄含义,再用 CI 的依赖图要求必需结果同时成立。

2. 逐文件 100%:防止大文件替小文件“补贴”覆盖率

V8 coverage 的纳入面是 packages/*/*/src/**/*.{ts,tsx},不是整个仓库;examples 与 vendor 位于该 include glob 之外,glob 内的 type-only files、自执行 bin/worker 以及一批明确记录的 GUI 或组合债务则被排除。TINV-COVERAGE-SCOPE在 file exclusions 与源码 inline ignore 生效后,对纳入且仍被计量的每个文件,statements、branches、functions、lines 四项都必须分别达到 100%。TINV-COVERAGE-BAR

included production file
        │
        ├── statements 100%
        ├── branches   100%
        ├── functions  100%
        └── lines      100%

aggregate average cannot compensate for one file

它对组合型仓库尤其有价值:新建一个小 companion 或 adapter,不能因为同包另一个大文件覆盖很好而隐身。但这个数字的准确读法是“file exclusions 与 inline ignores 之后的计量集合内逐文件 100%”,不是“仓库所有生产路径 100%”,更不是“语义 100%”。

3. 豁免不是删除测试:instrumentation 与 correctness 被拆成并行 gate

编译器分析和真实子进程 fixture 等重型 suite 可以从 instrumented run 排除,但同一 coverage aggregate 会在旁边以普通 Vitest 再运行这些 suite;清单的准入原则是它们执行的 coverage-measured 文件已由其他 suite 完全覆盖。TINV-COVERAGE-EXEMPT机械测试进一步要求每个 CLI filter 与 exclude glob 选择相同且非空的文件集,并禁止清单项重叠。TINV-COVERAGE-EXEMPT-TEST

平台条件也改变实际纳入面:Windows 排除依赖 POSIX shell 的 suites,所有非 Windows host 都排除只在 Windows 执行的 ACL source;缺少真实 pwsh 时,相关源码随 suite 的自跳过而豁免。TINV-PLATFORM-COVERAGE因此 coverage 报告必须连同运行平台和工具可用性解释,不能把一台机器的 100% 外推成所有平台路径均已执行。

4. Keyless snapshot:把非确定模型边界替换为已提交脚本

replay 是默认模式:不加载 .env,从已提交模型响应启动真实子进程并比较组装请求、归一化协议或 transcript、以及持久日志。record 才读取凭据并调用真实 API;refresh 仍然无密钥,只用现有脚本重写当前预期输出。只有 replay 会在配置上限允许时并行运行 snapshot files;record/refresh files 保持串行,避免真实配额竞争或并发写坏 golden。TINV-SNAPSHOT-MODE在 ACP suite 内部,scenario tests 也只在 replay mode 使用 concurrent suite。TINV-SNAPSHOT-SCENARIO-MODE

CI 的 snapshot gate 依赖 build,并设置 DSH_EXAMPLE_MODE=lib:示例和包快照从构建后的产物通过普通 Node 启动,脚本快照才运行真实 source entry。TINV-SNAPSHOT-GATE这使“源码测试通过”与“发布形状可加载”之间保留了独立证据。

模式模型来源是否写 fixture主要用途
replay已提交 JSONL / override默认 CI、确定性回归
record真实 API模型 transcript 改变时重新采集
refresh已提交 JSONL / override输入仍有效、下游输出格式变化时刷新

5. 回放从 durable log 派生调用,并同时比较 wire 与 log

deriveReplayScript()assistant/chunk 的终止 finish 分割模型调用;turn/step 变化前若上一调用未终止就 fail loud。显式标记为本地 LLM 调用的 compaction summary 会在其日志位置重建 block、usage 与终止 chunk。抛出和挂起无法仅由普通日志无损推导,必须使用 override。TINV-REPLAY-DERIVE

recorded session JSONL
        │
        ├── assistant/chunk + finish ──► positional replay entries
        ├── marked compaction summary ─► reconstructed local call
        └── throw / hang gap ──────────► explicit override required
                                             │
real assembled subprocess ◄─────────────────┘
        │
        ├── normalized stdout vs committed wire snapshot
        └── normalized harvested JSONL vs committed session fixtures

ACP suite 对当前 mode、platform 或 PowerShell availability 没有跳过的每个场景运行真实组装入口,先拒绝 UNKNOWN_TOOL 被当作成功行为,再归一化会话 id、cwd 等波动值。最终 stdout 逐文件匹配,主/子会话的 harvested logs 与 fixture 进行一一归一化比较;record 与 refresh 的写权限由模式显式控制。TINV-SNAPSHOT-COMPARE场景目录还有闭包守卫:孤儿目录、缺失 input/stdout/session、错误的 override 或 header sidecar ownership 都会失败。TINV-SNAPSHOT-FIXTURES

6. Runtime invariant registry:把失败归属和生命周期统一,把规则留给 owner

InvariantRegistry 提供全局 enable、package allowlist 与 blocklist;即使 filter 禁用某个 installer,package name 仍被保留,避免两个 companion 静默声明同一 owner。启用的 installer 运行在独立 child fiber 中,收到绑定 package name 的 fail();失败抛出带稳定 INVARIANT code 和 packageName 的错误。启动失败会 dispose child 并释放 reservation,正常 disposer 则先完成 child teardown 再释放。TINV-REGISTRY

注册表本身不 import 产品包,也不集中维护一张巨型规则表。仓库约定要求每个包的 ./invariant companion 检查它拥有的 event 或 mutable-data relationship;类型、方法存在性、固定纯函数结果仍交给 type/load/unit tests。Gate 可以验证注册的 npm owner 和 no-runtime-rule marker 是否存在,但规则是否真的属于该包、解释是否充分仍需人工评审。

7. “每个包都有 companion”由源码门禁、测试拓扑和构建消费分别证明

源码门禁扫描每个 packages/*/*/package.json,检查 ./invariant export、发布文件、peer/dev dependency 与 TypeScript reference;随后解析 companion AST,要求恰好注册自己的 npm name、具名导出 name/inject/apply、禁止 default export,并要求非空 installer 实际使用 failure reporter。空 installer 必须包含 No runtime invariant: marker;gate 不判断解释是否具体或充分。TINV-COMPANION-GATE

普通 Vitest root 会先装启用的 registry,再按测试路径只装当前包的 companion,并用 readiness dependency 阻止目标插件抢先启动。TINV-TEST-HOST专门的拓扑测试则装载全部 companion,逐个经真实 Loader unwrapExports 并验证每个 package name 已被保留。TINV-INVARIANT-TOPOLOGY-TEST

三个不同问题

源码门禁回答“声明是否完整”;全量 topology 回答“所有 source companion 能否真实装载和注册”;built-package gate 与 lib-mode snapshot 回答“编译后的发布形状是否仍可被普通 Node 消费”。built-package gate 会暂存 manifest 声明的 lib 视图,再用普通 Node 通过包导出导入 companion,并检查 Loader 不会折叠 namespace。TINV-BUILT-COMPANIONS前两者不能替代第三者。

8. 具体不变量检查关系,不复述实现

Session companion 为每个 Session 保存 lastSeq/openTurn/openStep/nextTurn/nextStep/pendingCalls trace。候选 core-execution event 必须保持 seq 单调及各自要求的 Turn/Step enclosure。Append-mode tool result 必须引用同一 Step 内先前的 call,synthetic TOOL_NOT_STARTED result 除外;Step 结束时会清除尚未匹配的 pending call。Merge-extensible event 的关系则留给其 owner,而不是由 Session 猜测。TINV-SESSION-RULES

更关键的是 mutation timing:internal/dispatch 上只做纯验证并暂存 transition;只有 session/event 真正发布后才提交 trace。若后续 pre-commit listener veto,暂存 transition 被放弃,不会让诊断状态超前于真实日志;companion reload 时则从现有 durable events 重建基线。TINV-SESSION-COMMIT

Agent-loop companion 在 llm/stream 最前端检查 loop-built request:请求和 messages 必须冻结、session id 必须指向 live Session,messages 必须等于 durable log 的即时派生,model/system/temperature/maxTokens/stop/tools 必须等于折叠后的 request header。TINV-LOOP-REQUEST这类断言正是 runtime invariant 的独特价值:每个对象单独看都合法,只有把“将发送的请求”与“已提交的日志事实”比较才能发现组合失同步。

9. 配置闭包:在 Loader 启动前证明两张可达图

verify-runtime-closure 从 executable deploy manifest 的 workspace dependencies 做 BFS,沿普通和 optional dependencies 扩展,并要求遍历到的每个非 optional workspace peer 都由根 runtime manifest 显式供应;失败信息保留从 runtime 到缺失 peer 的完整链。TINV-RUNTIME-CLOSURE

verify-cordis-config 扫描所有 Loader YAML,递归验证 entries/patches,并把 example、app 与 bundle 中出现的插件说明符反查到各自 manifest dependency。对本地包,它还要求 source launch 经 tsconfig.base.json paths 解析到 .ts/.tsx,阻止一个已有旧 lib/ 的开发机掩盖 clean checkout 缺映射的问题。运行时字符串选择的 directory-picker backends 也被显式加入闭包。TINV-CONFIG-CLOSURE

配置 AST 还有语义边界:只有 Loader 真正插值的 config 与 entry-level disabled 可以动态;id/name/group/inject/intercept/isolate 中的 !!js 会成为 truthy data 而非表达式,因此门禁拒绝它们,并预解析 disabled 语法。TINV-CONFIG-METADATA

10. 生成文档不是手工副本,而是可重算的源码投影

doc-sync 不是一个 Markdown linter:它并行组合 code-fence typecheck、Cordis/client/tool/config/persistence catalogs、文档图、scoped events、链接、source ownership、type equivalence、翻译配对、站点投影与文档站生产构建。TINV-DOC-SYNC

Config catalog 会从 package entry、config type、JSDoc 与静态 Schemastery schema 重建目录;每个包必须分类,类型引用必须无冲突,并且可枚举的 schema path 必须能在声明类型中定位。TINV-CONFIG-CATALOG交叉 schema 会先递归合并 key,再检查缺失成员;--check 逐字节比较计算结果与已提交文档。TINV-CONFIG-CATALOG-CHECK

Cordis catalog 则扫描 Context merges 与 Events members,要求每个 service/event scope 能映射到页面、exemption 不陈旧、双语页面都有生成区标记,再把完整输出与已提交文件比较。TINV-CORDIS-CATALOGverify-type-equiv 会先把 byte-identical 的 paired-language copy 分为 derivatives,再要求每个 primary ts type-equiv/ts public-api block 与 manifest 一一对应,并把 primary block 与 source structure/JSDoc 比较。TINV-TYPE-EQUIV

实际效果

公开契约的机械部分与源码共用一个事实来源;生成器会发现“新服务没有文档归属”和“schema 接受了类型目录没有展示的 key”这类普通拼写检查看不到的漂移。自然语言解释仍需评审,因此 freshness 不是完整的文档真实性证明。

11. 平台矩阵不是复制同一套命令,而是分配不同证据责任

Linux PR workflow 把 Node 24 static、coverage 与 consumer 分成独立 jobs。TINV-CI-LINUXConsumer gate graph 拥有 build、package-consumption checks、assembled snapshots、browser snapshot 与 built-bin smoke。TINV-CI-CONSUMERS另一个矩阵在 Node 22.19 与 26 上运行 compatibility contracts,避免主版本的绿色掩盖支持边界。TINV-NODE-MATRIX

Windows 有两条不同信号:pull request 的 windows workflow job 委托 runner provision checksum-verified Windows Node,确认它报告 win32 x64,并且只运行 workspace build 与文档站 production build 两个 surface。TINV-WINDOWSTINV-WINE-RUNNER真实 Windows kernel 的 windows-native 跑 complete inventory,但结果独立且不在 all-checks-passed.needs 中。最终 all checks passed 使用 if: always() 聚合列明的 jobs,并把 failed、cancelled、skipped 都视为失败。TINV-REQUIRED-VERDICT

信号拥有的结论不拥有的结论
Linux Node 24主静态、覆盖率、组装 snapshot 与产物消费Windows kernel 行为
Node 22.19 / 26显式 compatibility smokes完整主 gate inventory
Wine Windowsall-checks-passed aggregate 内的 win32 build/site 可执行性真实 kernel、ACL、native process 语义
Native Windows真实 kernel 上的完整观察性 inventoryall-checks-passed aggregate

12. 绿色结果的精确含义与剩余盲区

可以得出的结论不能外推的结论
排除 file exclusions 与 inline ignores 后,被 coverage 计量的每个文件四项指标均为 100%显式排除面、child-process instrumentation 与所有平台路径也被覆盖
已记录场景的 wire/log 归一化后稳定真实模型质量、未记录调用交错、OS confinement
已装载 companion 能在运行中拒绝已编码的关系违规未装 companion 的 custom composition 自动获得同样保护
当前 runtime/config 引用闭合外部系统、凭据、网络和业务行为都可用
机械生成区和类型粘贴与源码一致所有手写 prose 的因果解释都准确
all-checks-passed.needs 列明的 jobs 同时成功observational lane 或独立 workflow 也属于同一个 aggregate

最重要的工程纪律不是继续增加一个更大的“总测试”标签,而是在改动计划里先写出需要哪一种反例:局部分支、真实 Loader 组合、durable transcript、跨事件关系、部署闭包、生成契约还是特定 kernel。只有这样,新增测试才会落在能让真实回归变红的层级。

13. 本章验证范围

所有仓库事实固定在 commit 47f943859bef60e4160492346772ded9b24f765a。本次没有运行全量 build、全量 coverage、全量 snapshot、浏览器 suite、真实 API、Windows/Wine、性能或压力测试。

第一组聚焦 Vitest 覆盖 coverage-exempt roster、全量 companion topology、registry 生命周期、Session invariant、LLM replay、snapshot harness/normalizer 与 Cordis config helpers:9 个测试文件、256 个用例全部通过。代表性断言包括全量 companion 经 Loader 注册、registry 失败归属和原子回滚、Session veto 不推进 trace,以及 positional replay 的 throw/hang/exhaustion/underrun 失败语义。TINV-INVARIANT-TOPOLOGY-TESTTINV-REGISTRY-TESTTINV-SESSION-TESTTINV-REPLAY-TEST

pnpm exec vitest run \
  scripts/coverage-exempt.spec.ts \
  scripts/test-invariants.spec.ts \
  packages/runtime-diagnostics/invariants/tests/service.spec.ts \
  packages/core/session/tests/invariant.spec.ts \
  packages/test-support/llm-replay/tests/llm-replay.spec.ts \
  packages/test-support/acp-snapshot/tests/harness.spec.ts \
  packages/test-support/acp-snapshot/tests/normalize.spec.ts \
  scripts/cordis-config-files.spec.ts \
  scripts/verify-cordis-config.spec.ts

Test Files  9 passed (9)
Tests      256 passed (256)
Duration   22.17s

第二组运行时两个环境变量均未设置,使用 replay/source 默认值;下面的复现命令会显式固定二者。该组以 snapshot config 只读运行 canonical session-fixture layout 与 translation prompt snapshot:2 个文件、2 个用例通过。布局守卫会扫描所有 session-format JSONL 并拒绝非 canonical packed representation。TINV-FIXTURE-LAYOUT-TEST

DSH_SNAPSHOT=replay DSH_EXAMPLE_MODE=src \
pnpm exec vitest run --config vitest.snapshot.config.ts \
  scripts/session-fixture-layout.snapshot.ts \
  scripts/translation-prompt.snapshot.ts

Test Files  2 passed (2)
Tests      2 passed (2)
Duration   1.98s

第三组同样在两个环境变量未设置时使用 replay/source 默认值;下面的复现命令会显式固定二者。该组只选择 ACP handshake 场景,真实 source-mode 组装进程通过:1 个用例运行并通过,85 个同文件用例因 -t handshake 过滤而跳过;这不是全量 ACP snapshot 结果。

DSH_SNAPSHOT=replay DSH_EXAMPLE_MODE=src \
pnpm exec vitest run --config vitest.snapshot.config.ts \
  examples/acp-agent/tests/acp.snapshot.ts -t handshake

Test Files  1 passed (1)
Tests      1 passed | 85 skipped (86)
Duration   14.70s

最后运行六项只读结构门禁,均以退出码 0 完成:verify-package-invariants 报告 219 个 hand-owned companions;verify-runtime-closure 报告 109 个 workspace packages;verify-cordis-config 报告 120 个 config files;config catalog 已是最新;Cordis catalog 的 93 个 generated files/regions 已是最新;verify-type-equiv 报告 384 个 blocks 与源码/JSDoc 一致,并识别 384 个 paired derivatives。Cordis metadata 的聚焦测试也覆盖了允许的 disabled 表达式与三类拒绝路径。TINV-CONFIG-TEST

pnpm run verify-package-invariants
pnpm run verify-runtime-closure
pnpm run verify-cordis-config
pnpm run verify-config-catalog
pnpm run verify-cordis-catalog
pnpm run verify-type-equiv

我的学习体会

内容仅自动保存到当前浏览器,不上传、不进入仓库。你可以导出 Markdown 自行归档。