T3 Code 源码拆解
工程化

19 · 测试、日志与故障定位

约 771 个测试文件如何按纯核心、协议、adapter、reactor 和平台边界分层。

测试数量不是重点,边界才是

在 apps、packages、infra、native 范围内,本快照约有 771 个 .test/.spec 文件。数字会变化,真正值得学习的是命名与分层: 纯 decider/projector、协议 framing、Provider adapter、reactor、数据库迁移、客户端 supervisor、Electron lifecycle 都有各自测试。

测试金字塔按架构切片

T3 Code 的测试层次
Pure model tests - decider/projector/reducers Effect service tests - engine/registry/supervisor Protocol tests - RPC/JSON-RPC/ACP/auth Adapter tests - Provider/PTY/Git/platform Integration - runtime/process/db/desktop smoke Release smoke + packaged artifacts

层次不是“越上越好”。每类 failure 应在最窄边界被发现:一个 event mapping bug 不需要启动 Electron,安装器漏文件则纯函数测试无法发现。

纯核心测试

Decider

输入 read model 与 command,断言 events/rejection。应覆盖每个 invariant 的正反面、幂等语义所依赖的 command shape、 archive/pin/snooze/settled/title regeneration 等状态组合。

Projector / client reducers

给定 event sequence,断言新 state;还要验证:

  • replay 全序与逐条增量结果相同;
  • 重复/旧 sequence 的策略;
  • 流式 segment append;
  • session stop 结算 turn;
  • 2,000 messages / 500 checkpoints 等边界;
  • structural sharing 不误改旧 state。

这些测试快、可穷举,是事件系统最重要的回归网。

编排引擎测试

Engine 测试使用临时数据库/Effect test layers 验证跨组件不变量:事务原子性、单队列顺序、receipt 幂等、commit 后 publish、 失败对账。不要只断言最终 thread;还要查询 event sequence、receipt 和 persisted projection,确认它们一致。

并发测试应使用 barrier/Deferred 构造确定交错,而不是起两个 Promise 后祈祷竞态出现。

Reactor 测试与 drain

Provider/Checkpoint ingestion 是后台 worker。makeDrainableWorker 暴露 drain(),测试能在 enqueue 后等待所有 outstanding handler 完成。

反模式:

emit(event)
await sleep(100)
expect(state).toEqual(...)

正确模式:

emit(event)
await worker.drain()
expect(state).toEqual(...)

drain 把“工作完成”变成契约,CI 负载不再决定测试是否 flaky。

Provider 测试的四层

  1. Wire/Schema:截断 frame、多消息、未知字段、request ID、EOF;
  2. Runtime mapping:原生 notification/update → canonical event;
  3. Adapter contract:start/send/interrupt/approval/stop/list/has;
  4. Ingestion:canonical sequence → domain messages/activities/lifecycle。

真实 CLI 登录的端到端测试昂贵且不稳定,所以仓库使用 mock peer、wire fixture 与 SDK mock 覆盖大多数协议。少量 integration 验证 process/runtime 组合。

数据库迁移测试

迁移不只要在空数据库通过,还要从旧 shape 构造数据:非法 pending approval、旧 model selection、archive/index/backfill 等。 Canonicalization 测试应包括未知值与重复执行。索引迁移可检查 query/Schema,而不是仅“没有 throw”。

由于 SQLite 是权威存储,一次 migration bug 可能比 UI bug 更难恢复;迁移测试应和当前 Schema 测试同级对待。

Git 与文件系统测试

VCS 测试用临时目录创建真实 Git 仓库,覆盖 staged/unstaged/untracked、无 HEAD、worktree、diff、restore。关键断言之一是捕获 checkpoint 前后 用户 index 和 HEAD 不变。文件/PTY 测试必须只操作明确临时目录,不能依赖开发者真实仓库或 userdata。

Client connection 测试

supervisor.test.ts 使用 TestClock/可控 connectivity 驱动 3/4/8/16 秒退避、offline、stable reset、wakeup 和 scope close。 用虚拟时间能把分钟级状态机在毫秒内确定验证,也避免真实网络。

Registry 测试关注同环境 lease 串行化、最后释放、删除清 cache;snapshot/reducer 测试关注 cursor gap 与重建。

Electron 与 Mobile 边界测试

Electron 模块将 app/window/updater/protocol/safeStorage 包在 service 后,测试使用 fake adapter 验证调用顺序。test:desktop-smoke 再对打包组合做轻量验证。Mobile 原生 module 边界有 JS contract/static check,终端 buffer replay 等逻辑保持纯 TS 测试。

可观测性分层

结构化 Effect logs/spans

Server 在 command ID、environment、thread、session、provider instance 等维度关联日志。日志要记录状态转移和耗时,不复制完整 prompt/code。

Provider NDJSON

可选原生 event logger 用于协议诊断。它是高敏本地调试资料,应有开关、路径与清理策略,禁止默认上传。

Relay tracing

cloud/relayTracing.ts / traceRelayRequest.ts 关联控制面请求;应记录 route、status、latency 和 trace ID,移除 Authorization、ticket、DPoP proof。

Desktop observability / diagnostics

主进程、backend process、renderer connection 是不同故障域。Diagnostics 页面应展示版本、endpoint/状态、最近安全化错误和日志位置, 让“UI 空白”“backend 未 ready”“远端 auth 失败”可区分。

Resource telemetry

CPU/内存采样用于产品监控,不替代日志/trace。异常资源可以定位 provider session,再用关联 ID 查 runtime event。

故障定位手册

症状第一证据下一层
消息重复command ID/receiptevent sequence、客户端是否重生成 ID
UI 永远 runningprojected session/turnprovider stream end、ingestion 结算
断线后少消息snapshot sequence/cursorgap 上限、subscription 建立
Provider 启动失败instance snapshot/launch argsexecutable/home、stderr、protocol handshake
审批点了没反应pending request IDresponse intent event、adapter callback
回退破坏暂存区checkpoint test/logGIT_INDEX_FILE、restore scope
手机恢复后请求风暴supervisor state是否有多个 retry owner/重复 wakeup
Desktop 空白backend readiness + renderer logIPC/preload/router history

可迁移经验

  • 测试围绕状态所有权和协议边界组织,而不是围绕文件大小。
  • 后台 worker 必须可 drain,时间状态机必须可注入虚拟时钟。
  • Event system 的测试要同时断言 log、projection、receipt 和 publish 顺序。
  • 协议原始日志非常有用也非常敏感;默认本地、可控、去凭据。
  • Diagnostics 首先区分故障域,再提供细节,不要只展示一段综合 stack trace。

On this page