用AI写代码?现在还能自动测分布式系统,发现隐藏故障
为分布式和有状态系统设计并运行基于声明驱动的测试的AI编码代理的两项技能。它们共同生成结构化的Markdown测试计划和一份包含9种状态判定结果以及明确的SUT/测试工具/检查器/环境责任分类的发现报告。评审者阅读这两份产物后即可决定是否发布;无需重新运行任何其他内容。
适用于Claude Code、Codex、Copilot CLI、Cursor、Gemini或任何能读取Markdown并运行Shell的代理。这些技能是纯文本的SKILL.md文件。代理执行它们;计划和发现报告即为输出。
一项技能负责设计计划。另一项负责执行计划。计划从产品的声明出发,生成与这些声明相关的假设,并编写以每个声明命名的场景,旨在证伪该声明。对于一致性关键场景,每个场景还将一个抽象模型(寄存器|队列|日志|锁|租约|账本|……)绑定到操作历史模式、一个命名的检查器以及一个具有可观测着陆证据的破坏者。计划以覆盖充分性论证和保守的信心声明结束。
为什么
默认的分布式和有状态系统测试方法——编写少量集成测试并就此收工——只能发现实际生产环境中破坏这些系统的一小部分错误:部分网络分区、非确定性并发、崩溃恢复、升级/回滚、重放下的幂等性、时序敏感排序。这些技能强制执行一种基于该领域来之不易的知识的特定工作流程:
- 声明驱动,而非测试驱动。 从产品承诺的内容开始。每个场景在一个故障下证伪一个声明。以声明命名的测试比以设置命名的测试更难被削弱。 - 覆盖充分性是交付物。 计划以论证所选场景足以发布结束,并附上一份诚实的未验证内容清单。 - 重用SUT自身的工具箱。 执行技能在发明任何新内容之前,会先发现现有的测试、运行手册和故障注入脚手架。 - 模型+历史+检查器,而不仅仅是混沌。 对于安全性、持久性、幂等性、隔离性、顺序性或成员资格声明,每个场景都声明一个抽象模型、一个操作历史模式、一个命名的检查器(线性一致性、可序列化性、会话一致性、无丢失确认、恰好一次……),以及它如何处理模糊结果(超时、未知提交、重试)。混沌加上模型和检查器,而非仅混沌。 - 无静默通过。 每个PASS都引用预言执行证据和证明故障实际触发的信号。判定结果来自一个9种状态的集合,因此“混沌脚本运行干净”不能被解读为“声明在故障中幸存”。每个FAIL都带有SUT/测试工具/检查器/环境责任标签,以便复现者能到达正确的队列。
你得到什么
端到端地,这两项技能产生:
`
testing-plans/<slug>.md ← 包含§0–§9的计划(见下文)
test-sessions/<UTC>/
├── session-log.md ← 时间线 + 工具箱 + 环境探测
├── logs/ ← 每个场景的标准输出/标准错误
├── metrics/ ← 指标快照
├── artifacts/ ← 临时测试工具、转储
└── findings/
├── <scenario>.md ← 每个场景的判定结果(随运行过程写入)
└── report.md ← 摘要 + 充分性 + 信心变化
`
计划结构(评审者可以阅读此内容并在无需重新运行测试的情况下决定是否发布): 0. 架构摘要 — 系统实际存在的样貌 1. 范围 1b. 待测试声明 — 主线 1c. 发现的缺失声明 — 文档与代码的偏差 2. SUT模型 3. 现有测试清单 — 已覆盖的内容 4. 故障模式假设 — 与声明ID关联 5. 覆盖矩阵 — 声明 × 假设 6. 技术选择 — 从目录中选取 6b. 环境要求 7. 场景 — 每个以声明命名,包含目标测试文件 + 骨架 7.M 模型/历史/检查器规范 — 当场景证伪{safety, durability, idempotency, isolation, ordering, membership}中的声明时为必填项:被测模型、操作历史模式、命名检查器、破坏者+着陆证据、模糊结果处理、缩减计划(SUT/测试工具/检查器/环境责任) 7b. 覆盖充分性论证 — 为什么这些测试足够 7c. 剩余不确定性 — 哪些内容未验证,以及为何可以接受 7d. 信心声明 — 评审者的判定 8. 本计划未覆盖的内容 9. 未解决问题/后续事项
示例§7.M块(计划摘录) ### 场景S3:分区下的线性一致性追加 - 如果FAIL则证伪:C1(每个已确认的追加都是持久且线性一致的),C5(领导者选举在5秒内完成) - 工作负载:8个客户端,70%追加/30%读取,5分钟,键偏斜Zipf分布 - 故障:在T+60秒时隔离当前领导者的非对称分区,持续30秒 - 预言:通过Porcupine对每个键的历史进行线性一致性检查
§7.M(模型/历史/检查器规范) - 被测模型:日志 - 操作历史:默认11字段模式(操作ID,进程ID,调用/完成时间戳,操作类型,键,输入,输出,错误,超时标记,可见节点,故障纪元)。进程内+服务端审计记录。 - 检查器:每个键的线性一致性(Porcupine),然后针对最终状态进行无丢失确认检查 - 破坏者+着陆:非对称分区(iptables丢弃一个方向)。着陆证据 = iptables丢弃计数器在30秒窗口内从0变为14,712,并且Raft日志在注入后2秒内发出“领导者丢失;开始选举”消息。 - 模糊结果:超时 → timeout_marker=true, complete_ts=null,视为可能已成功;重试是共享输入的独立操作 - 缩减计划:如果FAIL,二分故障窗口+固定种子,然后根据references/test-case-reduction.md分类为SUT/测试工具/检查器/环境
示例发现报告行
| ID | 判定结果 | 破坏者着陆证据 | 缩减类别 | |---|---|---|---| | S3 | PASS-强化 | iptables计数器0→14,712;Raft在T+1.8秒重新选举 | 不适用 | | S4 | FAIL-可复现 | 分区已着陆;Elle:键K17上的G2-item异常 | SUT | | S7 | INCONCLUSIVE-故障未证明 | iptables规则已安装但计数器保持为0 — 错误的链 | 测试工具 | | S9 | PARTIAL-模型 | 着陆正常;检查器覆盖了每个键,未覆盖跨键 | 不适用 |
(完整的发现模板包含预言、预言执行证据、产物链接、与计划的充分性对比部分以及信心变化 — 参见skills/executing-distributed-system-tests/assets/findings-report-template.md。)
安装(一行命令,任何代理)
在任何AI编码代理(Claude Code、Codex、Copilot CLI、Cursor、Gemini或任何其他能读取Markdown并运行Shell的工具)中粘贴以下内容:
`
Read https://raw.githubusercontent.com/shenli/distributed-system-testing/main/INSTALL.md
and follow the instructions to install and configure
distributed-testing-skills for this agent.
`
代理会获取INSTALL.md,将仓库克隆到~/.local/share/distributed-testing-skills/,并连接这些技能(对于Claude Code,在~/.claude/skills/下创建符号链接;对于其他代理,在~/AGENTS.md中创建一个指针块)。
之后,向机器上的任何代理询问“为这个系统设计一个测试计划”或“执行X处的计划”,它将遵循SKILL.md工作流程。
更新
再次粘贴同一行命令。INSTALL.md是幂等的:如果安装路径存在,则执行git pull --ff-only;如果不存在,则执行git clone。符号链接始终指向克隆的内容,因此它们会自动获取新版本。~/AGENTS.md指针块使用HTML标记,每次运行时都会被干净地替换 — 不会重复。
如果你对克隆的技能有本地编辑,git pull --ff-only将失败;代理会停止并在丢弃更改前询问。
## 手动安装(如果你更想看到发生了什么)
`bash
git clone https://github.com/shenli/distributed-system-testing.git \
~/.local/share/distributed-testing-skills
# Claude Code: 在~/.claude/skills/下创建符号链接 mkdir -p ~/.claude/skills ln -snf ~/.local/share/distributed-testing-skills/skills/designing-distributed-system-tests \ ~/.claude/skills/designing-distributed-system-tests ln -snf ~/.local/share/distributed-testing-skills/skills/executing-distributed-system-tests \ ~/.claude/skills/executing-distributed-system-tests
# Codex / Copilot CLI / Cursor / Gemini / 其他: 参见INSTALL.md
`
用法
技能安装完成后,你有两种驱动它们的方式:
随意询问(Claude Code带自动触发):
`
为这个代码库设计一个项目范围的测试计划。
`
`
针对这个代码库执行./testing-plans/<slug>.md处的计划。
`
技能描述会识别诸如“设计一个测试计划”、“执行计划”、“运行稳定性测试”、“设计一个发布验证计划”等自然措辞。
对于特定模式、输出路径或非自动触发代理,USAGE.md为每个工作流程(设计和执行,及其各自模式)提供了可复制粘贴的提示,以及关于范围、环境探测和长时间运行检查点的技巧。
这两项技能
designing-distributed-system-tests 遍历仓库,提取产品所做的声明,生成与这些声明相关的假设,从目录中选择技术,并编写一个结构化的Markdown计划,包含覆盖充分性论证和信心声明。对于一致性关键场景,计划为每个场景填充一个§7.M块:被测模型、操作历史模式、命名检查器、破坏者+着陆证据、模糊结果处理、缩减计划。详情:history-discipline.md。
两种模式:变更范围(特定提交或PR)和项目范围(包含现有测试清单和差距分析的整体计划)。
executing-distributed-system-tests 读取计划,发现SUT的工具箱,探测环境,并使用检查点规范运行场景。每个场景:捕获故障的着陆证据,运行“绿色但已损坏”和“弱预言”审计,从verdict-taxonomy.md中的9种状态分类法中分配一个判定结果,并在归档前将每个FAIL分类为SUT/测试工具/检查器/环境。生成一份包含与计划的充分性评估和信心变化的发现报告。
两种模式:默认模式(对SUT只读,会话目录下的临时测试工具)和作者模式(将计划§7中声明的场景骨架写入SUT以供审查)。
技术目录
从该领域文献中提炼的八个参考文件:
| 文件 | 何时使用 | |---|---| | catalog-index.md | 选择页面 — 从这里开始 | | jepsen-and-elle.md | 故障下的线性一致性/可序列化性 | | deterministic-simulation.md | 从种子可复现的错误;异步繁重代码 | | chaos-and-fault-injection.md | 真实集群的部分/非对称故障 | | fuzzing.md | 在消毒器下的输入或并发模糊测试 | | formal-methods-tla.md | 设计时的协议正确性 | | property-and-metamorphic.md | 代数定律/变形关系测试 | | performance-and-benchmarking.md | 尾部延迟/吞吐量/公平性 | | crash-recovery-and-upgrade.md | 持久性、重放、幂等性、混合版本 |
每个文件都遵循相同的结构:何时使用、它能很好地检测什么、它遗漏了什么、具体工具、论文、成本信号、计划检查清单。目录索引将症状与参考文件配对。
## 仓库布局
`
.
├── plugin.json ← 可选的插件清单
├── README.md ← 本文件
├── INSTALL.md ← 幂等安装/更新(可粘贴)
├── USAGE.md ← 每个工作流程的可复制粘贴提示
├── LICENSE
├── skills/
│ ├── designing-distributed-system-tests/
│ │ ├── SKILL.md ← 设计工作流程
│ │ ├── assets/plan-template.md ← §0–§9,包含有条件的§7.M
│ │ └── references/ ← 8文件技术目录+索引、
│ │ 常见分布式系统陷阱、
│ │ 历史规范
│ └── executing-distributed-system-tests/
│ ├── SKILL.md ← 执行工作流程
│ ├── assets/
│ │ ├── session-log-template.md
│ │ └── findings-report-template.md ← 9种状态判定结果+着陆证据
│ └── references/ ← 预言模式(检查器选择器+13种模式)、
│ 故障注入指南(22行破坏者分类法)、
│ 测试用例缩减(含责任分类)、
│ 绿色但已损坏红旗标志(含弱预言审计)、
│ 发现分类(TaxDC)、
│ 判定结果分类法(9种状态)
├── evals/ ← 两项技能的评估套件
├── verification/ ← 针对AgentDB的真实运行(具体输出)
└── specs/ ← 原始设计规范
`
状态
早期但已实践。两项技能已多次端到端地针对AgentDB(一个用Rust编写的分布式代理运行时)驱动,发现了六个发现(一个P0候选现已关闭,两个P1作为PR已发布,两个仍开放)。技能主体随着测试工具经验的积累而演变;预计在接下来的几次迭代中会对SKILL.md和模板进行小幅更新。
来自这些运行的真实计划输出、会话目录和发现报告位于verification/下,每个运行一个子目录,每个子目录包含一个README.md,描述了什么通过、什么失败以及技能在此过程中揭示了关于自身的什么。值得注意的运行:
- verification/agentdb-fab7d9d/ — 针对AgentDB提交fab7d9d的变更范围计划+执行(持久幂等追加重放);670行计划,涵盖所有八个故障模式类别的16个假设。 - verification/agentdb-jepsen/ — 带线性一致性检查的一致性+崩溃恢复运行。 - verification/agentdb-projectwide-lidev/ 和 -v2 — 项目范围计划,包含完整的覆盖矩阵+充分性论证+信心声明。
此外,在evals/下还有一个评估套件(设计和执行技能各有独立的evals.json)——用于验证SKILL.md主体在迭代之间的行为变化。
致谢
技术目录提炼自Andrey Satarin的综合测试分布式系统目录。支撑该目录的开创性论文包括:
- Yuan等人,“简单测试可以防止大多数关键故障”(OSDI'14) - Gunawi等人,“云中有什么错误?”(SoCC'14) - Zheng等人,“为了乐趣和利润折磨数据库”(OSDI'14) - Kingsbury和Alvaro,“Elle:从实验观察推断隔离异常”(VLDB'20) - Alfatafta等人,“迈向部分网络分区的通用容错技术”(OSDI'20) - Lou等人,“理解、检测和定位大型系统软件中的部分故障”(NSDI'20) - Gao等人,“大规模分布式系统中崩溃恢复错误的实证研究”(FSE'18) - Zhang等人,“理解和检测分布式系统中的软件升级故障”(SOSP'21) - Bornholt等人,“使用轻量级形式化方法验证Amazon S3中的键值存储节点”(SOSP'21) - Newcombe等人,“Amazon Web Services如何使用形式化方法”(CACM'15)
许可证
MIT。