feat(ai-code-review): 建問題模式導向 issue,並整併流程調整、文件與 CI #6

Merged
admin merged 79 commits from ai-review-resolve/develop-20260717-185330 into develop 2026-07-21 09:39:48 +00:00
2 changed files with 1 additions and 136 deletions
Showing only changes of commit 44c33b6c1e - Show all commits
@@ -47,45 +47,6 @@
"suggestion": "補單元測試攔截 git 參數/env:斷言以 token 認證推送、推送目標 refspec 正確、呼叫次數,並確保任何拋出的錯誤、log 或快照都不含原始 token。屬測試架構決策。",
"suggestedCode": ""
},
{
"id": "F005",
"reviewer": "Bard",
"focus": "style",
"badge": "🎼",
"severity": "建議",
"file": "action.yml",
"startLine": 3,
"endLine": 3,
"problem": "檔頭「更新時間」為手動維護的固定字串,與實際檔案更新時間不一致;散落各檔的手動時間戳容易走調,讀者無法判斷可信度。",
"suggestion": "屬 jsc spec-time-log 慣例(各檔頭「更新時間」由 doc-funcs 流程統一產生/同步)。是否移除改用版控紀錄、或如何統一更新,宜由 doc-funcs 流程處理,不在 resolve 逐條硬改。",
"suggestedCode": ""
},
{
"id": "F006",
"reviewer": "Bard",
"focus": "style",
"badge": "🎼",
"severity": "建議",
"file": "readme.md",
"startLine": 3,
"endLine": 3,
"problem": "README 檔頭手動「更新時間」與實際更新時間不符,並與 action.yml、src/index.js 重複保存同類易過期資訊,形成多個不一致的真相來源。",
"suggestion": "同 F005:屬 jsc spec-time-log 慣例,交 doc-funcs 流程統一維護(移除或自動注入)。",
"suggestedCode": ""
},
{
"id": "F007",
"reviewer": "Bard",
"focus": "style",
"badge": "🎼",
"severity": "建議",
"file": "src/index.js",
"startLine": 7,
"endLine": 7,
"problem": "啟動橫幅硬編碼的「更新時間」與程式實際更新時間不一致,每次改程式都要人工校準,製造噪音並讓執行日誌呈現失真版本資訊。",
"suggestion": "同 F005:屬 jsc spec-time-log 慣例,交 doc-funcs 流程統一維護;若日誌需辨識版本,可改顯示 CI 注入的 commit SHA/版本號(屬慣例調整)。",
"suggestedCode": ""
},
{
"id": "F008",
"reviewer": "Bard",
@@ -7,103 +7,7 @@
"version": "codex-cli 0.144.6",
"model": "gpt-5.5"
},
"findings": [
{
"reviewer": "Mage",
"focus": "logic",
"badge": "🔮",
"severity": "嚴重",
"file": "src/index.js",
"startLine": 134,
"endLine": 139,
"problem": "這裡把「本輪審查」改成即使找到嚴重 finding 也回傳 0,並依賴後續 `[ai-review-bot][failure]` 結果 commit 觸發下一輪才讓檢查失敗。最小重現情境:PR 內有 1 條嚴重問題,但 `commitFindings()` 因分支保護、token 無 push 權限、遠端競態或 PAT 無法觸發 CI 而回傳 false;本輪仍成功結束,且沒有下一輪 failure commit 可被步驟 1 讀到,嚴重問題就被靜默放行。未驗證「結果 commit 一定成功且一定觸發下一輪」這個假設時,它就是流程成敗判定的單點失效。",
"suggestion": "嚴重 finding 已確認後,若 failure 結果 commit/push 沒有成功產生,就應在本輪直接回傳 1;只有在確認 failure commit 已成功推送時,才可把失敗狀態交給下一輪快速回報。也就是:`severe.length > 0 && !resultCommitPushed` 必須阻擋。",
"suggestedCode": "const result = severe.length === 0 ? 'success' : 'failure';\nlet pushed = false;\nif (filesToCommit.length > 0) {\n pushed = commitFindings({ cwd, ctx, files: filesToCommit, result });\n}\n\nif (severe.length > 0 && !pushed) {\n log('收尾', 'ERR', '已有嚴重問題,但 failure 結果 commit 未成功產生;本輪直接以失敗收場。');\n return 1;\n}\n\nreturn 0;",
"id": "F009",
"verdicts": {
"Paladin": {
"exclude": false,
"reason": "保留。此條指控嚴重 finding 依賴結果 commit 觸發下一輪才失敗,且 commit/push 失敗時本輪可能靜默通過;既有排除事項未涵蓋此成敗判定風險。"
}
}
},
{
"reviewer": "Mage",
"focus": "logic",
"badge": "🔮",
"severity": "警告",
"file": "src/index.js",
"startLine": 201,
"endLine": 209,
"problem": "`createIssueAndFlushBufferedComments()` 先建立 `trackingIssue`,再逐則寫入暫存留言;但只要其中一則留言失敗,外層 catch 會呼叫 `fallbackToPrComments()`,把整批 `pendingIssueCommentBodies` 全部改貼回 PR。最小重現情境:追蹤 issue 建立成功,第一則工具留言也成功寫入 issue,第二則 diff 留言 API 回 500;流程降級後 PR 會收到全部暫存留言,而已建立的 issue 仍殘留第一則留言、沒有後續 finding、也可能沒有 PR 連結或相依關係。這會留下部分成功、部分降級的不一致狀態。",
"suggestion": "flush 時應在每則留言成功後立刻從 pending 佇列移除,並明確處理「issue 已建立但 flush 失敗」的狀態:要嘛繼續沿用已建立 issue 並讓後續失敗冒泡,要嘛在降級前補一則 PR 診斷/連結並避免重貼已成功寫入 issue 的留言。",
"suggestedCode": "while (pendingIssueCommentBodies.length > 0) {\n const body = pendingIssueCommentBodies[0];\n await gitea.createCommentOnIssue(ctx, trackingIssue.number, body);\n pendingIssueCommentBodies.shift();\n}",
"id": "F010",
"verdicts": {
"Paladin": {
"exclude": false,
"reason": "保留。既有排除事項涵蓋 issue 建立後留言失敗導致重跑重複 issue,但本條另指出 flush 部分成功後 fallback 會把整批 pending 留言改貼 PR,造成 issue 與 PR 狀態不一致;不是單純重複。"
}
}
},
{
"reviewer": "Bard",
"focus": "style",
"badge": "🎼",
"severity": "建議",
"file": "action.yml",
"startLine": 3,
"endLine": 3,
"problem": "手動維護的「更新時間」已與本次檔案標示的最後更新時間不同步;樂譜開頭的拍號一錯,讀者後面每段註解都會多一分懷疑。同樣的不協調也出現在 `readme.md` 與 `src/index.js` 的 banner/文件時間。",
"suggestion": "移除這類容易走調的手動時間戳,或改由發布流程自動產生。若一定要保留,請讓所有檔案的時間標示與本次變更一致。",
"suggestedCode": "",
"id": "F001",
"verdicts": {
"Paladin": {
"exclude": false,
"reason": "保留。已知排除事項與歷史 findings 未涵蓋手動更新時間不同步;目前也無足夠原始碼證據可判定為誤報。"
}
}
},
{
"reviewer": "Bard",
"focus": "style",
"badge": "🎼",
"severity": "建議",
"file": "src/index.js",
"startLine": 199,
"endLine": 199,
"problem": "`createIssueAndFlushBufferedComments` 這個名稱把「建立 issue」與「flush 暫存留言」兩個實作細節硬串在一起,像一句過長的歌詞;呼叫點讀起來偏機械,沒有清楚表達業務意圖。",
"suggestion": "改成較語意化的命名,例如 `openTrackingIssue` 或 `createTrackingIssueWithContext`,讓讀者先理解目的,再從函式內容看見 flush 的細節。",
"suggestedCode": "",
"id": "F004",
"verdicts": {
"Paladin": {
"exclude": false,
"reason": "保留。此條針對 createIssueAndFlushBufferedComments 的命名語意與可讀性,未明確命中既有排除事項;與先前 ensureIssueCreated 暗示冪等的問題不完全相同。"
}
}
},
{
"reviewer": "Maya",
"focus": "testing",
"badge": "🧪",
"severity": "建議",
"file": "src/lib/gitref.js",
"startLine": 12,
"endLine": 24,
"problem": "assertSafeBranchRef 目前只測了一個正常分支與一個 ../../ 路徑穿越案例;但這個函式承擔 refspec 安全邊界,新增的空值、前後斜線、反斜線、以及 git check-ref-format 拒絕的格式都沒有案例。邊界沒被驗證時,未來調整條件很容易放過不合法 ref。",
"suggestion": "補上表格測試,至少涵蓋空字串、純空白、/feature、feature/、feature\\\\x、feature..x、feature.lock、feature@{x},並斷言錯誤訊息能區分「不安全」與「不合法 git 分支名稱」。",
"suggestedCode": "",
"id": "F014",
"verdicts": {
"Paladin": {
"exclude": false,
"reason": "保留。此條針對 assertSafeBranchRef 的 refspec 安全邊界測試不足,未見已知排除事項或歷史 findings 明確涵蓋;證據不足以排除。"
}
}
}
],
"findings": [],
"excluded": [
{
"reviewer": "Bard",