審查 AI 廢料
AI 廢料不是風格,而是未經驗證的聲明和沒有存在理由的程式碼。下列每一項發現都必須有事實佐證:一行程式碼、命令輸出、或缺少使用者。不包含品味上的意見或 linter 能抓到的問題。
原則。
- 刪除優於補充。 無效的選項應直接刪除,而非加文件說明;行銷用語應替換為事實或直接移除。
- 聲明須經程式碼驗證,而非憑記憶。 在斷定 README 中一行文字為真或假之前,實際打開它提到的檔案。
- 沒有證據的發現不算發現。 如果無法提供
file:line或命令輸出,就不要寫出來。 - 修正僅在對方要求時進行。預設審查結果為列表形式。
1. 工作流程
- 確定範圍:diff(
git diff main...HEAD)、特定檔案或發布前的整個儲存庫。 - 執行第 3 節的搜尋——它提供候選項目,而非最終發現。
- 對每個候選項目,透過閱讀程式碼來驗證,並排除誤報。
- 對搜尋無法捕捉的問題,執行第 2 節的檢查清單:README 與程式碼比對、UI 狀態、抽象層。
- 如果可能啟動應用程式,瀏覽各頁面:樣板畫面與未樣式化的元件會立即顯現。
- 以第 4 節的格式輸出報告。
2. 檢查清單
2.1. 生成器與樣板殘留
- 生成器的起始頁面與區塊:"Get started by editing"、框架與工具的文件連結、
utm_source=…-project、"Give us a star"、工具的雲端服務區塊。 - 樣板檔案:
example.spec.ts、僅檢查樣板標題的測試、public/中的 SVG 與圖片、生成器的 README。 - 空白佔位符:已有檔案的資料夾中的
.gitkeep、空的index.ts、沒有程式碼的資料夾層。
2.2. 無效與未完成的內容
- 設定值或
switch分支中拋出 "not implemented" / "pending"。 - 只有一個值的列舉,看起來像擴充點(
type: "graphql" | "msw",但msw未實作)。 - 被註解掉的程式碼、沒有理由和連結的
TODO、未使用的匯出、package.json中從未 import 的依賴。 package.json中無法執行的腳本(參照已刪除的檔案或不存在的目標)。
2.3. 文件與程式碼不符
驗證 README、ADR、註解和提交描述中的每一項聲明:
- 名稱與路徑: 提到的檔案、命令、環境變數必須存在(文字中寫
next.config.ts但儲存庫中是next.config.js——這是發現)。 - 行為: "請求直接傳送"、"Token 無法被 JS 存取"、"防止 open redirect"——找到實作這些行為的程式碼,並檢查邊界情況。
- 版本與數字: 函式庫版本、Token 生命週期、測試覆蓋率。
- 以現在式描述未來: 規劃中的功能被描述為已完成。
- Markdown 中的連結與錨點必須指向正確位置(修改標題時錨點會失效)。
2.4. 語氣
- 評價性詞語而非事實:premium、state-of-the-art、cutting-edge、blazing/lightning-fast、seamless、robust、powerful、modern、production-ready、enterprise-grade、「不僅僅是」、「高品質」、「先進」、「強大」。
- 文件標題、UI、日誌和提交訊息中的表情符號。
- "Designed with ❤️"、"Carefully crafted"、為徽章而徽章。
- 複述式註解(
// 獲取使用者放在getUser()上方)、歷史註解(// 已修正、// 已更新為 X)、全大寫註解、無說明的 "IMPORTANT" 標記。 - 標題與註解風格如 "🚀 產品路線圖" 和 "(Premium Aesthetic)"。
替代方案——事實:做什麼、為什麼這樣做、有什麼限制。
2.5. 多餘抽象層
- 只有一種實作且測試中沒有模擬物(fake)的介面或工廠。
- 沒有使用者或未記錄原因(ADR、READOME 章節)的層、區域、monorepo 套件、狀態管理器、Storybook。
- 僅重新命名的包裝(
useAuthApi = () => useStrictContext(Ctx)不含邏輯尚可接受;但包裝之上的包裝則不行)。 - 「為了將來」:從未傳入的參數、只有一個值的設定選項。
2.6. 錯誤與非同步
- 根據錯誤訊息內容來判斷錯誤類型(
message === "unauthorized"、includes("invalid password"))——沒有原因註解和測試。 - 僅檢查錯誤陣列的第一個元素(
errors[0])。 throw { status, ... }——使用物件而非Error。- 空的
catch、回傳空資料的catch、.catch(() => {})。 - 共用的 in-flight promise,其結果未被等待者讀取(refresh token 時「等待後重試」但未檢查是否成功)。
- 直接將伺服器的
error.message顯示給使用者。 - 缺少載入狀態、錯誤狀態、空列表狀態。
2.7. 安全與隱私
- 日誌中的個人資料:email、電話、姓名;Token;請求主體。
- 儲存庫或 Git 歷史中的機密(
git log -p)、索引中的.env、帶有NEXT_PUBLIC_前綴的機密。 - 根據參數進行重新導向(
callbackUrl、next、returnTo)未經檢查,或僅檢查startsWith("/")/!startsWith("//")——這會漏過/\.evil.com和控制字元。 localStorage/sessionStorage中的 Token;URL 中的 Token 在讀取後未從網址列移除。dangerouslySetInnerHTML未使用消毒器(sanitizer)。
2.8. UI
- 主題中不存在的類別:複製自 shadcn/ui 的 Token(
bg-card、text-muted-foreground、bg-primary)用在沒有這些 Token 的專案中——元件會無聲無息地失去樣式。 - 在已有 Token 的情況下使用原始 HEX 和任意數值。
onChange中設定的「欄位已填寫」狀態:會被自動填入和reset()破壞。- 可變列表中的
key={index};表單中沒有type的按鈕;沒有aria-label的圖示按鈕。 - 來自設計稿的 SVG,其濾鏡(陰影、發光)被
viewBox裁剪——Logo 周圍出現可見矩形。
2.9. 測試
- 檢查模擬資料而非行為的測試;大型元件的快照測試。
- 針對共用或正式後端的 e2e 測試,修改了資料。
- 因為 jsdom 不套用 CSS 而通過的測試(元素被類別「隱藏」,但測試仍找到它)以及過寬的選擇器(
/password/i同時匹配到「顯示密碼」)。
2.10. Git
- 一個提交中包含不相關的變更;"fix stuff" 提交。
- 索引中的生成檔案和建置產物(故意提交的生成的 API 客戶端除外)。
- 提交訊息描述的內容與 diff 不符。
3. 搜尋候選項目
這些命令提供候選項目。每個匹配都須經由閱讀程式碼驗證。
# 生成器樣板與行銷
rg -n -i "utm_source|get started by editing|give us a star|nx cloud|welcome to|carefully crafted|designed with" \
--glob '!**/node_modules/**' --glob '!*.lock' --glob '!pnpm-lock.yaml'
rg -n -i "premium|state-of-the-art|cutting-edge|blazing|lightning|seamless|robust|enterprise-grade|production-ready|премиальн|современн|мощн" \
--glob '!**/node_modules/**'
# 程式碼、UI 與文件中的表情符號
rg -n --pcre2 '[\x{1F300}-\x{1FAFF}\x{2600}-\x{27BF}]' --glob '!**/node_modules/**' --glob '!*.lock'
# 未完成的內容
rg -n -i "not implemented|pending implementation|todo|fixme|hack" --glob '!**/node_modules/**'
# 脆弱的錯誤處理
rg -n "errors\?\.\[0\]|errors\[0\]|message ===|message\.includes|\.includes\(['\"][a-z ]+['\"]\)" src app
rg -n "throw \{" src app
rg -n "catch \{\s*\}|catch \(\w*\) \{\s*\}|\.catch\(\(\) => \{\s*\}\)" src app
# 含有個人資料的日誌
rg -n "(logger|console)\.\w+\(.*(email|phone|password|token)" src app
# 重新導向與 Token
rg -n "callbackUrl|returnTo|redirectTo|searchParams.get\(['\"]next" src app
rg -n "localStorage|sessionStorage" src app
# 沒有 Token 的 shadcn 類別:找出類別並與 @theme / tailwind 設定比對
rg -n -o "\b(bg|text|border)-(card|muted|popover|accent|primary|secondary|destructive)(-foreground)?\b" src app | sort -u
# 未使用的依賴與匯出(如果已安裝 knip)
pnpm dlx knip
# Git 歷史中的機密
git log -p --all | rg -n -i "(api[_-]?key|secret|password|token)\s*[:=]\s*['\"][A-Za-z0-9_\-]{16,}"
git ls-files | rg -n "(^|/)\.env($|\.)" | rg -v "\.env\.example$"
4. 報告格式
發現按重要性遞減排序:安全與隱私 → 文件中的錯誤聲明 → 錯誤處理的缺陷 → 無效與未完成 → 樣板 → 語氣。
<file>:<line> — <類別>
問題:<一句話說明:什麼問題,附上事實>
重要性:<對使用者、審查者或維護的後果>
修正:<具體建議;通常是「刪除」或「替換為事實:…」>
結尾處列出已檢查且無發現的項目,以及未檢查的項目(例如應用程式未啟動)。如果完全沒有發現,應如實說明,不要勉強列出意見。