FlakeGate:别再把 flaky test“重跑到绿”了

发布时间:2026/7/19 13:37:15
FlakeGate:别再把 flaky test“重跑到绿”了 最近两三周一直在针对开发方面的问题进行优化是否还能做一些有意义的开源项目也是挺值得思考的发现很多地方叶被大厂拿下了然后在某天项目合作的业务处理上发现很有意思的一点我们知道agent时代已经到来了很快agent集群的落地和agent任务的落地那么它的工程性质回更强现在遇到一个很场景的问题就是在CI有时候反馈给你出问题失败的不是刚修改的业务逻辑而是一个偶尔超时的集成测试。团队已经见过它很多次所以没有人先分析代码差异也没有人认真读失败栈。最自然的反应是“先重跑一下。”第二次运行变绿合并继续。看起来问题已经解决但实际上团队失去了一样更重要的东西对红色构建的信任。总的问题而言一旦“重跑到绿”成为默认动作CI 的失败就不再能清楚回答一个最基本的问题代码到底坏没坏开发者会逐渐忽略红灯发布负责人会依赖经验判断coding agent 看到的也只是一段没有历史背景的错误信息。Flaky test 的成本不只是多跑几分钟机器。它会污染整个工程系统的决策信号。接下来我会先针对商用角度去回答这个问题最近两三周一直在针对开发方面的问题进行优化是否还能做一些有意义的开源项目也是挺值得思考的发现很多地方叶被大厂拿下了然后在某天项目合作的业务处理上发现很有意思的一点我们知道agent时代已经到来了很快agent集群的落地和agent任务的落地那么它的工程性质回更强现在遇到一个很场景的问题就是在CI有时候反馈给你出问题失败的不是刚修改的业务逻辑而是一个偶尔超时的集成测试。团队已经见过它很多次所以没有人先分析代码差异也没有人认真读失败栈。最自然的反应是“先重跑一下。”第二次运行变绿合并继续。看起来问题已经解决但实际上团队失去了一样更重要的东西对红色构建的信任。总的问题而言一旦“重跑到绿”成为默认动作CI 的失败就不再能清楚回答一个最基本的问题代码到底坏没坏开发者会逐渐忽略红灯发布负责人会依赖经验判断coding agent 看到的也只是一段没有历史背景的错误信息。Flaky test 的成本不只是多跑几分钟机器。它会污染整个工程系统的决策信号。接下来我会先针对商用角度去回答这个问题Retry 为什么不是治理策略Retry 能降低一次偶发失败阻断流水线的概率但它没有回答三个问题1. 这个测试是否真的已经有 flaky 证据2. 如果暂时放行谁负责修、什么时候到期3. 同一份报告里如果出现一个新的真实回归怎样保证它不会被一起放过去简单的 retry 或 blanket quarantine 很容易把“降低噪音”变成“降低警觉”。最危险的结果不是 CI 经常变红而是团队学会了忽略红色。因此一个完整方案至少需要三种能力检测、隔离和治理。只有检测列表没有最终 gate团队仍然要人工猜测只有 quarantine没有 owner 和 expiry临时例外最终会变成永久债务。FlakeGate 的边界已知 flaky 可以放行未知回归必须保持红灯FlakeGate 是一个本地优先的 flaky-test CI gate。它把每次 CI 产生的标准 JUnit XML 写入本地 SQLite 历史并从中寻找同一代码上的结果矛盾。最强的两类证据是同一次运行中一个逻辑测试既通过又失败同一个 commit SHA 的不同运行中同一测试既通过又失败。五步闭环这里我就简单描述了希望佬们有问题开源直接问FlakeGate 的完整路径不是“检测以后自动跳过”而是通过1.Ingest每次 CI 结束后读取 JUnit XML2.Detect从 SQLite 历史中寻找同代码矛盾和反复振荡3.Suggest为有证据的 finding 生成待审核的隔离条目4.Govern把 reason、owner、since、expires 写进版本控制5.Gate根据当前报告和有效策略决定最终退出码。代码没有变化而结果相反这比“某个测试失败了一次”提供了更明确的 flaky 证据。对于长期在不同 commit 之间反复翻转的测试FlakeGate 还会计算普通 flip rate 和近期权重更高的 EWMA flip rate。同时它保护一个关键性质一次真实 regression 从绿变红并持续为红只发生了一次状态翻转不应该因此被高分识别为 flaky。有效隔离中的 flaky test 仍然执行、仍然记录、仍然出现在报告里只是不再阻断合并。未知失败继续阻断。隔离到期后的失败也重新阻断。Quarantine-as-codeFlakeGate 不把 quarantine 状态藏在一个独立 dashboard 中而是使用项目仓库里的 .flakegate.yml这意味着 quarantine 不是测试的坟场而是一条有负责人、有时钟、有退出条件的修复队列。配置会拒绝未知字段、错误日期、重复 test ID 和缺失治理字段。条目在 expires 当天仍然有效从第二天开始重新进入阻断路径。这样做的好处是隔离通过现有 pull request 流程审核责任和期限在代码历史中可追踪不需要再维护一套孤立权限和状态系统。为什么是 JUnit XML SQLite 单二进制FlakeGate 有意保持一个很窄的集成面。JUnit XMLpytest、Jest、Maven Surefire、Gradle、gotestsum、RSpec 等大量框架都可以输出 JUnit。与其为每个框架写插件不如统一读取测试已经产生的报告。SQLite历史不需要另一个托管服务。一个 SQLite 文件可以通过 CI 自己的 cache 或 artifact 机制在运行之间传递。测试数据仍留在用户自己的基础设施内。纯 Go 二进制FlakeGate 使用 pure-Go SQLite 驱动不需要 CGO。Linux、macOS 和 Windows 可以使用同一个集成模型。核心工作流不要求网络。只有可选 BYOK 根因分类和显式启用的 GitHub issue escalation 会访问外部接口。同一个判断同时提供给人、CI 和 coding agentFlakeGate 的数据型命令支持稳定 JSONgate 可以写 GitHub Markdown summary本地 stdio MCP 则提供 test status、detect、gate 和 quarantine 查询。这解决了 agentic development 中一个很现实的问题coding agent 通常只能看到当前失败却不知道它是否曾经在同一 commit 上通过也不知道团队是否已经为它建立了有效隔离。通过本地 MCPagent 获得的不是一个模糊的“可能 flaky”而是和 CI 使用同一份历史、同一份配置与同一套边界得出的判断。部分实验结果因为还没有佬使用过然后这个也在开发阶段我们只能用已经用的数据做了测试测试结果如下FlakeGate 的 benchmark 将不同问题拆开验证因为没有一个数据集能同时证明检测、产业影响、外部覆盖和 gate 安全性。当前仓库中可复现的主要结果包括- FlakeFlagger ICSE 202126,765 个带标签测试其中 828 个 flaky、25,937 个 stable- 原始归档回放47,430 份 Surefire XML、869,550 次测试执行- IDoFT 固定快照10,687 个有效唯一记录、916 个项目和 14 个观察类别- 17 个严格定义的固定 revision false-red 运行对 retry、active quarantine、unknown regression 和 expiry 分别执行 17/17 控制- 100,000 次执行的本机 microbenchmark当前流式聚合测得 13.3 ms、3.83 MB/op 和 10,036 allocs/op。最后欢迎各位佬能持续提供意见和支持这个项目算是我除了商业方面看到的算是第一个开源很多地方都是自己想想也感谢各位佬的star和关注GitHubGitHub - xiao-zi-chen/FlakeGate · GitHub项目网站FlakeGate — Make red mean broken again