晚上十一點,一個退款 PR 已經改到第六版。
第一輪,AI 找到重複退款的風險。工程師補了冪等處理。第二輪,它要求補上逾時測試。第三輪開始討論函式命名;第四輪又建議拆出一層 service。每次都有理由,每次也都能產出新的 commit。到了第六輪,原本要修的退款問題已經解決,大家卻說不清楚還差什麼才能合併。
這是虛構的退款案例。問題在於,當寫程式與提意見都變便宜,誰負責決定一輪審查已經足夠?
我的判斷是,AI review 要進入日常開發,必須同時交付兩件事:可追查的問題證據,以及能結束本次審查的條件。只要求「再仔細看一次」,很容易得到更多意見,未必更接近可以發布的版本。
Anthropic 遇到的麻煩,是審查不肯結束
2026 年 10 月 15 日,Addy Osmani、Morgan Westlee Lunt 與 Qing Wang 在 Claude Code 團隊的審查實務中,描述過一個整晚跑了超過五十輪審查與修正的 PR。他們後來限制輪數、縮小重審範圍,並避免重複回報已提出的問題。這是團隊自述,不能拿來當所有程式庫的成效保證。
這篇文章值得借鏡的,是把「審查本身也會製造工作」攤開來看。它也保留一條責任界線:需要人的批准,不能由 agent 的批准代替。內部允許部分低風險變更走較輕的流程,不代表一般團隊安裝 reviewer 就能照做。
還有一個容易讀錯的地方。公開 Code Review 文件在本文查核時說明,託管 review 讀取 diff 與周邊程式,不會替你建置或執行程式碼。因而一則「看起來已修好」的留言,無法取代該 commit 的測試紀錄。
Addy 後來在 X 的長文再次整理這套流程。官方產品文件重新查核於 2026 年 10 月 27 日;以下退款案例與規則是工程建議,沒有在真實退款服務上實測。
一則 finding 要能讓另一個人重走一次
假設退款服務原本先查資料庫,確認沒有退款紀錄,再呼叫金流。兩個相同請求同時進來,都可能在紀錄寫入前通過查詢。Reviewer 說「這裡可能有 race condition」還不夠,修正者需要知道它指的是哪個交錯順序。
一則值得阻擋合併的回報,至少應留下這些資訊:
- 針對哪個 commit、哪段路徑與程式位置。
- 什麼輸入、狀態或執行順序會觸發。
- 原本應維持的行為,以及目前會怎樣違反。
- 是靜態推論、已執行的重現,還是缺資料而待確認。
- 哪一項測試或觀測可以支持修正完成。
例如,這個案例的回報可以寫成:兩個請求都讀到「尚無退款」,接著各自送出一次金流呼叫;若供應商端沒有共同的冪等鍵,可能形成兩次退款。驗證應刻意讓兩個請求停在查詢之後,再一起放行,檢查外部呼叫與退款義務是否重複。
這段描述仍是測試設計,不能寫成「已重現」。如果金流其實已有穩定冪等鍵,原回報可能只指出多餘呼叫,沒有證明重複退款。問題的嚴重度要跟著證據調整。
反過來說,「我比較喜歡另一種 repository pattern」沒有指出行為風險,就適合留作設計討論。把它混進退款阻擋清單,會讓修正者誤以為每一項偏好都是驗收條件。
REVIEW.md 要寫得出退款怎樣才算錯
同一種併發問題反覆出現,下一步可以把判準留下來。原文區分專案脈絡的 CLAUDE.md 與區域審查規則的 REVIEW.md。對退款模組,光寫「注意一致性與資安」沒有足夠資訊:reviewer 仍得猜測哪些變化會破壞業務。
我會把一條規則寫成下面這樣。這是供團隊調整的審查文字,不是會自動執行的測試:
退款義務的識別值,必須在逾時與重試之間保持不變。
若變更會為同一筆退款義務產生新的供應商冪等鍵,
請指出鍵的產生位置、重試呼叫路徑,以及可能重複退款的順序。
若無法確認供應商的冪等範圍與有效期限,列為待確認,勿推定安全。
單純更換函式名稱,不列為此規則的阻擋理由。
它比「檢查冪等」多做了兩件事:指定要保護的業務事實,也指定什麼證據足以支持 finding。接著將同一條規則轉成測試案例:第一次請求逾時、重試再送出,擷取兩次外部請求的鍵,確認它們對應同一義務。供應商是否接受這個鍵、保留多久,則需要另外查契約或在允許的測試環境驗證。
規則檔還有自己的信任來源。公開 Code Review 文件說明,託管 reviewer 使用 base 或 default branch 的 REVIEW.md,不採用 PR 自己改過的版本。因此,退款修正 PR 同時把「必須保留冪等鍵」刪掉,不應讓這輪審查跟著失去判準。若是自建 skill 或 subagent,應明確記錄讀了哪個 revision 的規則,不能只因檔名相同就假設有這層保障。
規則、測試與批准仍有各自的工作。規則讓 reviewer 知道要找什麼;測試提供某條執行路徑的證據;誰能接受殘餘風險、誰能合併,交由 repository 的權限及人審流程處理。把三件事都放進一段 prompt,失敗時很難知道哪一道實際擋住了問題。
關閉的是一個問題,不是一串留言
假設工程師把金流冪等鍵固定為同一筆退款義務的識別值,並補上併發測試。下一輪 reviewer 應該回答:這個修正是否涵蓋原本的交錯順序?是否引入新的退款狀態錯誤?
它不應因為開始掃描整個付款模組,就把三年前的命名問題也算成本次退款修正未完成。
但「舊問題」也不能一律丟進 backlog。若這次改動使原本不會走到的分支變得可達,或者舊缺陷會直接破壞這次交付,仍然要處理。判斷依據是與本次變更的因果關係,不能只看 git blame 的日期。
我建議保留穩定的 finding ID,並讓每個 ID 最後落在一個清楚決定:
- 已修正:連到修正 commit 與相關驗證。
- 不成立:列出反證,例如相同退款義務確實共用供應商冪等鍵。
- 接受風險:由有權決策的人說明影響、期限與後續責任。
- 移至獨立工作:說明為何不影響目前交付,附追蹤位置。
無法取得必要證據,應保持待確認,不能為了清空留言而當成不成立。 同樣地,agent 把 thread 按成 resolved,也不等於負責人接受了風險。
前一篇用可驗證實驗推進 AI 工作談的是怎麼判斷任務有沒有往前走。Review 多了一個要求:同一項判斷要能跨 commit 延續,否則每輪都會從零開始爭論。
輪數上限,是交棒給人
對這個退款 PR,可以採用以下具名停止規則,作為團隊討論的起點:
第一次做完整變更範圍檢查。修正後,依 finding ID 檢查修正及受影響的呼叫路徑。若連續三輪仍未收斂,停止自動改寫,交給人重新判斷範圍、設計或證據是否有問題。
三輪是這份建議的初始設定,不是安全標準。到上限仍有未解的退款風險,PR 依然不能合併。停止的是自動修修補補,不是停止負責。
縮小重審範圍也有代價。只看最新幾行 diff,可能漏掉前兩輪共同造成的行為變化。因此「依增量重審」至少需要保留原始目的、尚未結案的 findings,以及這次修改觸及的依賴。遇到共享介面、交易邊界、權限或發布流程改動,應重新擴大審查。
這時候,工程師真正要做的決定通常很具體:這個 PR 是否同時塞了冪等修正與付款模組重構?若是,拆開可能比再加一位 reviewer 更有效。先交付可驗證的退款修正,再用另一個 PR 討論重構,不必讓兩種風險綁在一起。
CI 的綠燈,也必須對到正確版本
另一個陷阱出現在第七版。人看過第六版,agent 推了第七版;畫面上仍留著批准,測試結果卻來自更早的 SHA。這三個訊號各自成立,合起來仍不足以說第七版可以發布。
實作時,應讓審查證據記錄被檢查的 head,並依 repository 的規則重新確認後續變更。對金流或授權路徑,我會把最後的差異與必要測試交回對應負責人;不能用「只多改一點」自行延伸批准範圍。
多人開發還有另一層版本問題:兩個 PR 各自通過,不代表合在一起仍通過。GitHub merge queue會在最新目標分支及排在前面的變更組合上執行必要檢查。使用 GitHub Actions 時,必要工作流須處理 merge_group 事件,不能只測 pull_request。
小團隊未必需要立即導入 queue,也要確認測的是準備合併的內容。這是整合驗證的問題,多跑幾輪文字審查補不了它。
退款路徑只改三行,也值得人看
原文的較輕審批路徑有可信作者限制,敏感路徑還有額外規則。它不是看 diff 短就一律免審。把這個判斷放回退款 PR,三行程式若改了金流冪等鍵,造成的結果可能比三百行說明文字更難補救。
我會讓退款義務、授權判斷與 migration 這幾類變更保留負責人的審批。Reviewer 的工作是整理變更觸及的行為與未決問題,例如:新鍵是否跨重試穩定、舊訂單是否能由新版本繼續處理,以及回滾後誰來對帳。人接手時有這些材料,才是在做決定,不是替 AI 留言按確認。
也要防止 PR 的描述替自己降級。標題寫「整理退款 helper」,實際 diff 卻把鍵從退款義務 ID 改成每次呼叫的亂數,風險應由變更內容決定。若分類器與 code owner 對風險有不同意見,就留給指定負責人處理,不讓 author agent 挑一個方便合併的標籤。
這種安排增加等待時間,適合漏錯後難以撤銷的路徑。若只是說明文字與已隔離的內部功能,可以先觀察人工時間與漏錯成本,再討論是否降低審批負擔。調整規則是獨立決策,不能隨某個急著上線的 PR 一起悄悄放寬。
評估 reviewer,不能只數它抓到幾個問題
回到晚上十一點的退款 PR。如果 AI 留了二十則意見,工程師花兩小時全部照改,這算成功嗎?
只有「意見被採納」仍不夠。有些修改確實防止重複退款;有些只是作者懶得辯論。還有些修改會把原本正確的邊界條件弄壞。把採納率當準確率,會獎勵一個說服力強、卻不一定正確的 reviewer。
比較可行的起點,是挑幾個團隊已理解的案例:曾發生的缺陷、已知正確的變更,以及容易誤判但行為刻意如此的程式。記錄 reviewer 是否指出可驗證的原因,是否誤報,修正需要多少輪,以及人實際花在哪些判斷上。
例如保留一對案例:A 版在每次重試重新產生冪等鍵,B 版沿用退款義務的穩定鍵。兩版都讓網路呼叫看起來執行了兩次,reviewer 卻應分辨哪個可能造成重複退款,哪個需要先核對供應商去重契約。若它把兩版都判成同一種嚴重缺陷,這次提示詞調整就還沒學會那條邊界。
這份小樣本能幫助回答一個具體問題:某項新提示詞雖然多抓到缺陷,是否也讓正確的退款流程更常被要求重寫?提示詞、模型或工具改版後,使用同一批案例比較,才有機會看出退步。
發布後仍要看回滾與事故。若 review 時間縮短,事後補救時間卻變長,就沒有省下工程成本。對資料與金流尤其要小心:回滾程式碼,無法自動追回已發生的外部退款;發布策略還需要停用入口、對帳與補償安排。
下一個 PR,只增加一份可以結案的紀錄
這套做法不需要從「低風險自動合併」開始。先維持現有人審規則,在下一個 agent 撰寫的 PR 加入 finding ID、觸發條件、證據與處置理由,再定義何時停止自動修正、交給誰判斷。
退款案例的結論很簡單:併發風險有具體觸發條件、修正有對應驗證、剩下的架構偏好有獨立去處,這個 PR 才能結束。若仍說不清楚,增加第八輪審查通常只是延後那個必要的人類決定。
AI 可以讓檢查更頻繁。工程團隊要補上的,是每一輪到底解決了哪個問題,以及為什麼現在可以停。
