--- name: code-review description: 生產級代碼審查 - 深度思考流程,扣分制評分(可為負分)。當完成任務、PR 合併前、或用戶要求嚴格審查時使用。 allowed-tools: Read, Grep, Bash --- # 代碼審查 Skill > ⛔ **原則**:不是「勾清單」,是「逐行質疑」。最嚴苛標準,分數可為負。 ## 使用時機 - 任務標記完成前 - PR 合併前 - 用戶要求 review 時 --- ## 評分標準(可為負分,嚴苛版) **預設扣分制,沒證據證明沒問題就扣分。** ### 基礎分:100 分,逐項扣分,無下限 | 類別 | 扣分項目 | 扣分 | |------|----------|------| | **基礎檢查失敗** | | | | | typecheck 失敗(每個錯誤) | -20 | | | lint 錯誤(每個錯誤) | -10 | | | lint 警告(每個警告) | -5 | | | 測試失敗(每個失敗) | -30 | | | 使用 `any`(每處) | -15 | | | 使用 `@ts-ignore`(每處) | -20 | | | 使用 `as unknown as`(每處) | -15 | | **致命缺陷** | | | | | 安全漏洞(SQL注入、XSS) | -50 | | | 硬編碼密鑰/Token | -50 | | | 資料遺失風險(事務不完整) | -40 | | | 競態條件 | -40 | | | 函數名稱與實作不符 | -30 | | **嚴重缺陷** | | | | | 未處理 Supabase/API error | -20 | | | 邊界值未處理(null/undefined) | -15 | | | 空陣列未處理 | -15 | | | 隱式假設未驗證 | -15 | | **中等缺陷** | | | | | 錯誤訊息顯示技術細節給用戶 | -10 | | | 缺少 console.error 日誌 | -10 | | | 魔術數字未抽成常數 | -5 | | | 函數超過 50 行 | -5 | | | 複雜邏輯無註解 | -5 | | **輕微缺陷** | | | | | 命名不清楚 | -3 | | | 可抽成 helper 但沒抽 | -3 | | | 未使用的 import/變數 | -2 | ### 分數等級 | 分數 | 等級 | 結論 | |------|------|------| | 90-100 | 🟢 優秀 | 可合併 | | 80-89 | 🟡 良好 | 修正後可合併 | | 60-79 | 🟠 需改進 | 必須修正 | | 0-59 | 🔴 不合格 | 重寫 | | <0 | ⛔ 災難 | 拒絕,需嚴肅檢討 | --- ## Step 0:基礎檢查(必須先做) **在任何深度審查之前,先執行:** ```bash npm run typecheck npm run lint npm run test npm run gate ``` ### 檢查項目 | 檢查 | 指令 | 標準 | 失敗扣分 | |------|------|------|----------| | TypeScript | `npm run typecheck` | 零錯誤 | -20/錯誤 | | ESLint | `npm run lint` | 零錯誤零警告 | -10/錯誤, -5/警告 | | 測試 | `npm run test` | 100% 通過 | -30/失敗 | | Gate | `npm run gate` | 通過 | -30 | ### 掃描禁用項 ```bash # 搜尋 any grep -rn ": any" --include="*.ts" --include="*.tsx" src/ # 搜尋 @ts-ignore / @ts-expect-error grep -rn "@ts-ignore\|@ts-expect-error" --include="*.ts" --include="*.tsx" src/ # 搜尋強制轉型 grep -rn "as unknown as" --include="*.ts" --include="*.tsx" src/ # 搜尋 non-null assertion (!) grep -rn "\!\." --include="*.ts" --include="*.tsx" src/ # 搜尋 console.log(生產代碼不應有) grep -rn "console.log" --include="*.ts" --include="*.tsx" src/ # 搜尋 .only(會跳過其他測試) grep -rn "\.only(" --include="*.test.ts" --include="*.spec.ts" src/ # 搜尋 TODO/FIXME(未完成的工作) grep -rn "TODO\|FIXME" --include="*.ts" --include="*.tsx" src/ ``` ### 禁用項扣分標準 | 項目 | 扣分 | |------|------| | `any` | -15/處 | | `@ts-ignore` / `@ts-expect-error` | -20/處 | | `as unknown as` | -15/處 | | `!.` non-null assertion(無註解說明) | -5/處 | | `console.log`(非 error/warn) | -5/處 | | `.only` 在測試中 | -20/處 | | `TODO` / `FIXME` 未處理 | -3/處 | **每發現一處,立即扣分。** --- ## Step 1:理解意圖 對每個函數/API,回答: | 問題 | 你的答案 | |------|----------| | 這段代碼要解決什麼問題? | | | 對應工單的哪個需求? | | | 它在系統中扮演什麼角色? | | **如果答不出來,先讀需求文件。** --- ## Step 2:追蹤資料流 ``` 輸入來源 → [這段代碼] → 輸出去向 ↓ ↓ ↓ 可能的值? 如何轉換? 誰使用? ``` 檢查: - 輸入可能是 null/undefined 嗎? - 輸入可能是空陣列嗎? - 輸入可能超出預期範圍嗎? --- ## Step 3:質疑假設 列出所有隱式假設,逐一驗證: | 假設 | 成立嗎? | 不成立會怎樣? | |------|----------|---------------| | 資料庫一定成功回應 | | | | 陣列一定有元素 | | | | 用戶一定已登入 | | | | ID 一定存在 | | | --- ## Step 4:模擬極端 ### 4.1 邊界值 | 輸入 | 預期 | 實際 | 有處理? | |------|------|------|----------| | null | | | ✅/❌ | | undefined | | | ✅/❌ | | "" | | | ✅/❌ | | [] | | | ✅/❌ | | 負數 | | | ✅/❌ | ### 4.2 併發 ``` 兩個請求同時呼叫,會發生什麼? ``` ### 4.3 中途失敗 ``` 執行到第 N 行失敗,系統狀態會壞掉嗎? ``` --- ## Step 5:名稱 vs 實作對照 拆解函數名稱,逐一驗證: | 名稱片段 | 承諾 | 實作有做到? | |----------|------|-------------| | | | ✅/❌ | | | | ✅/❌ | | | | ✅/❌ | **任何 ❌ 直接 -30 分。** --- ## Step 6:可維護性 | 問題 | 答案 | |------|------| | 六個月後看得懂嗎? | | | 魔術數字要抽常數嗎? | | | 複雜邏輯要加註解嗎? | | --- ## 審查報告格式(必須輸出) ```markdown # 代碼審查報告 ## 評分:XX/100 🟢/🟡/🟠/🔴/⛔ ## 審查檔案 - `path/to/file.ts` ## 基礎檢查 - typecheck: ✅/❌ (X 錯誤) - lint: ✅/❌ (X 錯誤, X 警告) - test: ✅/❌ (X 失敗) - any 使用: X 處 - @ts-ignore: X 處 ## 扣分明細 | 扣分 | 原因 | 位置 | |------|------|------| | -XX | [原因] | L123 | | -XX | [原因] | L456 | | **總計** | **-XXX** | | ## 問題清單 ### ⛔ 致命 1. ... ### 🔴 嚴重 1. ... ### 🟡 建議 1. ... ## 結論 [能不能合併,為什麼] ``` --- ## 執行原則 - ✅ **必須跑完全部流程**,即使基礎檢查失敗 - ✅ **必須列出所有問題**,不可遺漏 - ✅ **必須給出總分**,讓用戶知道這次實作幾分 - ✅ **問題列在對話框**,不要亂改或新增檔案 ## 禁止事項 - ❌ 沒跑基礎檢查就開始審查 - ❌ 發現問題但略過不報告 - ❌ 跳過任何 Step - ❌ 不給分數 - ❌ 分數虛高(沒證據就給高分) - ❌ 用「應該沒問題」當結論 - ❌ 只報告部分問題