# Flaky Test Hunter

> 從 CI 跑歷史紀錄統計每個測試的失敗率，識別 flaky test（重跑就過的不穩定測試）、給出修復建議、自動標記到 quarantine（隔離區）讓 CI 不被假失敗阻擋。支援 GitHub Actions / GitLab CI / CircleCI / Jenkins JUnit XML / pytest-xdist 失敗紀錄。當使用者提到「flaky test / 不穩定測試 / 假失敗 / retry 才過 / CI 不穩 / quarantine test / 隔離測試 / 找出 flaky / 修 flaky」時觸發。配套：smoke-test-analyzer（flaky 不該進 T0）、test-review（審 flaky pattern）、bug-report（追 flaky bug）。

- Skill: `kao273183/flaky-test-hunter` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add kao273183/flaky-test-hunter`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kao273183/flaky-test-hunter/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: kao273183 (https://skillmd.com/u/kao273183)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/kao273183/flaky-test-hunter

---


# flaky-test-hunter

> ⚙️ **執行前先讀 [`modules/config-loader.md`](./modules/config-loader.md)**。

## 為什麼需要這個 skill

Flaky test 是 CI 信任度殺手：
- 工程師看到紅燈第一反應是「應該又是 flaky，按 retry」
- 久了真實 bug 也被當 flaky 忽略
- 浪費 CI 時間（重跑成本）
- 工程師對自動化測試失去信心 → 開始 skip

→ 這個 skill **量化哪些測試在 flaky、給數據說服團隊修**。

## 適用場景

- ✅ CI 有歷史紀錄（GitHub Actions / GitLab / CircleCI 至少跑 1 個月）
- ✅ 開始懷疑某些測試「隨機 fail」
- ✅ Release 前想清理 flaky 避免假警報
- ✅ 想把 flaky 自動移到 quarantine（隔離區）

## 不適用場景

- ❌ 沒 CI 歷史 / 剛起步 — 先累積數據
- ❌ 全部測試都 flaky — 系統性問題，不是個別 fix
- ❌ Manual test 不穩 — 跟程式碼 flaky 是不同問題

## 執行流程

### Phase 1: 收集 CI 失敗紀錄

支援來源：

| CI 平台 | 取得方式 |
|---------|---------|
| **GitHub Actions** | `gh run list --workflow=ci.yml --json` + `gh run view <id>` |
| **GitLab CI** | `glab ci list` + GitLab API |
| **CircleCI** | CircleCI API |
| **Jenkins** | JUnit XML 直接讀 |
| **pytest local** | `pytest --json-report` 連續跑 N 次 |

預設讀過去 `{{FLAKY_DAYS}}` 天（預設 30 天）的紀錄。

### Phase 2: 計算每個測試的 flakiness score

```
flakiness_score = (failures_in_passing_runs / total_runs) × 100%
```

Flakiness 定義：
- **Stable**: 0% flakiness（每次都 pass）
- **Stable-fail**: 失敗率 > 80% 且每次都 fail（真實 bug，不是 flaky）
- **Flaky**: 失敗率 1-80%（時 pass 時 fail）

只列出 **Flaky** 區間的測試。

### Phase 3: 分類 flaky 嚴重度

| 分類 | Flakiness | 處理建議 |
|------|-----------|---------|
| 🔴 **High flaky** | > 30% | 立刻 quarantine + 修 |
| 🟡 **Medium flaky** | 10-30% | 排程修，先進 quarantine |
| 🟢 **Low flaky** | 1-10% | 監控，看是否持續惡化 |

### Phase 4: 識別 flaky 根因 pattern

掃描 flaky test 的程式碼，找常見問題：

| Pattern | 範例 | 修復方向 |
|---------|------|---------|
| **Hard-coded sleep** | `Thread.sleep(2000)` / `await delay(2000)` | 改 `waitFor(condition)` |
| **依賴時序** | `expect(time.now() - start < 1000)` | 改 deterministic time / clock injection |
| **共享狀態** | 全域 singleton 累積 | 每 test setUp/tearDown 重置 |
| **依賴外部網路** | call real API | Mock HTTP boundary |
| **隨機資料** | `Math.random()` 沒固定 seed | 固定 seed / faker.seed() |
| **DB race condition** | 平行測試讀寫同 row | 用 unique key / transaction |
| **動畫 / 過場** | `cy.contains("Welcome")` 但動畫沒完 | `cy.get(...).should("be.visible")` |
| **non-deterministic 順序** | `expect(arr).toEqual([1,2,3])` 但實際 order 不定 | 用 `arrayContaining` |
| **Memory / 資源洩漏** | 跑久了變慢 | 每 N test 重啟 worker |

### Phase 5: 產出報告

寫到 `~/.local/share/qa-flaky/{repo}/report-{date}.md`：

```markdown
# Flaky Test Report · my-app · 2026-05-22

## 📊 整體
- 分析期間: 過去 30 天 (n=842 runs)
- 總測試數: 1247
- Stable: 1186 (95.1%)
- Flaky: 42 (3.4%)
- Stable-fail: 19 (真實 bug，不是 flaky)

**Flakiness Score**: 3.4% （目標 < 2%）

## 🔴 High flaky (> 30%)

### #1 `LoginUITests.testRetryAfterFailure` (Flakiness: 47%)
- 平台: iOS
- 失敗次數: 23 / 49 runs
- 最近失敗: 2026-05-21
- **疑似根因**: `Thread.sleep(2000)` (line 42) + 依賴後台 token expiry
- **建議修復**:
  1. 改用 `expect(element).toExist()` 等待條件
  2. 注入 fake clock，控制 token expiry
- **隔離**: 加 `@QuarantineFlaky` annotation，CI 標 warning 不阻擋

### #2 `WebSocketTest.testReconnect` (Flakiness: 35%)
- 平台: Backend
- ...

## 🟡 Medium flaky (10-30%)
[10 條...]

## 🟢 Low flaky (1-10%)
[30 條...]

## 📋 自動化處理建議

立刻動作:
- [ ] Quarantine 8 條 High flaky (PR: feature/quarantine-flaky)
- [ ] 建 8 個 JIRA ticket 追蹤修復（用 bug-report skill）

中期動作:
- [ ] 設 CI gate: flakiness > 30% 自動標 quarantine
- [ ] 把 Quarantine 區獨立成 nightly job，不阻 PR

## 📈 趨勢

- 上次報告 (2026-04): 5.1% flakiness
- 這次:                3.4% (-1.7% 改善 ✅)
```

### Phase 6: 自動處理選項

互動式問使用者：
- 要不要對 High flaky 加 `@Disabled` / `@QuarantineFlaky` annotation？
- 要不要建 JIRA ticket（用 `bug-report` skill）追蹤修復？
- 要不要產 PR 把 flaky 移到隔離區？

預設**不主動修改測試碼**，只給建議。

## ⚠️ 安全護欄

- ❌ 不主動 disable test（必使用者明確同意）
- ❌ 不對 stable-fail（真實 bug）標 flaky
- ✅ Quarantine 標記必含 "must-fix-by: YYYY-MM-DD" 避免被忘記
- ✅ 報告寫 `~/.local/share/qa-flaky/`，不污染 repo

## 設定依賴

| 設定 Key | 用途 | 缺值時行為 |
|---------|------|-----------|
| `flaky_hunter.ci_platform` | CI 平台類型 | 偵測 `.github/workflows/` 等推斷 |
| `flaky_hunter.lookback_days` | 分析天數 | 預設 30 |
| `flaky_hunter.flaky_threshold` | 標 flaky 起始失敗率 | 預設 1% |
| `flaky_hunter.high_flaky_threshold` | 高嚴重度標準 | 預設 30% |

## 配套整合

```
持續看到 CI 不穩
   ↓
/flaky-test-hunter
   ↓ 報告找出 42 條 flaky
   ↓
互動式 → 對 8 條 High flaky 加 @Quarantine
   ↓
/bug-report → 為 8 條建 JIRA ticket
   ↓
修復後重跑 /flaky-test-hunter → 看 score 是否降
```

## 範例

詳見 [`examples.md`](./examples.md)

