與使用者溝通、以及審查報告,都使用繁體中文。
針對 HEAD 與使用者提供的固定點之間的 diff,做雙軸審查:
- Standards:程式碼是否遵守這個 repo 文件化的寫作規範?
- Spec:程式碼是否忠實實作了原始的 issue/spec?
兩個軸都以平行子 agent執行,讓它們不會汙染彼此的情境,然後由本 skill 彙整它們的發現。
Issue tracker 應該已經提供給你了。如果沒有,告訴使用者先執行 /setup-matt-pocock-skills。
流程
1. 確定固定點
使用者說的就是固定點(commit SHA、分支名稱、tag、main、HEAD~5 等)。如果他沒有指定,就問。
一次記下 diff 指令:git diff <fixed-point>...HEAD(三個點,所以是和 merge-base 比較)。同時用 git log <fixed-point>..HEAD --oneline 記下 commit 清單。
繼續之前,確認固定點能被解析(git rev-parse <fixed-point>)而且 diff 不是空的。錯誤的參照或空的 diff 應該在這裡就失敗,而不是在兩個平行子 agent 裡失敗。
2. 找出 spec 來源
依以下順序尋找原始 spec:
- commit 訊息中的 issue 參照(
#123、Closes #45、GitLab 的!67等),透過 tracker 文件中的流程取得。 - 使用者以參數傳入的路徑。
docs/、specs/或.scratch/底下與分支名稱或功能相符的 spec 檔。- 如果什麼都找不到,問使用者 spec 在哪裡。如果他說沒有 spec,Spec 子 agent 就跳過,並回報「沒有可用的 spec」。
3. 找出規範來源
搜尋 repo 中所有記載程式碼該怎麼寫的檔案。如果 CODING_STANDARDS.md 或 CONTRIBUTING.md 存在,一定要列入。Python 專案也要看 pyproject.toml 中 linter/formatter(ruff、black、mypy 等)的設定,但工具已經強制執行的規則不必再審。
在 repo 文件記載的內容之外,Standards 軸永遠帶著下方的壞味道基準:一組固定的 Fowler 程式碼壞味道(《重構》第 3 章),即使 repo 什麼都沒記載也適用。有兩條規則約束它:
- repo 優先。 repo 文件化的規範永遠勝出;當它認可某個基準會標記的東西時,就不要標記該壞味道。
- 永遠是判斷題。 每個壞味道都是一個加了標籤的經驗法則(「可能有 Feature Envy」),從來不是硬性違規。和這裡的任何規範一樣,工具已經強制執行的就跳過。
每個壞味道的寫法是「它是什麼 → 怎麼修」;拿它對照 diff:
- 神秘命名(Mysterious Name):函式、變數或型別的名稱看不出它做什麼或裝什麼。→ 重新命名;如果想不出誠實的名字,代表設計本身就模糊。
- 重複程式碼(Duplicated Code):同樣的邏輯形狀出現在這次變更的不只一個區塊或檔案中。→ 抽出共同的形狀,兩邊都呼叫它。
- 依戀情結(Feature Envy):一個方法存取別的物件的資料多於自己的。→ 把方法搬到它依戀的資料那邊。
- 資料泥團(Data Clumps):同樣幾個欄位或參數總是一起出現(一個想要誕生的型別)。→ 把它們包成一個型別,傳遞那個型別。
- 基本型別偏執(Primitive Obsession):用一個基本型別或字串代表一個值得擁有自己型別的領域概念(例如用
str表示料號、用float表示金額與幣別)。→ 給這個概念一個自己的小型別(例如dataclass)。 - 重複的條件分支(Repeated Switches):同一個型別上同樣的
match/if串在這次變更中反覆出現。→ 改用多型,或用一個兩處共用的對照表。 - 散彈式修改(Shotgun Surgery):一個邏輯上的改變,迫使 diff 中許多檔案出現零散的修改。→ 把會一起改變的東西集中到一個模組。
- 發散式變化(Divergent Change):一個檔案或模組因為幾個不相關的理由被修改。→ 拆開,讓每個模組只因一個理由改變。
- 臆測的通用性(Speculative Generality):為 spec 沒有的需求加入的抽象、參數或掛鉤。→ 刪掉;內聯回去,等真正的需求出現再說。
- 訊息鏈(Message Chains):呼叫端不該依賴的長串
a.b().c().d()導航。→ 把這段走訪藏在第一個物件的一個方法後面。 - 中間人(Middle Man):一個主要只是往下委派的類別或函式。→ 拿掉它,直接呼叫真正的目標。
- 被拒絕的遺贈(Refused Bequest):一個子類別或實作者忽略或覆寫了它繼承的大部分東西。→ 放棄繼承,改用組合。
4. 平行派出兩個子 agent
同時發出兩個子 agent 呼叫(在前景執行),並彙整它們回傳的報告。
Standards 子 agent 的提示應包含:
- 完整的 diff 指令與 commit 清單。
- 你在步驟 3 找到的規範來源檔案清單,加上步驟 3 的壞味道基準完整貼上(子 agent 沒有其他途徑取得它)。
- 任務說明:「以繁體中文回報,並在相關處標明檔案/區塊:(a) diff 違反文件化規範的每一處:引用該規範(檔案+規則);以及 (b) 你發現的任何基準壞味道:說出名稱並引用該區塊。區分硬性違規與判斷題:違反文件化規範可以是硬性的,但基準壞味道永遠是判斷題,而且 repo 文件化的規範優先於基準。工具已經強制執行的就跳過。400 字以內。」
Spec 子 agent 的提示應包含:
- diff 指令與 commit 清單。
- spec 的路徑或已取得的內容。
- 任務說明:「以繁體中文回報:(a) spec 要求了、但缺少或只做了一部分的需求;(b) diff 中沒有被要求的行為(範圍蔓延);(c) 看起來已實作、但實作方式看起來錯誤的需求。每一項發現都引用 spec 的對應文字。400 字以內。」
如果沒有 spec,跳過 Spec 子 agent,並在最終報告中註明。
5. 彙整
把兩份報告分別放在 ## Standards 與 ## Spec 標題下,原文照登或稍作整理。不要合併或重新排序發現,因為兩個軸是刻意分開的(見「為什麼要兩個軸」)。
最後用一行總結:每個軸的發現總數,以及每個軸內最嚴重的問題(如果有)。不要跨軸選出單一贏家:那正是分開兩軸要防止的重新排序。
為什麼要兩個軸
一個變更可能通過一個軸、卻沒通過另一個:
- 遵守所有規範、但實作了錯的東西 → Standards 通過,Spec 失敗。
- 完全做到 issue 要求的事、但破壞了專案慣例 → Spec 通過,Standards 失敗。
分開回報,能避免一個軸掩蓋另一個。