# 06 — 規則檔瘦身（每月一次）

## 它防的是什麼

規則檔會長胖，而且**長胖的過程感覺是對的** —— 每一行加進去的時候都有充分理由。

但：

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

而且胖到一定程度之後會發生一件更糟的事：

> **一條規則躺在 700 行裡，注意力份額趨近於零。**
> **自動載入 ≠ 自動遵守。**

那個專案的實測：規則正文從 555 行降到 341 行（全檔 60% → 46%），
**三天後又長回去了** —— 所以現在上限由守衛檢查。

---

## 直接複製

```
幫我對規則檔做一次瘦身。逐段處理，不要一次改完再給我看。

對每一段問這五題，第一個「是」就決定它的去處：

1. 這是敘事嗎（那天發生什麼、當初為什麼）？      → 搬去事故記錄／日誌
2. 這是進度或狀態嗎（做到哪了、還缺什麼）？      → 搬去排程表
3. 這是操作步驟嗎（點哪顆按鈕、怎麼跑）？        → 搬去操作手冊
4. 機器接得住嗎（指令樣式／檔案事件／可以數的）？→ 變成 hook 或守衛
5. 以上皆非（只能靠判斷）→ 留下，但壓縮成「判準句 ＋ 一行指標」

每一段給我三個東西：
  · 現在幾行 → 壓縮後幾行
  · 搬去哪裡（或「留下，理由是機器接不住」）
  · 壓縮後的完整文字

🚨 兩個限制：
  · 不要刪掉任何規則，只搬家或壓縮。刪除是我的決定，不是你的。
  · 被搬走的內容要**真的寫進新的家**，不是消失。
    搬到一半的規則比留在原地更糟。

最後告訴我：總行數變化，以及現在最肥的三節是哪幾節。
```

---

## 壓縮的標準形狀

**壓縮前**（40 行）：

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

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

**壓縮後**（6 行）：

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

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

四個差別：

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

---

## 設一個上限，並且讓機器檢查它

否則它一定會長回去（實測會）。

```python
# 在你的 spec_check.py 裡加一個方向
LIMIT = 500

def check_rules_file_size():
    lines = open("CLAUDE.md", encoding="utf-8").read().splitlines()
    n = len(lines)
    if n > LIMIT:
        fail(f"CLAUDE.md {n} 行，超過上限 {LIMIT}")
    # 順便印出最肥的三節 —— 下次瘦身直接從這裡開始
    sections = fattest_sections(lines, top=3)
    return f"CLAUDE.md {n} 行／上限 {LIMIT}（最肥：{sections}）"
```

輸出長這樣：

```
CLAUDE.md 403 行／上限 500（最肥：架構 55・Commit 前自查 39・專案概觀 31）
```

**「最肥的三節是哪幾節」這個資訊比「超過上限了」有用得多** ——
它直接告訴你下次從哪裡開始。

---

## 什麼時候跑

```
· 每月一次（設一個提醒）
· 守衛報「接近上限」的時候
· 每次你發現自己在規則檔裡找東西找了超過三十秒
```

最後一條是最好的訊號 —— **找不到東西代表結構壞了，不是你不熟。**
