用途:处理 PostHog 仓库中在 CI 上偶发失败、但本地往往通过的 flaky 测试(测试不稳定/间歇性失败)。核心原则有三:先复现再修复;修根因而非症状;用 N 次循环验证,单次通过不能证明稳定。分类判定须基于 GitHub Actions API 的运行数据,而非 hogli ci:insights 摘要或 Slack 告警等二手信息。
主要流程:
- 度量失败率——用 gh run list 拉取目标 workflow 与分支的结论时间线,再用 gh api repos/PostHog/posthog/actions/jobs/{job_id}/logs 确认每次失败是同一测试;相邻提交上通过/失败交替才是真 flaky,长时间连续失败更可能是确定性回归(应改用 debugging-ci-failures)。先查 git log 和 hogli ci:insights 是否已有修复。
- 提取失败——用 gh run view <run-id> --log-failed,并记录精确测试 ID、断言/报错、周围告警(如 [MSW] Unhandled)、同分片相邻测试。
- 本地复现——按阶梯升级:单跑、默认 20 次循环、模拟 CI 条件(如 pnpm --filter=@posthog/frontend jest <test_file> <neighbor_file> --maxWorkers=2 --forceExit)、调整顺序、制造资源竞争。循环以退出码判定,首次失败即停止以捕获日志。
- 定位根因——按症状匹配原因:未 await 的异步、共享状态、真实时钟、非确定顺序、最终一致性、竞态。可用 CI 运行历史二分(最后绿 → 首次红)或 git bisect(仅适用于确定性失败)。列出 PostHog 特有模式:Jest+kea 缺 MSW mock、toFinishAllListeners() 超时、mock URL 不匹配、每测试重置 handler、未卸载的 logic;pytest 的 DB 状态泄漏、真实时间、ClickHouse 最终一致性。
- 修复——await 具体条件、找挂起原因,不抬高超时;重试仅限真正不确定的外部设施并附注释与 issue;跳过/隔离需用户明确批准;断言应通过排序、冻结、种子化保持严格。
- 验证——重现条件下跑 N 次循环,N 取 max(3k, 20)(k 为失败率倒数);无法本地复现则跑 20 次并标注为分析性验证;最后跑一次完整文件/套件。
- 报告——含测试、CI 观测率、本地复现命令、根因、修复、验证结果与后续项。
边界:不通过重跑 CI、推送或发 GitHub 评论来“测试”修复;不改 .github/workflows/;不为让 flaky 通过而接受快照。分类为 testing。