| name | evidence-driven-bugfix |
| description | 證據驅動除錯流程。Use for: (1) Bug 修復的結構化流程(重現 -> failing test -> 根因 -> 最小修復 -> 回歸防護), (2) 防止盲目猜測修復, (3) 確保每次修復可驗證、可追溯、可累積。Use when: 收到 bug report、測試失敗需要調查、生產環境問題需要修復、任何非新功能的程式碼修正。 |
/bugfix - 證據驅動除錯流程
核心原則:先有證據,才能動手。
沒有最小重現、沒有 failing test、沒有根因證據之前,禁止直接改程式碼。
反模式
| 反模式 | 後果 |
|---|
| 「我大概知道怎麼修,先 patch 再說」 | 修到症狀不是根因 |
| 跳過 failing test 直接改 code | 不知道到底修對沒 |
| 沒有調查紀錄 | 下次同類 bug 又得重查一次 |
| 一邊查一邊改 | 改動範圍失控,引入新問題 |
| 修改測試斷言來讓測試通過 | 測試失去防護價值,bug 仍存在 |
| 硬編碼預期值繞過測試 | 下次資料變動立即再次失敗 |
| 不查根因直接改程式碼試試看 | 表面通過但根因未解,同類 bug 反覆出現 |
流程模式
本流程有兩種執行模式,依據緊急程度選擇:
| 模式 | 適用場景 | 必做階段 | 可延後階段 |
|---|
| 標準模式 | 一般 bug 修復 | Stage 1-8 全部 | 無 |
| Hotfix 模式 | 生產環境緊急問題 | Stage 1-5 | Stage 6-8(24 小時內補齊) |
與 pre-fix-eval 的銜接
/pre-fix-eval 是錯誤的入口分類器,/bugfix 是修復執行流程。
| pre-fix-eval 產出 | bugfix 入口 | 說明 |
|---|
| 有初步根因定位(Stage 4 完成) | 從 Stage 2 開始 | 根因假設已有,直接補 failing test 驗證 |
| 只有錯誤分類(Stage 1-3 完成) | 從 Stage 1 開始 | 需要完整重現和分析 |
| 直接由用戶觸發(無 pre-fix-eval) | 從 Stage 1 開始 | 完整流程 |
八階段流程
Stage 1: 最小重現 [執行者: 認領 Ticket 的開發者]
|
Stage 2: 補 Failing Test [執行者: 同上]
|
Stage 3: 驗證根因假設 [執行者: 同上 / incident-responder]
|
Stage 4: 實作最小修復 [執行者: 語言對應的 developer agent]
|
Stage 5: 回歸防護 [執行者: 同 Stage 4]
|
Stage 6: 規格合規審查 [執行者: /parallel-evaluation 派發]
|
Stage 7: 程式碼品質審查 [執行者: /parallel-evaluation 派發]
|
Stage 8: 結案報告 [執行者: 認領 Ticket 的開發者]
與既有工具的銜接
| 階段 | 對應的專案工具 |
|---|
| 進入本流程前 | /pre-fix-eval(錯誤分類 + Ticket 開設) |
| Stage 3 深度分析 | incident-responder(複雜根因需要時派發) |
| Stage 4 實作 | 語言對應的 developer agent |
| Stage 6-7 審查 | /parallel-evaluation(派發後以其檢查清單為準) |
| Stage 8 結案 | /doc-flow(工作日誌)、/error-pattern add(錯誤模式) |
Stage 1:最小重現
目標:把「使用者描述的症狀」轉成「可判斷的重現條件」。
執行者:認領 Ticket 的開發者。
產出:重現步驟或腳本 + 環境條件記錄。
標準路徑(確定性 bug)
| 檢查項 | 說明 |
|---|
| 重現步驟是否穩定? | 連續執行 3 次都能觸發 |
| 環境條件是否記錄? | 瀏覽器版本、OS、資料狀態 |
| 是否為最小條件? | 移除任何一步就無法重現 |
替代路徑(非確定性 bug)
適用場景:race condition、時序問題、Chrome Service Worker 生命週期問題、特定網站結構下觸發。
| 替代條件 | 說明 |
|---|
| 有觸發條件描述 | 能說明在什麼狀態/時序下容易觸發 |
| 有日誌或錯誤截圖證據 | 至少有一次觸發的完整記錄 |
| 有機率估計 | 如「十次操作約觸發三次」 |
滿足以上三項即可通過閘門,進入 Stage 2 時使用防禦性測試策略(測試邊界條件而非精確重現)。
閘門:標準路徑或替代路徑任一滿足即可進入 Stage 2。兩者皆不滿足 → 回頭補充資訊。
Stage 2:補 Failing Test
目標:把重現步驟轉成穩定失敗的測試或結構化驗證計畫。
執行者:認領 Ticket 的開發者。
標準產出(可自動化)
至少一個 failing test,精確描述「預期行為」與「實際行為」的差異。
| 要求 | 說明 |
|---|
| 測試命名 | 描述 bug 行為,如 test_should_not_crash_when_empty_input |
| 斷言精確 | 斷言預期的正確行為,不是斷言「不 crash」 |
| 獨立可執行 | 不依賴其他測試的副作用 |
替代產出(無法自動化)
適用場景:Chrome 跨 context 通訊、popup/background 互動、UI 渲染問題等 Jest mock 無法真實覆蓋的場景。
產出一份結構化手動驗證計畫:
## 手動驗證計畫
### 前置條件
[環境設定、資料準備]
### 驗證步驟
1. [具體操作步驟]
2. [預期結果]
3. [實際結果欄位(執行時填寫)]
### 通過標準
[明確的 pass/fail 判斷條件]
手動驗證計畫視為技術債,在 Stage 8 記錄,後續版本補自動化測試。
閘門:標準產出或替代產出任一完成即可進入 Stage 3。
Stage 3:驗證根因假設
目標:帶著 failing test 回頭讀 code,找出真正失敗的原因。
執行者:認領 Ticket 的開發者。複雜問題可派發 incident-responder。
流程:
- 列出所有合理的根因假設(不限數量;若超過 5 個,先依影響範圍排序,取前 3 個驗證)
- 執行「假設粒度自檢」(見下方清單,反模式 3 防護)
- 對每個假設設計驗證方式(加 log、讀 code、LSP 追蹤引用)
- 逐一排除,直到定位唯一根因
- 記錄排除過程(供日後參考)
假設粒度自檢清單(W17-104 反模式 3 防護)
Why:W17-102 Test G 設計時用「PM 是否已 Edit 過該檔」(檔案層級)作變因,否證後直接跳到「不是 PM 接觸史」結論。但真正的變因可能在不同粒度——「PM 是否已 Edit 過 prefix(.claude/)內任一檔」(前綴層級)。同一個變因在不同粒度可能得到相反結論。
Consequence:粒度錯誤會讓對照實驗的否證跳到錯誤結論。否證「該檔層級的 PM 接觸史」≠ 否證「整個 PM 接觸史變因」。
Action:列假設後、設計驗證實驗前,對每個假設執行粒度自檢:
| 粒度層 | 範例(以「檔案修改史」為變因) | 範例(以「session 狀態」為變因) |
|---|
| 檔案層 | 該特定檔是否被改過 | 該檔在當前 session 是否被觸碰 |
| 前綴 / 目錄層 | .claude/ 下任一檔是否被改 | session 內是否曾操作該前綴 |
| 模組 / 命名空間層 | 同模組任一檔是否被改 | session 內是否載入該模組 |
| Session 層 | 任一 session 內檔案修改紀錄 | 當前 session 是否處於某狀態(已 commit / 已 pytest) |
| 跨 session 層 | 跨 session 累積修改 | 跨 session 累積觸發狀態 |
| 時間層 | 修改時間段(過去 N 分鐘 / N 小時 / N 天) | session 啟動時間距今 |
| 全域層 | 系統全域狀態(CC 版本 / 環境變數 / OS) | runtime 全域狀態 |
自查問句(每個假設都要問):
- 我選的粒度是「檔案層」「前綴層」「模組層」還是更高?
- 是否有更細粒度(檔案內的特定行)或更粗粒度(整個目錄/session)的同類變因?
- 否證該粒度後,是否需要驗證其他粒度才能完整否證該假設族?
強制動作:每個假設至少考慮 2 個相鄰粒度層;若只考慮單一粒度即進入驗證實驗,標記為「粒度未充分」並補實驗或在結論中明示。
粒度修正的教訓:先以大粒度否證後,若未驗證相鄰粒度即下結論,假設族否證不完整(需補相鄰粒度實驗)。
工具選擇:
| 需求 | 工具 |
|---|
| 追蹤函式呼叫鏈 | Serena find_referencing_symbols |
| 搜尋特定模式 | Grep / search_for_pattern |
| 理解符號結構 | Serena get_symbols_overview |
外部因素退出點
若 Stage 3 確認根因不在本專案(如外部平台 API 行為變更、目標站點改版、上游套件行為變更):
- 記錄證據(API 文件、changelog、網站截圖)
- 開 workaround Ticket(類型 IMP,標題含「workaround」)
- 退出本流程,在 Stage 8 產出簡化報告
閘門:根因已確認(含外部因素確認) → 進入 Stage 4。禁止「看起來像是這裡的問題」就動手。
迭代上限:Stage 3↔4 來回不超過 3 次(Hotfix 模式下為 2 次)。超過上限仍無法定位 → 升級為 incident,派發 incident-responder 深度分析。Stage 6/7 回退到 Stage 4 後,迭代計數器重置(因根因已確認,問題性質不同)。
Stage 4:實作最小修復
目標:只改讓 failing test 通過的最小範圍。
執行者:語言對應的 developer agent。
| 原則 | 說明 |
|---|
| 最小變更 | 修改檔案數 <= 3,diff 行數建議 < 50 行 |
| 超過需說明 | 超過上述範圍須在 Ticket log 記錄理由 |
| 不擴大範圍 | 發現周圍有問題 → 開新 Ticket,不在此修 |
| 確認 test 變綠 | 修完立即執行 Stage 2 的 failing test |
| 修產品程式碼,不修測試 | 見下方「測試完整性保護」 |
測試完整性保護
修復的目標是讓產品程式碼符合測試描述的正確行為,而非反過來。
| 禁止行為 | 範例 | 為什麼禁止 |
|---|
| 修改斷言值 | expect(result).toBe(3) 改成 toBe(5) | 測試描述的是正確行為,改斷言 = 改需求 |
| 硬編碼通過 | 函式直接 return 3 讓測試過 | 沒有解決邏輯問題,只騙過斷言 |
| 刪除失敗測試 | 刪掉「不方便」的測試案例 | 測試覆蓋率下降,bug 不被偵測 |
| 放寬驗證條件 | toEqual 改成 toBeTruthy | 降低測試精度,喪失防護力 |
唯一允許修改測試的場景:Stage 3 根因分析確認測試本身的預期值有誤(如需求變更但測試未同步)。此時必須:
- 在 Ticket log 記錄「測試預期值修正」及修正理由
- 引用需求文件或 use case 作為新預期值的依據
- 修正後的測試仍必須能驗證正確行為
閘門:Stage 2 的 failing test 變綠 → 進入 Stage 5。未變綠 → 回到 Stage 3(受迭代上限約束)。
Stage 5:回歸防護
目標:避免同一個 bug 之後偷偷回來。
執行者:同 Stage 4。
| 動作 | 說明 |
|---|
| 確認 failing test 已納入 CI | 不是臨時腳本,是正式測試 |
| 補邊界測試 | 根因相同但輸入不同的場景,至少補 1 個測試 |
| 執行完整測試套件 | npm test 確認無回歸 |
測試失敗分流
完整測試套件出現失敗時:
| 情況 | 判斷方式 | 處理 |
|---|
| 本次修復導致 | git stash 後失敗消失 | 回到 Stage 4 修正 |
| 既有 flaky test | git stash 後仍失敗 | 開獨立 Ticket 追蹤,不阻擋本流程 |
閘門:完整測試套件通過(排除已記錄的 flaky test) → 進入 Stage 6。未通過 → 依分流表處理。
Stage 6:規格合規審查
目標:確認修復符合原始需求與驗收條件。
執行者:透過 /parallel-evaluation 派發,以其檢查清單為準。
以下為最低檢查項(若 /parallel-evaluation 已涵蓋則不重複):
| 檢查項 | 說明 |
|---|
| 修復是否符合 use case 描述? | 對照 docs/use-cases.md |
| 是否引入行為變更? | 對使用者可見的行為改變需記錄 |
| 驗收條件是否滿足? | 對照 Ticket 的驗收條件 |
閘門:審查通過 → 進入 Stage 7。不通過 → 回到 Stage 4 修正(不重置 Stage 3 的根因結論)。
Stage 7:程式碼品質審查
目標:確認修法乾淨、可維護、無副作用。
執行者:同 Stage 6(通常與 Stage 6 在同一次 /parallel-evaluation 中完成)。
以下為最低檢查項(若 /parallel-evaluation 已涵蓋則不重複):
| 檢查項 | 說明 |
|---|
| 符合專案品質基線? | 對照 .claude/references/quality-common.md |
| 無硬編碼? | 常數提取、訊息外部化 |
| 可觀測性? | 錯誤路徑有日誌 |
| 無過度修改? | diff 只含必要變更 |
閘門:審查通過 → 進入 Stage 8。不通過 → 回到 Stage 4 修正。
Stage 8:結案報告
目標:整理修復紀錄,讓經驗可累積。
執行者:認領 Ticket 的開發者。
最小產出:
## Bug Fix Report
### 症狀
[使用者觀察到的問題]
### 根因
[Stage 3 確認的根本原因]
### 修復方式
[Stage 4 的修改摘要]
### 影響範圍
[修改的檔案清單 + 影響的功能模組]
### 排除的假設
[Stage 3 中排除的其他假設及排除理由]
### 回歸防護
[Stage 5 新增的測試]
### 殘留風險
[已知但未處理的相關問題,已開 Ticket 追蹤]
### 技術債
[Stage 2 的手動驗證計畫待自動化、其他待處理項目]
### 關聯資訊
- Ticket ID: [ID]
- 修復耗時: [時間]
- 關聯 Ticket: [相關 Ticket ID]
額外動作:
- 若為常見錯誤模式 →
/error-pattern add 記錄
- 更新工作日誌 →
/doc-flow
- 標記 Ticket 完成 →
/ticket track complete
複合 bug 處理
一個 bug report 實際上包含多個獨立問題時:
| 時機 | 判斷標準 | 處理 |
|---|
| Stage 1 發現 | 重現步驟觸發多個不同症狀 | 拆分為獨立 Ticket,各自走完整流程 |
| Stage 3 發現 | 根因分析指向多個獨立原因 | 當前 Ticket 只修第一個根因,其餘開新 Ticket |
閘門總覽
| 階段 | 閘門條件 | 不通過時 |
|---|
| Stage 1 → 2 | 標準路徑或替代路徑任一滿足 | 回頭補充資訊 |
| Stage 2 → 3 | 有 failing test 或手動驗證計畫 | 不准開始分析 |
| Stage 3 → 4 | 根因已確認(含外部因素) | 不准開始修改 |
| Stage 3 → 8 | 外部因素確認(捷徑) | 產出簡化報告,開 workaround Ticket |
| Stage 4 → 5 | failing test 變綠 | 回到 Stage 3(上限 3 次 / Hotfix 2 次) |
| Stage 5 → 6 | 完整測試通過(排除已知 flaky) | 依分流表處理 |
| Stage 6 → 7 | 規格合規審查通過 | 回到 Stage 4 修正(迭代計數器重置) |
| Stage 7 → 8 | 品質審查通過 | 回到 Stage 4 修正(迭代計數器重置) |
使用方式
/bugfix
顯示本流程概覽和閘門總覽。
/bugfix start [ticket-id]
從 Stage 1 開始完整流程。行為:
- 若提供 ticket-id,載入 Ticket 資訊作為 bug 描述
- 若無 ticket-id,提示用戶描述症狀
- 引導進入 Stage 1
/bugfix stage N [ticket-id]
跳到指定階段。行為:
- 檢查前置閘門是否已通過(讀取 Ticket log)
- 閘門未通過 → 拒絕跳轉,提示需先完成哪個階段
- 閘門已通過 → 進入指定階段
/bugfix hotfix [ticket-id]
啟動 Hotfix 模式。行為:
- 執行 Stage 1-5(與標準模式相同)
- Stage 5 完成後直接產出簡化結案報告
- 自動建立延後 Ticket:「補齊 Stage 6-8 審查」(priority: P0,due: 24 小時內,who: PM 在下一個 session 檢查)
Last Updated: 2026-04-02
Version: 2.2.0 - 新增測試完整性保護規則(禁止修改測試繞過失敗)