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

Closed
opened 2026-07-20 07:03:31 +00:00 by gitea-actions · 21 comments

變更摘要

本 PR 將 ai-code-review action 分支的完整成果併入 develop,主要含四塊:

  1. 建問題模式重構(feat)create-issue: 'true' 時,審查留言(工具/diff/角色/嚴重問題/警告+建議)全部改發到追蹤 issue、不再張貼到 PR;不執行「舊留言標過時/resolve」;issue 延後到「確定有保留問題」才建立;無保留問題或無可審查變更則不建 issue、PR 也完全不留言(靜默通過);有問題時最後在 PR 回貼一則 issue 連結並補掛標籤,形成雙向關聯。
  2. 審查流程步驟調整(refactor):將「標記舊留言過時/resolve」提前到偵測 AI 工具之前,並依新順序重編所有步驟編號與說明。
  3. 修正(gitrepo):補抓淺層 checkout 的 base 歷史,避免 merge-base 計算失敗。
  4. 文件與 CI:補齊 action.ymlsrc 各模組文件、重建 readme.md,新增 .gitea/workflows/ci.yaml(多工具 code review 驗證)並啟用建問題模式。

影響範圍

範圍 說明
action 執行流程 src/index.js main() 依模式分流:留言去向、跳過 resolveOldComments、issue 延後建立、severe/others 導向 issue、有問題才在 PR 回貼連結
Gitea API src/lib/gitea.js 新增 addLabelsToIssue
留言模板 src/lib/templates.js 新增 issueLinkComment
審查核心 src/lib/review.js 新增 postSevereToIssue,移除 createIssueWithFindingssortFindingsForIssue
git base 解析 src/lib/gitrepo.js 補抓淺層 checkout 的 base 歷史
文件與 CI readme.mdaction.yml.gitea/workflows/ci.yaml.gitea/workflows/readme.md

風險與注意事項

  • 建問題模式行為明顯改變:啟用後 PR 上不再有審查留言(有問題時改為 issue + 一則連結留言;無問題時完全不留言),請確認團隊流程可接受。
  • 端對端行為需靠 CI 實測:本地僅完成語法與模組載入驗證,實際 issue/PR 互動需一次 CI 觸發確認。
  • readme.md 尚未反映「建問題模式導向 issue」的最新行為與新/移除的函式,建議後續以 doc-funcs 重建文件。
  • 各檔頭部「更新時間」時間戳仍為 2026/07/17 18:49:58,未刷新。

本問題由 AI Code Review 依 PR #6 的審查結果自動建立,問題明細見下方留言。

<!-- ai-code-review --> ## 變更摘要 本 PR 將 ai-code-review action 分支的完整成果併入 `develop`,主要含四塊: 1. **建問題模式重構(feat)**:`create-issue: 'true'` 時,審查留言(工具/diff/角色/嚴重問題/警告+建議)全部改發到追蹤 issue、不再張貼到 PR;不執行「舊留言標過時/resolve」;issue 延後到「確定有保留問題」才建立;**無保留問題或無可審查變更則不建 issue、PR 也完全不留言(靜默通過)**;有問題時最後在 PR 回貼一則 issue 連結並補掛標籤,形成雙向關聯。 2. **審查流程步驟調整(refactor)**:將「標記舊留言過時/resolve」提前到偵測 AI 工具之前,並依新順序重編所有步驟編號與說明。 3. **修正(gitrepo)**:補抓淺層 checkout 的 base 歷史,避免 merge-base 計算失敗。 4. **文件與 CI**:補齊 `action.yml`/`src` 各模組文件、重建 `readme.md`,新增 `.gitea/workflows/ci.yaml`(多工具 code review 驗證)並啟用建問題模式。 ## 影響範圍 | 範圍 | 說明 | | --- | --- | | action 執行流程 | `src/index.js` `main()` 依模式分流:留言去向、跳過 resolveOldComments、issue 延後建立、severe/others 導向 issue、有問題才在 PR 回貼連結 | | Gitea API | `src/lib/gitea.js` 新增 `addLabelsToIssue` | | 留言模板 | `src/lib/templates.js` 新增 `issueLinkComment` | | 審查核心 | `src/lib/review.js` 新增 `postSevereToIssue`,移除 `createIssueWithFindings`、`sortFindingsForIssue` | | git base 解析 | `src/lib/gitrepo.js` 補抓淺層 checkout 的 base 歷史 | | 文件與 CI | `readme.md`、`action.yml`、`.gitea/workflows/ci.yaml`、`.gitea/workflows/readme.md` | ## 風險與注意事項 - **建問題模式行為明顯改變**:啟用後 PR 上不再有審查留言(有問題時改為 issue + 一則連結留言;無問題時完全不留言),請確認團隊流程可接受。 - **端對端行為需靠 CI 實測**:本地僅完成語法與模組載入驗證,實際 issue/PR 互動需一次 CI 觸發確認。 - `readme.md` 尚未反映「建問題模式導向 issue」的最新行為與新/移除的函式,建議後續以 doc-funcs 重建文件。 - 各檔頭部「更新時間」時間戳仍為 `2026/07/17 18:49:58`,未刷新。 --- > 本問題由 AI Code Review 依 PR #6 的審查結果自動建立,問題明細見下方留言。

🤖 AI Code Review|審查工具

項目 內容
工具 codex
版本 codex-cli 0.144.6
模型 (工具預設)
審查 commit 10d826d1b17ab26521359a11e08dbe3e7ead8d31
Run Job #19
flowchart LR
    A[整理 git diff] --> B[⚔️ 攻擊方找問題]
    B --> C[🛡️ 防守方裁決]
    C --> D[保存 findings]
    D --> E[留言到 PR]
<!-- ai-code-review --> ## 🤖 AI Code Review|審查工具 | 項目 | 內容 | | --- | --- | | 工具 | `codex` | | 版本 | `codex-cli 0.144.6` | | 模型 | (工具預設) | | 審查 commit | `10d826d1b17ab26521359a11e08dbe3e7ead8d31` | | Run Job | [#19](https://gitea.jsc.idv.tw/node-actions/ai-code-review/actions/runs/1587) | ```mermaid flowchart LR A[整理 git diff] --> B[⚔️ 攻擊方找問題] B --> C[🛡️ 防守方裁決] C --> D[保存 findings] D --> E[留言到 PR] ```

📋 變更摘要(送審 git diff)

檔案 用途 git diff 長度 最後更新時間
action.yml 定義 Action 輸入與執行環境 95 行/4205 字元 2026/07/20 15:00:23
readme.md 說明專案功能、流程與使用方式 274 行/23780 字元(過長截斷送審) 2026/07/20 09:46:12
src/index.js 編排 AI 程式碼審查主流程 320 行/14204 字元 2026/07/20 15:00:15
src/lib/agents.js 偵測並執行可用的 AI 工具 14 行/503 字元 2026/07/20 09:46:12
src/lib/context.js 載入 Action 輸入與執行上下文 31 行/1398 字元 2026/07/20 15:00:23
src/lib/gitea.js 封裝 Gitea API 操作 143 行/6234 字元 2026/07/20 15:00:15
src/lib/gitrepo.js 處理 Git 差異、歷史與提交 177 行/7374 字元 2026/07/20 14:59:49
src/lib/review.js 執行審查、裁決與結果處理 578 行/24706 字元(過長截斷送審) 2026/07/20 14:59:38
src/lib/roles.js 載入並分類審查角色設定 14 行/586 字元 2026/07/20 09:46:12
src/lib/templates.js 產生審查留言的固定模板 165 行/5949 字元 2026/07/20 15:00:32

共 10 個檔案納入審查;另有 5 個檔案依 .reviewignore 排除。

<!-- ai-code-review --> ## 📋 變更摘要(送審 git diff) | 檔案 | 用途 | git diff 長度 | 最後更新時間 | | --- | --- | --- | --- | | `action.yml` | 定義 Action 輸入與執行環境 | 95 行/4205 字元 | 2026/07/20 15:00:23 | | `readme.md` | 說明專案功能、流程與使用方式 | 274 行/23780 字元(過長截斷送審) | 2026/07/20 09:46:12 | | `src/index.js` | 編排 AI 程式碼審查主流程 | 320 行/14204 字元 | 2026/07/20 15:00:15 | | `src/lib/agents.js` | 偵測並執行可用的 AI 工具 | 14 行/503 字元 | 2026/07/20 09:46:12 | | `src/lib/context.js` | 載入 Action 輸入與執行上下文 | 31 行/1398 字元 | 2026/07/20 15:00:23 | | `src/lib/gitea.js` | 封裝 Gitea API 操作 | 143 行/6234 字元 | 2026/07/20 15:00:15 | | `src/lib/gitrepo.js` | 處理 Git 差異、歷史與提交 | 177 行/7374 字元 | 2026/07/20 14:59:49 | | `src/lib/review.js` | 執行審查、裁決與結果處理 | 578 行/24706 字元(過長截斷送審) | 2026/07/20 14:59:38 | | `src/lib/roles.js` | 載入並分類審查角色設定 | 14 行/586 字元 | 2026/07/20 09:46:12 | | `src/lib/templates.js` | 產生審查留言的固定模板 | 165 行/5949 字元 | 2026/07/20 15:00:32 | > 共 10 個檔案納入審查;另有 5 個檔案依 `.reviewignore` 排除。

⚔️ 攻擊方登場

角色 面向 個性
🗡️ Assassin 安全性(security) 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用
🎼 Bard 風格(style) 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版
🧰 Leo 可維護性(maintainability) 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來
🔮 Mage 邏輯(logic) 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」
🧪 Maya 測試(testing) 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑
Rogue 效率(efficiency) 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」
<!-- ai-code-review --> ## ⚔️ 攻擊方登場 | 角色 | 面向 | 個性 | | --- | --- | --- | | 🗡️ **Assassin** | 安全性(security) | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | 🎼 **Bard** | 風格(style) | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | 🧰 **Leo** | 可維護性(maintainability) | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | 🔮 **Mage** | 邏輯(logic) | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | 🧪 **Maya** | 測試(testing) | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | ⚡ **Rogue** | 效率(efficiency) | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 |

🛡️ 防守方登場

角色 面向 個性
🛡️ Paladin 裁決(verdict) 沉穩公正、就事論事,不護短也不冤枉,只依排除事項與原始碼脈絡裁定問題成立與否
<!-- ai-code-review --> ## 🛡️ 防守方登場 | 角色 | 面向 | 個性 | | --- | --- | --- | | 🛡️ **Paladin** | 裁決(verdict) | 沉穩公正、就事論事,不護短也不冤枉,只依排除事項與原始碼脈絡裁定問題成立與否 |

🔴 嚴重|🔮 Mage

位置src/index.js 第 268–268 行

問題描述

舊審查留言仍在本回合結果完整發布前就被標記為過時;一般審查路徑的同類呼叫也出現在約第 343 行。最小重現:先有一輪有效舊 findings,本輪成功完成 AI 裁決後執行 resolveOldComments,接著 postSevereComments、其他問題留言或 commitFindings 因 API/push 暫時失敗;Action 最終回傳失敗,但舊結果已被清除,新結果又只發布一部分或完全未提交。無可審查變更路徑同樣會在 saveFindings 與 push 成功前清除舊結果,違反此次改動宣稱的「成功產生結果後才清除」語義。

修改建議

把清理舊留言移到本輪所有必要結果均成功產生之後:無變更路徑至少先保存並成功提交空 findings;一般路徑先完成所有新留言與必要提交,再清理舊留言。若 push 會觸發下一輪而不能最後執行,應將發布狀態做成可重入的兩階段流程,確保失敗重跑不會留下「舊結果已清除、新結果不完整」的中間狀態。

<!-- ai-code-review --> ### 🔴 嚴重|🔮 Mage **位置**:`src/index.js` 第 268–268 行 **問題描述** 舊審查留言仍在本回合結果完整發布前就被標記為過時;一般審查路徑的同類呼叫也出現在約第 343 行。最小重現:先有一輪有效舊 findings,本輪成功完成 AI 裁決後執行 `resolveOldComments`,接著 `postSevereComments`、其他問題留言或 `commitFindings` 因 API/push 暫時失敗;Action 最終回傳失敗,但舊結果已被清除,新結果又只發布一部分或完全未提交。無可審查變更路徑同樣會在 `saveFindings` 與 push 成功前清除舊結果,違反此次改動宣稱的「成功產生結果後才清除」語義。 **修改建議** 把清理舊留言移到本輪所有必要結果均成功產生之後:無變更路徑至少先保存並成功提交空 findings;一般路徑先完成所有新留言與必要提交,再清理舊留言。若 push 會觸發下一輪而不能最後執行,應將發布狀態做成可重入的兩階段流程,確保失敗重跑不會留下「舊結果已清除、新結果不完整」的中間狀態。

🔴 嚴重|🗡️ Assassin

位置src/lib/gitrepo.js 第 274–276 行

問題描述

專用 PAT 被直接嵌入遠端 URL,再作為 git push 的命令列參數。攻擊者只要讓推送失敗,Node.js/git 的例外、程序診斷或 runner 程序清單就可能帶出完整命令,將 PAT 洩漏到 CI log 或同機程序;註解宣稱「不輸出 URL」並不能阻止底層例外回顯 argv。

修改建議

推送目標應維持不含憑證的 URL,改用暫時性的 GIT_ASKPASS/credential helper 或受 runner 保護的認證機制提供 PAT;同時在 git 包裝層攔截錯誤並建立不含參數與遠端 URL的固定錯誤訊息,清除暫存憑證後再拋出。

<!-- ai-code-review --> ### 🔴 嚴重|🗡️ Assassin **位置**:`src/lib/gitrepo.js` 第 274–276 行 **問題描述** 專用 PAT 被直接嵌入遠端 URL,再作為 `git push` 的命令列參數。攻擊者只要讓推送失敗,Node.js/git 的例外、程序診斷或 runner 程序清單就可能帶出完整命令,將 PAT 洩漏到 CI log 或同機程序;註解宣稱「不輸出 URL」並不能阻止底層例外回顯 argv。 **修改建議** 推送目標應維持不含憑證的 URL,改用暫時性的 `GIT_ASKPASS`/credential helper 或受 runner 保護的認證機制提供 PAT;同時在 git 包裝層攔截錯誤並建立不含參數與遠端 URL的固定錯誤訊息,清除暫存憑證後再拋出。

🔴 嚴重|🗡️ Assassin

位置src/lib/review.js 第 72–81 行

問題描述

開啟 ACTIONS_STEP_DEBUG=true 後,會把攻擊者可間接操控的 AI CLI stderr/stdout 寫入長期保存的 CI log。redactSecrets 只是黑名單式正規表示式,短 token、JWT、含標點或空白的密碼、非典型金鑰及 PII 都能繞過;惡意 PR 可透過提示注入誘使 CLI 回顯來源內容或環境資訊,再刻意觸發失敗完成外洩。這也違反回應不得包含 PII 的組織規範。

修改建議

CI log 不應輸出 AI CLI 原文,即使在除錯模式也只記錄退出碼、signal、逾時狀態與隨機診斷 ID。若確實需要原始輸出,應寫入存取受限、短期保存且經人工授權取得的安全 artifact,並在寫入前套用允許清單式結構化診斷與 PII/機密掃描。

建議寫法

function agentFailureDetail(res) {
  const err = res && res.error;
  if (err && err.killed) return '已逾時終止';
  if (err && typeof err.code === 'number') return `exit ${err.code}`;
  if (err && err.signal) return `signal ${err.signal}`;
  return 'AI CLI 執行失敗(原始輸出已隱藏)';
}
<!-- ai-code-review --> ### 🔴 嚴重|🗡️ Assassin **位置**:`src/lib/review.js` 第 72–81 行 **問題描述** 開啟 `ACTIONS_STEP_DEBUG=true` 後,會把攻擊者可間接操控的 AI CLI stderr/stdout 寫入長期保存的 CI log。`redactSecrets` 只是黑名單式正規表示式,短 token、JWT、含標點或空白的密碼、非典型金鑰及 PII 都能繞過;惡意 PR 可透過提示注入誘使 CLI 回顯來源內容或環境資訊,再刻意觸發失敗完成外洩。這也違反回應不得包含 PII 的組織規範。 **修改建議** CI log 不應輸出 AI CLI 原文,即使在除錯模式也只記錄退出碼、signal、逾時狀態與隨機診斷 ID。若確實需要原始輸出,應寫入存取受限、短期保存且經人工授權取得的安全 artifact,並在寫入前套用允許清單式結構化診斷與 PII/機密掃描。 **建議寫法** ``` function agentFailureDetail(res) { const err = res && res.error; if (err && err.killed) return '已逾時終止'; if (err && typeof err.code === 'number') return `exit ${err.code}`; if (err && err.signal) return `signal ${err.signal}`; return 'AI CLI 執行失敗(原始輸出已隱藏)'; } ```

🟠 警告|🧰 Leo

位置src/index.js 第 176–218 行

問題描述

main() 內新增了 issueBuffer、可變的 issuepostCommentensureIssueCreated 閉包,後續流程又在多處依 ctx.createIssue 分支。留言路由、issue 生命週期、標籤、相依關係與審查編排因此共享同一批可變狀態;未來再增加發布目的地或重試策略時,必須同步理解並修改整個超長主流程,測試也只能透過 main() 間接覆蓋。

修改建議

抽出具明確介面的發布器,例如 PrReviewPublisherIssueReviewPublisher,由發布器封裝留言暫存、issue 建立、沖刷、問題明細與收束關聯;main() 只呼叫一致的 publishContextpublishFindingsfinalize。如此可分別注入假的 Gitea client 測試兩種模式,也能移除散落的模式判斷。

<!-- ai-code-review --> ### 🟠 警告|🧰 Leo **位置**:`src/index.js` 第 176–218 行 **問題描述** `main()` 內新增了 `issueBuffer`、可變的 `issue`、`postComment` 與 `ensureIssueCreated` 閉包,後續流程又在多處依 `ctx.createIssue` 分支。留言路由、issue 生命週期、標籤、相依關係與審查編排因此共享同一批可變狀態;未來再增加發布目的地或重試策略時,必須同步理解並修改整個超長主流程,測試也只能透過 `main()` 間接覆蓋。 **修改建議** 抽出具明確介面的發布器,例如 `PrReviewPublisher` 與 `IssueReviewPublisher`,由發布器封裝留言暫存、issue 建立、沖刷、問題明細與收束關聯;`main()` 只呼叫一致的 `publishContext`、`publishFindings`、`finalize`。如此可分別注入假的 Gitea client 測試兩種模式,也能移除散落的模式判斷。

🟠 警告|🧪 Maya

位置src/index.js 第 184–245 行

問題描述

建問題模式新增了「issue 建立前先暫存留言、建立後依序沖刷」的狀態流程,但本次變更沒有對應測試。尚未驗證 createIssue 或沖刷途中拋錯、空 buffer、重複呼叫 ensureIssueCreated,以及一般模式與建問題模式的留言目的地是否正確;這些失敗路徑可能造成 issue 已建立但內容不完整,或留言誤發到 PR。

修改建議

補上主流程整合測試,mock Gitea API 並驗證:一般模式直接發 PR 且記錄留言 id;issue 尚未建立時只暫存;建立後依原順序沖刷並清空 buffer;issue 已建立後直接留言;createIssue 與第 N 則沖刷留言失敗時會以失敗結束,且不會繼續發布後續內容。

<!-- ai-code-review --> ### 🟠 警告|🧪 Maya **位置**:`src/index.js` 第 184–245 行 **問題描述** 建問題模式新增了「issue 建立前先暫存留言、建立後依序沖刷」的狀態流程,但本次變更沒有對應測試。尚未驗證 `createIssue` 或沖刷途中拋錯、空 buffer、重複呼叫 `ensureIssueCreated`,以及一般模式與建問題模式的留言目的地是否正確;這些失敗路徑可能造成 issue 已建立但內容不完整,或留言誤發到 PR。 **修改建議** 補上主流程整合測試,mock Gitea API 並驗證:一般模式直接發 PR 且記錄留言 id;issue 尚未建立時只暫存;建立後依原順序沖刷並清空 buffer;issue 已建立後直接留言;`createIssue` 與第 N 則沖刷留言失敗時會以失敗結束,且不會繼續發布後續內容。

🟠 警告|🧪 Maya

位置src/index.js 第 309–395 行

問題描述

建問題模式的核心分支被大幅改寫,但沒有測試驗證各種 findings 組合與 API 失敗時的行為。尤其 kept.length === 0、只有嚴重問題、只有警告/建議、兩者皆有,以及標籤挑選失敗、issue 建立失敗、PR 回貼連結失敗、相依 API 失敗等路徑都尚未被試煉;目前無法確認「無問題時完全靜默」、「有問題才建 issue」及相依失敗僅降級等契約真的成立。

修改建議

以參數化測試覆蓋 findings 的四種組合,精確斷言 API 呼叫順序、次數、issue number 與問題統計。另分別讓 listLabelsselectLabelscreateIssue、問題留言、PR 連結留言及 addIssueDependency 拋錯,驗證哪些錯誤應中止、哪些只記錄警告並繼續;也要斷言零 findings 時所有寫入 API 都不會被呼叫。

<!-- ai-code-review --> ### 🟠 警告|🧪 Maya **位置**:`src/index.js` 第 309–395 行 **問題描述** 建問題模式的核心分支被大幅改寫,但沒有測試驗證各種 findings 組合與 API 失敗時的行為。尤其 `kept.length === 0`、只有嚴重問題、只有警告/建議、兩者皆有,以及標籤挑選失敗、issue 建立失敗、PR 回貼連結失敗、相依 API 失敗等路徑都尚未被試煉;目前無法確認「無問題時完全靜默」、「有問題才建 issue」及相依失敗僅降級等契約真的成立。 **修改建議** 以參數化測試覆蓋 findings 的四種組合,精確斷言 API 呼叫順序、次數、issue number 與問題統計。另分別讓 `listLabels`、`selectLabels`、`createIssue`、問題留言、PR 連結留言及 `addIssueDependency` 拋錯,驗證哪些錯誤應中止、哪些只記錄警告並繼續;也要斷言零 findings 時所有寫入 API 都不會被呼叫。

🟠 警告|🧪 Maya

位置src/lib/gitea.js 第 171–215 行

問題描述

新增的標籤與問題相依 API 包裝沒有測試驗證 endpoint、HTTP method 與 payload。特別是 addLabelsToIssue 的 null/undefined/空陣列短路,以及 addIssueDependency 中容易顛倒的「PR 相依於 issue」方向都未被斷言;若 index 或 body 欄位放反,測試外觀仍可能正常但合併阻擋語意會相反。

修改建議

mock 底層 API,驗證空 labels 完全不送請求並回傳 null,非空 labels 使用正確 issue 編號與 { labels }。對相依關係使用不同的 PR/issue 編號,精確斷言 URL 指向 PR、body.index 指向阻擋來源 issue,並覆蓋 API 非 2xx 時錯誤原樣往上拋出的案例。

<!-- ai-code-review --> ### 🟠 警告|🧪 Maya **位置**:`src/lib/gitea.js` 第 171–215 行 **問題描述** 新增的標籤與問題相依 API 包裝沒有測試驗證 endpoint、HTTP method 與 payload。特別是 `addLabelsToIssue` 的 null/undefined/空陣列短路,以及 `addIssueDependency` 中容易顛倒的「PR 相依於 issue」方向都未被斷言;若 index 或 body 欄位放反,測試外觀仍可能正常但合併阻擋語意會相反。 **修改建議** mock 底層 API,驗證空 labels 完全不送請求並回傳 null,非空 labels 使用正確 issue 編號與 `{ labels }`。對相依關係使用不同的 PR/issue 編號,精確斷言 URL 指向 PR、body.index 指向阻擋來源 issue,並覆蓋 API 非 2xx 時錯誤原樣往上拋出的案例。

🟠 警告|🧪 Maya

位置src/lib/gitrepo.js 第 103–157 行

問題描述

resolveMergeBase 新增多階段 fetch/重試策略,卻沒有測試鎖定淺層與失敗路徑。尚未驗證首次 merge-base 成功時會提早返回、非 shallow repo 不執行 unshallow、某次 fetch 失敗後仍會嘗試下一策略、補抓成功後立即停止,以及全部失敗時診斷與 cause 是否完整;這類流程很容易因呼叫順序或 off-by-one 次數錯誤而在 runner 上才暴露。

修改建議

將 git 執行器注入或 stub,建立表格化案例覆蓋:首次成功、unshallow 後成功、deepen base 後成功、deepen HEAD 後成功、各 fetch 個別失敗,以及全部策略失敗。逐案斷言 git 參數與呼叫順序、成功後不再額外 fetch,並檢查最終錯誤包含每個策略的成敗摘要且保留首次錯誤為 cause

<!-- ai-code-review --> ### 🟠 警告|🧪 Maya **位置**:`src/lib/gitrepo.js` 第 103–157 行 **問題描述** `resolveMergeBase` 新增多階段 fetch/重試策略,卻沒有測試鎖定淺層與失敗路徑。尚未驗證首次 merge-base 成功時會提早返回、非 shallow repo 不執行 unshallow、某次 fetch 失敗後仍會嘗試下一策略、補抓成功後立即停止,以及全部失敗時診斷與 `cause` 是否完整;這類流程很容易因呼叫順序或 off-by-one 次數錯誤而在 runner 上才暴露。 **修改建議** 將 git 執行器注入或 stub,建立表格化案例覆蓋:首次成功、unshallow 後成功、deepen base 後成功、deepen HEAD 後成功、各 fetch 個別失敗,以及全部策略失敗。逐案斷言 git 參數與呼叫順序、成功後不再額外 fetch,並檢查最終錯誤包含每個策略的成敗摘要且保留首次錯誤為 `cause`。

🟠 警告|🧪 Maya

位置src/lib/gitrepo.js 第 249–289 行

問題描述

推送流程新增 pushToken 分支,但沒有測試驗證兩套認證策略。尚未確認有 PAT 時確實略過 origin、PAT 推送失敗時不會意外退回其他 token、無 PAT 時 origin 成功不重試,以及 origin 失敗才使用一般 token;也沒有案例保護含憑證 URL 不會出現在錯誤或測試輸出中。

修改建議

mock git 執行器與 URL 組裝,補測 pushToken 有值/空字串、origin 成功/失敗、PAT 推送失敗及 token 含特殊字元等案例。精確斷言 push 目標與呼叫次數,並確保任何拋出的錯誤、log 或快照都不含原始 token。

<!-- ai-code-review --> ### 🟠 警告|🧪 Maya **位置**:`src/lib/gitrepo.js` 第 249–289 行 **問題描述** 推送流程新增 `pushToken` 分支,但沒有測試驗證兩套認證策略。尚未確認有 PAT 時確實略過 origin、PAT 推送失敗時不會意外退回其他 token、無 PAT 時 origin 成功不重試,以及 origin 失敗才使用一般 token;也沒有案例保護含憑證 URL 不會出現在錯誤或測試輸出中。 **修改建議** mock git 執行器與 URL 組裝,補測 `pushToken` 有值/空字串、origin 成功/失敗、PAT 推送失敗及 token 含特殊字元等案例。精確斷言 push 目標與呼叫次數,並確保任何拋出的錯誤、log 或快照都不含原始 token。

🟠 警告|🧪 Maya

位置src/lib/review.js 第 16–80 行

問題描述

新增的 redactSecretsagentFailureDetail 直接決定 CI 日誌是否洩漏內容及失敗診斷是否可用,但本次沒有測試覆蓋。空值、控制字元、Authorization/Bearer、URL 帳密、各種 token 樣式、500 字截斷,以及 ACTIONS_STEP_DEBUG 大小寫與未啟用時隱藏 stdout/stderr 等邊界都尚未驗證。

修改建議

為這兩個純函式補單元測試;必要時以受控方式匯出或抽到獨立模組。使用不具真實性的假憑證逐一測試所有遮罩規則與換行注入,並在每個案例斷言輸出不含原始秘密。另保存並還原 ACTIONS_STEP_DEBUG,驗證預設、true、混合大小寫、逾時、exit code、signal、無 error 與超長輸出的結果。

<!-- ai-code-review --> ### 🟠 警告|🧪 Maya **位置**:`src/lib/review.js` 第 16–80 行 **問題描述** 新增的 `redactSecrets`/`agentFailureDetail` 直接決定 CI 日誌是否洩漏內容及失敗診斷是否可用,但本次沒有測試覆蓋。空值、控制字元、Authorization/Bearer、URL 帳密、各種 token 樣式、500 字截斷,以及 `ACTIONS_STEP_DEBUG` 大小寫與未啟用時隱藏 stdout/stderr 等邊界都尚未驗證。 **修改建議** 為這兩個純函式補單元測試;必要時以受控方式匯出或抽到獨立模組。使用不具真實性的假憑證逐一測試所有遮罩規則與換行注入,並在每個案例斷言輸出不含原始秘密。另保存並還原 `ACTIONS_STEP_DEBUG`,驗證預設、`true`、混合大小寫、逾時、exit code、signal、無 error 與超長輸出的結果。

🟠 警告| Rogue

位置src/lib/review.js 第 68–72 行

問題描述

除錯模式下,stderr/stdout 會先把完整內容送進 redactSecrets(),經過多輪正規表示式掃描與字串配置後才截成 500 字。若 AI CLI 失敗並產生數 MB 輸出,每份輸出約需 O(k×n) 掃描及多份 O(n) 暫存字串,白白消耗 CPU 與記憶體;攻擊方並行失敗時還會按角色數放大。

修改建議

先限制送入遮罩器的字元數,再進行遮罩與最終截斷;保留少量緩衝即可涵蓋跨界 token 樣式,讓診斷成本固定在 O(1) 上限。

建議寫法

const DEBUG_INPUT_LIMIT = 2_000;
const stderr = redactSecrets(String((res && res.stderr) || '').slice(0, DEBUG_INPUT_LIMIT));
if (stderr) parts.push(`stderr:${stderr.slice(0, 500)}`);
const stdout = redactSecrets(String((res && res.output) || '').slice(0, DEBUG_INPUT_LIMIT));
if (stdout) parts.push(`stdout:${stdout.slice(0, 500)}`);
<!-- ai-code-review --> ### 🟠 警告|⚡ Rogue **位置**:`src/lib/review.js` 第 68–72 行 **問題描述** 除錯模式下,stderr/stdout 會先把完整內容送進 `redactSecrets()`,經過多輪正規表示式掃描與字串配置後才截成 500 字。若 AI CLI 失敗並產生數 MB 輸出,每份輸出約需 O(k×n) 掃描及多份 O(n) 暫存字串,白白消耗 CPU 與記憶體;攻擊方並行失敗時還會按角色數放大。 **修改建議** 先限制送入遮罩器的字元數,再進行遮罩與最終截斷;保留少量緩衝即可涵蓋跨界 token 樣式,讓診斷成本固定在 O(1) 上限。 **建議寫法** ``` const DEBUG_INPUT_LIMIT = 2_000; const stderr = redactSecrets(String((res && res.stderr) || '').slice(0, DEBUG_INPUT_LIMIT)); if (stderr) parts.push(`stderr:${stderr.slice(0, 500)}`); const stdout = redactSecrets(String((res && res.output) || '').slice(0, DEBUG_INPUT_LIMIT)); if (stdout) parts.push(`stdout:${stdout.slice(0, 500)}`); ```

🔵 建議|🎼 Bard

位置action.yml 第 47–61 行

問題描述

push-token 的用途與退回行為在區塊註解、欄位描述、required 註解及 default 註解中反覆吟唱,且單行 description 過長。資訊雖完整,主旋律卻被重複說明淹沒,日後修改語意也容易只改到其中一處。

修改建議

保留一段解釋「為何需要 PAT」的必要背景,其餘讓欄位名稱、requireddefault 自行表意;將 description 收斂成呼叫端真正需要知道的契約。

建議寫法

# 專用推送 PAT;以 PAT 推送可重新觸發 CI。留空時沿用 token。
  push-token:
    description: '推送審查結果 commit 的 PAT(留空時沿用 token)'
    required: false
    default: ''
<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`action.yml` 第 47–61 行 **問題描述** `push-token` 的用途與退回行為在區塊註解、欄位描述、`required` 註解及 `default` 註解中反覆吟唱,且單行 `description` 過長。資訊雖完整,主旋律卻被重複說明淹沒,日後修改語意也容易只改到其中一處。 **修改建議** 保留一段解釋「為何需要 PAT」的必要背景,其餘讓欄位名稱、`required` 與 `default` 自行表意;將 `description` 收斂成呼叫端真正需要知道的契約。 **建議寫法** ``` # 專用推送 PAT;以 PAT 推送可重新觸發 CI。留空時沿用 token。 push-token: description: '推送審查結果 commit 的 PAT(留空時沿用 token)' required: false default: '' ```

🔵 建議|🎼 Bard

位置readme.md 第 41–48 行

問題描述

流程圖將「舊留言標記解決」畫成步驟 1 後立即執行,但新版主流程實際延後至攻防裁決完成、發布問題留言之前。文件的演奏順序與程式碼錯拍,讀者會誤以為舊結果仍會在審查初期被清除。

修改建議

依實際執行順序重排節點,或明確將此節點標示為「編號 2、延後執行」,避免步驟編號被誤讀為時間順序。

建議寫法

flowchart TD
    S1[1 判斷 bot commit 標記] -->|命中| E0[直接回報 success/failure]
    S1 -->|未命中| S3[3 偵測 AI 工具並留言]
    S3 --> S4[4 讀 .reviewignore 整理 diff 並留言]
    S4 --> S5[5 攻擊方登場留言]
    S5 --> S6[6 攻擊方 sub agent 並行找問題]
    S6 --> S7[7 防守方登場留言]
    S7 --> S8[8 防守方裁決 → 保存 findings + 誤判回寫 exclusions.json]
    S8 --> S2[2 延後將舊留言標記解決]
    S2 --> S9[9 嚴重問題逐條留言]
<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`readme.md` 第 41–48 行 **問題描述** 流程圖將「舊留言標記解決」畫成步驟 1 後立即執行,但新版主流程實際延後至攻防裁決完成、發布問題留言之前。文件的演奏順序與程式碼錯拍,讀者會誤以為舊結果仍會在審查初期被清除。 **修改建議** 依實際執行順序重排節點,或明確將此節點標示為「編號 2、延後執行」,避免步驟編號被誤讀為時間順序。 **建議寫法** ``` flowchart TD S1[1 判斷 bot commit 標記] -->|命中| E0[直接回報 success/failure] S1 -->|未命中| S3[3 偵測 AI 工具並留言] S3 --> S4[4 讀 .reviewignore 整理 diff 並留言] S4 --> S5[5 攻擊方登場留言] S5 --> S6[6 攻擊方 sub agent 並行找問題] S6 --> S7[7 防守方登場留言] S7 --> S8[8 防守方裁決 → 保存 findings + 誤判回寫 exclusions.json] S8 --> S2[2 延後將舊留言標記解決] S2 --> S9[9 嚴重問題逐條留言] ```

🔵 建議|🎼 Bard

位置src/index.js 第 203–226 行

問題描述

ensureIssueCreated 之名帶有「已存在便沿用」的冪等語意,實際卻無條件建立新 issue,並悄悄改寫外層的 issue。名稱、行為與副作用沒有押上同一個韻,閱讀呼叫處時容易形成錯誤預期。

修改建議

若此函式只允許呼叫一次,改用直接表達建立與沖刷暫存留言的名稱,並回傳建立結果;由呼叫端明確指派 issue,讓資料流一眼可見。

建議寫法

const createIssueAndFlushBuffer = async (labelIds = []) => {
  const createdIssue = await gitea.createIssue(ctx, {
    title: ctx.prTitle || `AI Code Review:PR #${ctx.prNumber}`,
    body: templates.issueBody({ prNumber: ctx.prNumber, prBody: ctx.prBody }),
    labels: labelIds,
  });

  for (const body of issueBuffer) {
    await gitea.createCommentOnIssue(ctx, createdIssue.number, body);
  }
  issueBuffer.length = 0;
  return createdIssue;
};

issue = await createIssueAndFlushBuffer(labelIds);
<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`src/index.js` 第 203–226 行 **問題描述** `ensureIssueCreated` 之名帶有「已存在便沿用」的冪等語意,實際卻無條件建立新 issue,並悄悄改寫外層的 `issue`。名稱、行為與副作用沒有押上同一個韻,閱讀呼叫處時容易形成錯誤預期。 **修改建議** 若此函式只允許呼叫一次,改用直接表達建立與沖刷暫存留言的名稱,並回傳建立結果;由呼叫端明確指派 `issue`,讓資料流一眼可見。 **建議寫法** ``` const createIssueAndFlushBuffer = async (labelIds = []) => { const createdIssue = await gitea.createIssue(ctx, { title: ctx.prTitle || `AI Code Review:PR #${ctx.prNumber}`, body: templates.issueBody({ prNumber: ctx.prNumber, prBody: ctx.prBody }), labels: labelIds, }); for (const body of issueBuffer) { await gitea.createCommentOnIssue(ctx, createdIssue.number, body); } issueBuffer.length = 0; return createdIssue; }; issue = await createIssueAndFlushBuffer(labelIds); ```

🔵 建議|🧰 Leo

位置src/lib/gitea.js 第 171–195 行

問題描述

本次新增 addLabelsToIssue,但新流程已明確改為建立 issue 時一次帶入標籤,且目前沒有任何呼叫端。保留這個推測未來可能使用的公開函式,會擴大 Gitea client 的 API 面積,讓維護者誤以為存在兩套正式的標籤流程,未來也必須持續維護文件與測試。

修改建議

若目前沒有實際使用情境,先移除 addLabelsToIssue 與匯出項目;等真正需要對既有 issue 追加標籤時,再連同明確呼叫端與測試一起加入。

<!-- ai-code-review --> ### 🔵 建議|🧰 Leo **位置**:`src/lib/gitea.js` 第 171–195 行 **問題描述** 本次新增 `addLabelsToIssue`,但新流程已明確改為建立 issue 時一次帶入標籤,且目前沒有任何呼叫端。保留這個推測未來可能使用的公開函式,會擴大 Gitea client 的 API 面積,讓維護者誤以為存在兩套正式的標籤流程,未來也必須持續維護文件與測試。 **修改建議** 若目前沒有實際使用情境,先移除 `addLabelsToIssue` 與匯出項目;等真正需要對既有 issue 追加標籤時,再連同明確呼叫端與測試一起加入。
Owner

🔴 嚴重|🔮 Mage

位置src/index.js 第 268–268 行

問題描述

舊審查留言仍在本回合結果完整發布前就被標記為過時;一般審查路徑的同類呼叫也出現在約第 343 行。最小重現:先有一輪有效舊 findings,本輪成功完成 AI 裁決後執行 resolveOldComments,接著 postSevereComments、其他問題留言或 commitFindings 因 API/push 暫時失敗;Action 最終回傳失敗,但舊結果已被清除,新結果又只發布一部分或完全未提交。無可審查變更路徑同樣會在 saveFindings 與 push 成功前清除舊結果,違反此次改動宣稱的「成功產生結果後才清除」語義。

修改建議

把清理舊留言移到本輪所有必要結果均成功產生之後:無變更路徑至少先保存並成功提交空 findings;一般路徑先完成所有新留言與必要提交,再清理舊留言。若 push 會觸發下一輪而不能最後執行,應將發布狀態做成可重入的兩階段流程,確保失敗重跑不會留下「舊結果已清除、新結果不完整」的中間狀態。

這個功能的目的是把前一輪 PR 產生的訊息標記為已解決或過時,讓審查人員可以知道那些訊息是舊的,所以不能移到本輪結果產生之後執行,這樣會誤導審查人員

> <!-- ai-code-review --> > ### 🔴 嚴重|🔮 Mage > > **位置**:`src/index.js` 第 268–268 行 > > **問題描述** > > 舊審查留言仍在本回合結果完整發布前就被標記為過時;一般審查路徑的同類呼叫也出現在約第 343 行。最小重現:先有一輪有效舊 findings,本輪成功完成 AI 裁決後執行 `resolveOldComments`,接著 `postSevereComments`、其他問題留言或 `commitFindings` 因 API/push 暫時失敗;Action 最終回傳失敗,但舊結果已被清除,新結果又只發布一部分或完全未提交。無可審查變更路徑同樣會在 `saveFindings` 與 push 成功前清除舊結果,違反此次改動宣稱的「成功產生結果後才清除」語義。 > > **修改建議** > > 把清理舊留言移到本輪所有必要結果均成功產生之後:無變更路徑至少先保存並成功提交空 findings;一般路徑先完成所有新留言與必要提交,再清理舊留言。若 push 會觸發下一輪而不能最後執行,應將發布狀態做成可重入的兩階段流程,確保失敗重跑不會留下「舊結果已清除、新結果不完整」的中間狀態。 這個功能的目的是把前一輪 PR 產生的訊息標記為已解決或過時,讓審查人員可以知道那些訊息是舊的,所以不能移到本輪結果產生之後執行,這樣會誤導審查人員
Member

🔧 AI Code Review 問題處理進度

已依嚴重度逐條處理議題 #8 的 15 條審查問題,修復已提交並推送至分支 ai-review-resolve/develop-20260717-185330(納入既有 PR #6develop)。

統計: 已解決 4 條、⏭️ 待人工處理 10 條、🚫 不採納 1 條。

留言 等級 審查員 位置 處理 說明
#4766 🔴 嚴重 🗡️ Assassin src/lib/gitrepo.js 已解決 帶認證推送改經 GIT_CONFIG_*http.<url>.extraheader(base64 Basic)以 env 傳入、不進 argv,推送 URL 不含帳密;push 失敗改拋固定訊息,避免例外把命令列(含 token)回顯到 CI log
#4775 🟠 警告 Rogue src/lib/review.js 已解決 除錯輸出改為先截 2000 字上限再遮罩(最終仍截 500 字),避免對數 MB 失敗輸出跑整份 O(k×n) 正規掃描
#4779 🔵 建議 🧰 Leo src/lib/gitea.js 已解決 移除無任何呼叫端addLabelsToIssue(含匯出);現行流程已改為建立 issue 時一次帶入標籤
#4777 🔵 建議 🎼 Bard readme.md 已解決 流程圖依實際執行順序重排:「舊留言標記解決」節點移到裁決(步驟 8)之後、發布問題留言之前,標明「延後執行」
#4765 🔴 嚴重 🔮 Mage src/index.js 🚫 不採納 依維護者留言 #4838(系統管理員)裁示:resolveOldComments 用途為標記前一輪舊訊息、刻意在本回合結果前執行,不可延後,否則誤導審查人員。已記入 exclusions.json 以免後續重複提出
#4767 🔴 嚴重 🗡️ Assassin src/lib/review.js ⏭️ 待人工處理 「debug 模式也完全不輸出 AI CLI 原文」屬安全性與可除錯性的政策取捨;現行已刻意保留 debug-gated+遮罩輸出,是否完全移除需維護者裁示
#4768 🟠 警告 🧰 Leo src/index.js ⏭️ 待人工處理 抽出 PrReviewPublisherIssueReviewPublisher 屬大範圍重構+設計取捨
#4769 🟠 警告 🧪 Maya src/index.js ⏭️ 待人工處理 issueBuffer 沖刷主流程測試;專案目前無測試框架/devDependencies
#4770 🟠 警告 🧪 Maya src/index.js ⏭️ 待人工處理 建問題模式分支參數化測試;同測試架構決策
#4771 🟠 警告 🧪 Maya src/lib/gitea.js ⏭️ 待人工處理 相依 API 方向斷言測試;同測試架構決策(addLabelsToIssue 已移除)
#4772 🟠 警告 🧪 Maya src/lib/gitrepo.js ⏭️ 待人工處理 resolveMergeBase 降級路徑測試(需注入 git 執行器);可測性重構+測試架構決策
#4773 🟠 警告 🧪 Maya src/lib/gitrepo.js ⏭️ 待人工處理 pushToken 兩套認證策略測試;同測試架構決策
#4774 🟠 警告 🧪 Maya src/lib/review.js ⏭️ 待人工處理 redactSecrets/agentFailureDetail 單元測試;同測試架構決策
#4776 🔵 建議 🎼 Bard action.yml ⏭️ 待人工處理 push-token 描述精簡屬 doc-funcs 高密度註解慣例取捨,需維護者確認
#4778 🔵 建議 🎼 Bard src/index.js ⏭️ 待人工處理 ensureIssueCreated 重命名與 #4768 的 publisher 重構指向同區、維護者審視中,宜一併處理

⏭️ 待人工處理已寫回 findings 追蹤

10 條待人工處理問題已寫成 findings wrapper 檔 .gitea/ai-review/findings/2026-07-20-15:57:46.jsonF001F010),供後續 review/resolve 追蹤,不會因關閉議題而遺失待辦。

待人工處理共同原因

多數繞不開「專案目前無測試框架/devDependencies/可測性結構」(Maya 六條)或「對核心流程做大範圍重構/安全政策取捨」(Assassin debug 輸出、Leo publisher、Bard 重命名與註解慣例)。皆屬架構決策,依規範不逕自硬加,避免對未經 CI 驗證的核心流程造成回歸。

問題已全部分流: 已修復(4)/🚫 不採納(1,維護者裁示、寫入 exclusions)/⏭️ 待人工處理(10,寫回 findings 追蹤)。依 resolve 流程收尾,關閉本議題。

## 🔧 AI Code Review 問題處理進度 已依嚴重度逐條處理議題 #8 的 15 條審查問題,修復已提交並推送至分支 `ai-review-resolve/develop-20260717-185330`(納入既有 **PR #6** → `develop`)。 **統計:✅ 已解決 4 條、⏭️ 待人工處理 10 條、🚫 不採納 1 條。** | 留言 | 等級 | 審查員 | 位置 | 處理 | 說明 | | --- | --- | --- | --- | --- | --- | | #4766 | 🔴 嚴重 | 🗡️ Assassin | `src/lib/gitrepo.js` | ✅ 已解決 | 帶認證推送改經 `GIT_CONFIG_*`/`http.<url>.extraheader`(base64 Basic)以 **env 傳入、不進 argv**,推送 URL 不含帳密;push 失敗改拋固定訊息,避免例外把命令列(含 token)回顯到 CI log | | #4775 | 🟠 警告 | ⚡ Rogue | `src/lib/review.js` | ✅ 已解決 | 除錯輸出改為**先截 2000 字上限再遮罩**(最終仍截 500 字),避免對數 MB 失敗輸出跑整份 O(k×n) 正規掃描 | | #4779 | 🔵 建議 | 🧰 Leo | `src/lib/gitea.js` | ✅ 已解決 | 移除**無任何呼叫端**的 `addLabelsToIssue`(含匯出);現行流程已改為建立 issue 時一次帶入標籤 | | #4777 | 🔵 建議 | 🎼 Bard | `readme.md` | ✅ 已解決 | 流程圖依實際執行順序重排:「舊留言標記解決」節點移到裁決(步驟 8)之後、發布問題留言之前,標明「延後執行」 | | #4765 | 🔴 嚴重 | 🔮 Mage | `src/index.js` | 🚫 不採納 | 依維護者留言 #4838(系統管理員)裁示:`resolveOldComments` 用途為標記前一輪舊訊息、刻意在本回合結果前執行,**不可延後**,否則誤導審查人員。已記入 `exclusions.json` 以免後續重複提出 | | #4767 | 🔴 嚴重 | 🗡️ Assassin | `src/lib/review.js` | ⏭️ 待人工處理 | 「debug 模式也完全不輸出 AI CLI 原文」屬安全性與可除錯性的政策取捨;現行已刻意保留 debug-gated+遮罩輸出,是否完全移除需維護者裁示 | | #4768 | 🟠 警告 | 🧰 Leo | `src/index.js` | ⏭️ 待人工處理 | 抽出 `PrReviewPublisher`/`IssueReviewPublisher` 屬大範圍重構+設計取捨 | | #4769 | 🟠 警告 | 🧪 Maya | `src/index.js` | ⏭️ 待人工處理 | issueBuffer 沖刷主流程測試;專案目前無測試框架/devDependencies | | #4770 | 🟠 警告 | 🧪 Maya | `src/index.js` | ⏭️ 待人工處理 | 建問題模式分支參數化測試;同測試架構決策 | | #4771 | 🟠 警告 | 🧪 Maya | `src/lib/gitea.js` | ⏭️ 待人工處理 | 相依 API 方向斷言測試;同測試架構決策(addLabelsToIssue 已移除) | | #4772 | 🟠 警告 | 🧪 Maya | `src/lib/gitrepo.js` | ⏭️ 待人工處理 | resolveMergeBase 降級路徑測試(需注入 git 執行器);可測性重構+測試架構決策 | | #4773 | 🟠 警告 | 🧪 Maya | `src/lib/gitrepo.js` | ⏭️ 待人工處理 | pushToken 兩套認證策略測試;同測試架構決策 | | #4774 | 🟠 警告 | 🧪 Maya | `src/lib/review.js` | ⏭️ 待人工處理 | redactSecrets/agentFailureDetail 單元測試;同測試架構決策 | | #4776 | 🔵 建議 | 🎼 Bard | `action.yml` | ⏭️ 待人工處理 | push-token 描述精簡屬 doc-funcs 高密度註解慣例取捨,需維護者確認 | | #4778 | 🔵 建議 | 🎼 Bard | `src/index.js` | ⏭️ 待人工處理 | `ensureIssueCreated` 重命名與 #4768 的 publisher 重構指向同區、維護者審視中,宜一併處理 | ### ⏭️ 待人工處理已寫回 findings 追蹤 10 條待人工處理問題已寫成 findings wrapper 檔 ``.gitea/ai-review/findings/2026-07-20-15:57:46.json``(`F001`–`F010`),供後續 review/resolve 追蹤,不會因關閉議題而遺失待辦。 ### 待人工處理共同原因 多數繞不開「專案目前無測試框架/devDependencies/可測性結構」(Maya 六條)或「對核心流程做大範圍重構/安全政策取捨」(Assassin debug 輸出、Leo publisher、Bard 重命名與註解慣例)。皆屬架構決策,依規範不逕自硬加,避免對未經 CI 驗證的核心流程造成回歸。 > 問題已全部分流:✅ 已修復(4)/🚫 不採納(1,維護者裁示、寫入 exclusions)/⏭️ 待人工處理(10,寫回 findings 追蹤)。依 resolve 流程收尾,關閉本議題。
Sign in to join this conversation.
No labels
3 Participants
Notifications
Due Date
No due date set.
Reference: node-actions/ai-code-review#8