# 02 — 規則層：`CLAUDE.md` 怎麼寫

上一層：[01 全貌](01-overview.md)　下一層：[03 記憶層](03-memory.md)　模板：[templates/CLAUDE.md](templates/CLAUDE.md)

---

## 這個檔的唯一特性：它每次對話都全文載入

所有的寫法規矩都是從這一條推導出來的：

> **多一行的成本要乘以每一次對話。**
> **⇒ 一條規則的正文長度是它的成本，不是它的重要程度。**

這句話推翻了一個很強的直覺。直覺會說「這條很重要，所以要寫詳細一點」。
但實際上「重要」和「該寫多長」是兩件獨立的事 —— 一條**極重要**的規則如果能變成 hook，
它在正文裡的正確長度是**零行**。

---

## 判準：寫任何東西進來之前，先問「它有沒有別的家」

四層由上往下問，**接不住才往下掉一層**：

```
指令樣式／檔案事件攔得住的      →  hook 腳本
做完了也不會知道出錯的          →  守衛腳本
事故的來龍去脈與教訓            →  事故記錄
怎麼做、點哪顆按鈕              →  操作手冊
東西在哪、哪份文件有權威        →  架構索引
系統現在長什麼樣                →  規格
還要花多少時間                  →  排程表
                                    ↓
      以上全部接不住，才留在規則正文裡
```

**留在規則檔裡的，只有「機器接不住、而且每次動手都要用到」的判斷。**

---

## 什麼該進、什麼不該進

### ✅ 該進的三類

| 類別 | 長什麼樣 | 例子 |
|---|---|---|
| **判準** | 一個可執行的問句，答案決定下一步 | 「這張表現在有沒有真實的列？**用工具去問，不要用印象問**」 |
| **硬規則** | 違反了會出事，而機器擋不住 | 「綠燈必須附『我驗到了幾個』。驗 0 個然後 PASS ＝一律 FAIL」 |
| **索引** | 指向權威檔的一行 | 「hook 清單與加規則的規矩＝`tools/hooks/README.md`（本檔不重抄）」 |

### ❌ 不該進的四類

| 類別 | 為什麼不該進 | 它的家 |
|---|---|---|
| **敘事** | 「那天發生了什麼」讀一次就夠，但你每次對話都在付它的錢 | 事故記錄／日誌 |
| **進度** | 三天後就過期，而且過期的進度會**雙向有害**（見下） | 排程表 |
| **操作步驟** | 「點哪顆按鈕」是消耗品，做完就沒用了 | 操作手冊 |
| **同一張表的第二份** | 兩份一定會漂移 | 留一份，另一邊寫索引 |

> 🚨 **過時的狀態行是雙向有害的**：
> 把做完的寫成待辦（排程時整包重做）／把已經安全的寫成不安全（浪費上線那天的時間）。
> 看到就當場改 —— 這不是「等有空整理」的事。

---

## 怎麼寫一條規則：判準句放最前面

**壞的寫法**（AI 讀到這一段，不知道自己該做什麼）：

```markdown
## 關於資料庫 schema 的變更

早期專案還沒有真實使用者的時候，我們直接改 schema 比較快，
不需要寫 migration，也不需要考慮向後相容。這樣可以省下很多時間，
因為寫一支 migration 大概要 20 分鐘，而且還要測試。後來上架之後
情況就不一樣了...
```

**好的寫法**（判準句在第一行，接著是可執行的動作）：

```markdown
## ⏳「可以直接改 schema」是**有期限**的規則

**判斷句：問「這張表現在有沒有真實的列」—— 用 `scripts/db_peek.py prod <表名>` 問，不要用印象問。**
沒有真實列 ⇒ 舊規則仍成立：schema／default 直接改，不寫 migration。
有真實列 ⇒ 五條義務全部生效，全文＝`openspec/core/architecture.md §10.4`。
🚨 觸發點是**第一個真實帳號註冊的那一刻**，而且**可逆**
⇒ 這是**每次動 schema 前都要重問一次**的狀態查詢，不是記得一次就好的事實：
   **你記得的是「上次問的答案」，不是現在的狀態。**
```

差別在四個地方：

1. **第一行就是可執行的判斷句**，不是背景。
2. **指名了工具**（`db_peek.py`），不是「去查一下」。
3. **全文在別的地方**，正文只留判準 ⇒ 成本從 40 行變成 6 行。
4. **最後一句解釋了「為什麼這條容易被違反」** —— 這句話比規則本身更防得住復發。

---

## 瘦身：一個真實的數字

那個專案的規則檔經歷過兩次瘦身：

| 時間點 | 規則正文行數 | 佔全檔比例 |
|---|---|---|
| 瘦身前 | 555 行 | 60% |
| 第一次瘦身後 | 341 行 | 46% |
| 三天後 | **又長回來** | — |

**那 214 行不是被刪掉，是被推去 hook 和守衛了。**

而「三天後又長回來」這件事本身就是教訓 —— 所以現在規則檔的**第一段**就寫著體例，
並且明確記著「這條已經被違反兩次」。把違反紀錄寫在規則旁邊，比把規則寫得更詳細有效。

---

## 🚨 最重要的一課：自動載入 ≠ 自動遵守

有一條規則（「這張表一列只能寫一行」）白紙黑字寫在規則檔裡，**還是連續發作三次**。

三次都不是不知道規則。結構原因是：

> **一條規則躺在 700 行裡，注意力份額趨近於零。**

發作三次之後的正確反應**不是**「把規則寫得更醒目」（加粗、加 🚨、搬到最前面 —— 這些都試過，都沒用），
而是**加一支守衛去數**。加了之後，同一型錯誤再也沒發生過。

**⇒ 判準：同一條規則被違反第二次，就不要再改規則的寫法了，去問「機器怎麼接住它」。**

---

## 規則檔的建議結構

```markdown
# CLAUDE.md

> 本檔的體例：判準／規則／索引，不放敘事。
> 它每個對話全文載入一次 ⇒ 多一行的成本要乘以每一次對話。
> 寫任何東西進來之前先問「它有沒有別的家」（四層分流表）。

## 專案概觀
  三到五行。技術棧、進入點、「開工前先讀哪兩份」。

## 🧭 寫任何一句話之前，先問「它在回答哪個問題」
  一張分流表。這是整份規則檔裡最常被用到的一段。

## Source of Truth
  哪一份是權威、衝突時以誰為準。
  🚨 建議：**規格與 code 衝突 → 以 code 為準**，然後回頭更新規格。
     權威是跑得起來的東西，不是散文。

## 🔁 實作前強制流程（HARD RULE）
  查索引 → grep 三個同義詞 → **在回覆開頭印出查詢結果**。
  重點是把「有沒有查」從不可觀測的內部行為，變成使用者一眼能驗收的產出。

## 🟢 綠燈的可信度（HARD RULE）
  十條判準。這一節是整份檔案價值密度最高的地方（見 05）。

## 架構
  只留「會影響判斷的」那兩三條，其餘指向架構索引。

## Commands
  每天會打的那幾行指令，含它們的坑。

## 🔒 Commit 前自查（HARD RULE）
  一張表：「改到什麼 → 跑什麼 → 它擋的那種安靜失敗」。

## Conventions
  編碼、命名、commit 訊息、「不新開規劃 .md」。
```

**每一節的標題自己就要是判準**。看到 `## 🟢 綠燈的可信度` 就知道這一節在管什麼；
看到 `## 關於測試的一些想法` 則什麼都不知道。

---

## 一個容易忽略的配套：規則檔要記錄自己被違反的歷史

在每條高風險規則後面加一行：

```markdown
⚠️ 這條已經被違反兩次（某月某日瘦到 734 行，三天後又長回 786 行）
```

```markdown
（發作三次才補守衛：`spec_check` 檢查 ⑦）
```

這一行的作用不是自責，是**告訴讀者（包含 AI）這條規則的實際危險程度**。
一條「從來沒被違反過」的規則和一條「發作三次」的規則，該得到的注意力完全不同，
而這個資訊只能由歷史提供。

---

## 接下來

- 跨對話、跨專案的記憶怎麼分類 → [03-memory.md](03-memory.md)
- 可直接複製的規則檔骨架 → [templates/CLAUDE.md](templates/CLAUDE.md)
- 定期瘦身的 prompt → [prompts/06-rules-file-diet.md](prompts/06-rules-file-diet.md)
