debug-protocol · git:20260714.6307d7e · 2026-07-14 · sha256 b344b1671d118e3f

debug-protocol git:20260714.6307d7eA

Immutable. This exact content never changes and is served at /api/v1/blob/b344b1671d118e3f.

---
name: debug-protocol
description: 系統化除錯協定,含停損規則。在除錯卡住、同一問題修了 2 次以上還沒好、或開始想「隨便改改看會不會好」時使用。防止亂槍打鳥式修改把程式碼越改越爛。
---

# debug-protocol:系統化除錯

核心原則:**一次一個假設,一個假設一個最小改動,改完立刻驗證。** 沒有失敗重現指令之前,不准動任何程式碼。

## 步驟

### 1. 重現(沒有這步就沒有下一步)
- 找到一條指令能穩定重現失敗(測試指令、curl、script)。貼出失敗輸出。
- 無法穩定重現 → 先解決重現問題(加 log、固定 seed、記錄環境),不要修「猜的 bug」。

### 2. 建立假設日誌
在回覆中(或 scratchpad)維護一張表,之後每輪更新:

```
| # | 假設 | 驗證方式 | 結果 |
|---|------|---------|------|
| 1 | token 過期沒被 refresh | 在 refresh 處加 log 重跑 | 排除:有進 refresh |
```

### 2.5 假設從哪來(想不出假設時照此優先序)

1. **最近改動優先**:`git log -p <相關檔>`、`git diff main`——大多數新 bug 來自新改動。
2. **差異分析**:能重現與不能重現的情境差在哪(環境、輸入、版本、時序)?差異處就是嫌疑處。
3. **按症狀查常見嫌疑**:
   - 間歇性失敗 → 時序/競態、共享狀態、外部依賴逾時
   - 邊界值出錯 → off-by-one、型別轉換、空集合/None
   - 只在某環境出錯 → 設定、路徑、版本、環境變數
4. 以上都想不出 → 用二分縮小範圍(git bisect 或註解掉一半邏輯),別憑空猜。

### 3. 驗證假設(先觀察,後修改)
- 優先用「唯讀」手段驗證:讀碼、加 log、下斷點、bisect(`git bisect` 或手動二分註解)。
- 假設被證實之後才改程式碼;改動必須是針對該假設的**最小修改**。

### 4. 每輪改動後
- 重跑步驟 1 的重現指令。
- 沒修好 → 把這輪改動 **revert 乾淨**(不留半套修改疊加),更新假設日誌,回步驟 2。

## 停損規則(3-strike)

連續 3 輪修改都失敗時,**強制停手**,依序做:

1. `git checkout` / revert 回最後乾淨狀態。
2. 寫下:已排除的假設清單、目前掌握的事實、還沒看過的區域。
3. 擴大情報面(擇一):
   - 往上游讀更多程式碼(呼叫鏈、設定載入、初始化順序)
   - 用 `git log -p <file>` 查該區域最近改動
   - 開一個 subagent 平行調查另一條假設線
   - `git bisect` 找出引入問題的 commit
4. 帶著新事實重新進 plan mode 再開始。
5. 若再 3 輪仍失敗 → 停止,如實向使用者回報:事實、已排除假設、卡點、建議方向。**如實回報卡住遠優於硬掰一個「可能修好了」。**

## 修好之後(缺一不可)

1. 用一句話說出**根因**(說不出根因 = 可能只是碰巧不噴錯了,回步驟 2)。
2. 加一個會在此 bug 回歸時失敗的測試。
3. 跑 /done-check。
4. 檢查修法是不是貼補:自問「知道根因後,這是優雅解嗎?」

## 禁止事項

- 禁止一輪改多個地方然後「看哪個有效」。
- 禁止用 try/except 吞掉錯誤來「修好」。
- 禁止沒讀過相關程式碼就套 Stack Overflow / 訓練記憶裡的通用解。
- 禁止修改測試的預期值來讓測試通過(除非能證明測試本身錯,且在總結中說明)。

## Changelog

- 2026-07-14:新增步驟 2.5 假設生成優先序——原版只管流程紀律、不教怎麼想出假設(Fable 5 session 補蒸餾,使用者核准)。