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

Closed
opened 2026-07-20 09:32:00 +00:00 by admin · 14 comments
Owner

變更摘要

本 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 的審查結果自動建立,問題明細見下方留言。
Author
Owner

🤖 AI Code Review|審查工具

項目 內容
工具 codex
版本 codex-cli 0.144.6
模型 gpt-5.5
審查 commit b277ff2f7c4b565601d57ce93d346e4735b27ebb
Run Job #37
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` | | 模型 | `gpt-5.5` | | 審查 commit | `b277ff2f7c4b565601d57ce93d346e4735b27ebb` | | Run Job | [#37](https://gitea.jsc.idv.tw/node-actions/ai-code-review/actions/runs/1606) | ```mermaid flowchart LR A[整理 git diff] --> B[⚔️ 攻擊方找問題] B --> C[🛡️ 防守方裁決] C --> D[保存 findings] D --> E[留言到 PR] ```
Author
Owner

📋 變更摘要(送審 git diff)

檔案 用途 git diff 長度 最後更新時間
action.yml 定義 Action 介面與入口 88 行/4025 字元 2026/07/20 17:24:18
readme.md 說明專案用途與使用方式 276 行/23829 字元(過長截斷送審) 2026/07/20 16:01:05
src/index.js 編排 AI 審查主流程 318 行/14222 字元 2026/07/20 17:28:43
src/lib/agents.js 偵測並執行 AI 工具 14 行/503 字元 2026/07/20 09:46:12
src/lib/context.js 載入執行環境與輸入 15 行/769 字元 2026/07/20 17:24:18
src/lib/gitea.js 封裝 Gitea API 操作 121 行/5278 字元 2026/07/20 16:01:05
src/lib/gitrepo.js 處理 Git diff 與提交 209 行/8550 字元 2026/07/20 17:24:18
src/lib/review.js 整理審查結果與裁決 580 行/24901 字元(過長截斷送審) 2026/07/20 16:37:15
src/lib/roles.js 載入與分類審查角色 14 行/586 字元 2026/07/20 09:46:12
src/lib/templates.js 產生 PR 留言模板 165 行/5949 字元 2026/07/20 15:00:32

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

<!-- ai-code-review --> ## 📋 變更摘要(送審 git diff) | 檔案 | 用途 | git diff 長度 | 最後更新時間 | | --- | --- | --- | --- | | `action.yml` | 定義 Action 介面與入口 | 88 行/4025 字元 | 2026/07/20 17:24:18 | | `readme.md` | 說明專案用途與使用方式 | 276 行/23829 字元(過長截斷送審) | 2026/07/20 16:01:05 | | `src/index.js` | 編排 AI 審查主流程 | 318 行/14222 字元 | 2026/07/20 17:28:43 | | `src/lib/agents.js` | 偵測並執行 AI 工具 | 14 行/503 字元 | 2026/07/20 09:46:12 | | `src/lib/context.js` | 載入執行環境與輸入 | 15 行/769 字元 | 2026/07/20 17:24:18 | | `src/lib/gitea.js` | 封裝 Gitea API 操作 | 121 行/5278 字元 | 2026/07/20 16:01:05 | | `src/lib/gitrepo.js` | 處理 Git diff 與提交 | 209 行/8550 字元 | 2026/07/20 17:24:18 | | `src/lib/review.js` | 整理審查結果與裁決 | 580 行/24901 字元(過長截斷送審) | 2026/07/20 16:37:15 | | `src/lib/roles.js` | 載入與分類審查角色 | 14 行/586 字元 | 2026/07/20 09:46:12 | | `src/lib/templates.js` | 產生 PR 留言模板 | 165 行/5949 字元 | 2026/07/20 15:00:32 | > 共 10 個檔案納入審查;另有 7 個檔案依 `.reviewignore` 排除。
Author
Owner

⚔️ 攻擊方登場

角色 面向 個性
🗡️ 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 週期與記憶體,凡事先問「這能不能更快、更省」 |
Author
Owner

🛡️ 防守方登場

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

🔴 嚴重|🔮 Mage

位置src/lib/gitrepo.js 第 140–140 行

問題描述

deepen HEAD 這個補抓策略實際執行的是 git fetch --deepen=1000 origin HEAD,它會補遠端 origin 的預設 HEAD,而不是目前 checkout 的 PR head。最小重現:PR 來自非預設分支或 fork,checkout 為 shallow history,origin/HEAD 指向 develop,目前 HEAD 是 PR 分支 commit;初次 merge-base origin/<baseRef> HEAD 失敗後,此策略只加深預設分支歷史,PR head 的父提交仍不存在,最後仍會丟出「無法解析 merge-base」。這會讓原本可藉由加深 PR head 解決的淺層 checkout 直接審查失敗。

修改建議

不要用 origin HEAD 代表目前 PR head。resolveMergeBase 需要取得可 fetch 的 PR head ref(例如 ctx.headRef/事件 payload ref/head repo remote)並加深該 ref;若只能拿到 headSha,至少應明確診斷「無法加深目前 HEAD」,不要把遠端預設 HEAD 當成修復策略。

建議寫法

// 方向示意:讓呼叫端傳入 headRef,並加深該分支而非 origin HEAD
strategies.push([
  'deepen head',
  'fetch', '--no-tags', '--deepen=1000', 'origin',
  `+refs/heads/${headRef}:refs/remotes/origin/${headRef}`,
]);
<!-- ai-code-review --> ### 🔴 嚴重|🔮 Mage **位置**:`src/lib/gitrepo.js` 第 140–140 行 **問題描述** `deepen HEAD` 這個補抓策略實際執行的是 `git fetch --deepen=1000 origin HEAD`,它會補遠端 `origin` 的預設 HEAD,而不是目前 checkout 的 PR head。最小重現:PR 來自非預設分支或 fork,checkout 為 shallow history,`origin/HEAD` 指向 `develop`,目前 `HEAD` 是 PR 分支 commit;初次 `merge-base origin/<baseRef> HEAD` 失敗後,此策略只加深預設分支歷史,PR head 的父提交仍不存在,最後仍會丟出「無法解析 merge-base」。這會讓原本可藉由加深 PR head 解決的淺層 checkout 直接審查失敗。 **修改建議** 不要用 `origin HEAD` 代表目前 PR head。`resolveMergeBase` 需要取得可 fetch 的 PR head ref(例如 `ctx.headRef`/事件 payload ref/head repo remote)並加深該 ref;若只能拿到 `headSha`,至少應明確診斷「無法加深目前 HEAD」,不要把遠端預設 HEAD 當成修復策略。 **建議寫法** ``` // 方向示意:讓呼叫端傳入 headRef,並加深該分支而非 origin HEAD strategies.push([ 'deepen head', 'fetch', '--no-tags', '--deepen=1000', 'origin', `+refs/heads/${headRef}:refs/remotes/origin/${headRef}`, ]); ```
Author
Owner

🟠 警告|🗡️ Assassin

位置action.yml 第 21–24 行

問題描述

這裡建議呼叫端傳入「能觸發 CI 的 PAT」作為 action token。攻擊者最愛這種長效、可推送、可觸發 workflow 的憑證:只要此 action 在不受信任 PR 上執行,或 PR 能影響 action/workflow 執行內容,惡意變更就可能讀取 INPUT_TOKEN、推送結果 commit、再藉由可觸發 CI 的身分製造後續執行鏈。自動 token 原本不觸發 CI 是一道防線,這個建議等於要求使用者把防線拆掉。

修改建議

不要泛稱建議使用可觸發 CI 的 PAT。文件與介面應明確要求最小權限、repo 限定、短效或可輪替 token,並禁止在 fork/不受信任 PR context 暴露 PAT。更穩的設計是分離 API 留言 token 與 push token,且只有在明確受信任事件或受保護分支才允許 push token 存在;否則拒絕 commit/push,只做留言或 artifact。

<!-- ai-code-review --> ### 🟠 警告|🗡️ Assassin **位置**:`action.yml` 第 21–24 行 **問題描述** 這裡建議呼叫端傳入「能觸發 CI 的 PAT」作為 action token。攻擊者最愛這種長效、可推送、可觸發 workflow 的憑證:只要此 action 在不受信任 PR 上執行,或 PR 能影響 action/workflow 執行內容,惡意變更就可能讀取 `INPUT_TOKEN`、推送結果 commit、再藉由可觸發 CI 的身分製造後續執行鏈。自動 token 原本不觸發 CI 是一道防線,這個建議等於要求使用者把防線拆掉。 **修改建議** 不要泛稱建議使用可觸發 CI 的 PAT。文件與介面應明確要求最小權限、repo 限定、短效或可輪替 token,並禁止在 fork/不受信任 PR context 暴露 PAT。更穩的設計是分離 API 留言 token 與 push token,且只有在明確受信任事件或受保護分支才允許 push token 存在;否則拒絕 commit/push,只做留言或 artifact。
Author
Owner

🟠 警告| Rogue

位置src/lib/gitrepo.js 第 128–130 行

問題描述

這裡在淺層 checkout 找不到 merge-base 時,第一個補救策略就是 git fetch --unshallow origin,等於可能把整個 remote 歷史一次抓回來。大型 repo 或長歷史分支會直接浪費數百 MB 到數 GB 網路與磁碟 I/O,CI 時間也會被偷走;其實多數 PR 只需要有限 deepen 就能找到共同祖先。

修改建議

先做有上限、目標明確的 deepen base/head,仍失敗才把 --unshallow 當最後手段。這樣常見情境只付固定上限成本,不會一失敗就下載全歷史。

建議寫法

const strategies = [
  [
    'deepen base',
    'fetch', '--no-tags', '--deepen=1000', 'origin', `+refs/heads/${baseRef}:refs/remotes/${remoteBase}`,
  ],
  ['deepen HEAD', 'fetch', '--no-tags', '--deepen=1000', 'origin', 'HEAD'],
];
if (gitTrim(cwd, 'rev-parse', '--is-shallow-repository') === 'true') {
  strategies.push(['unshallow', 'fetch', '--no-tags', '--unshallow', 'origin']);
}
<!-- ai-code-review --> ### 🟠 警告|⚡ Rogue **位置**:`src/lib/gitrepo.js` 第 128–130 行 **問題描述** 這裡在淺層 checkout 找不到 merge-base 時,第一個補救策略就是 `git fetch --unshallow origin`,等於可能把整個 remote 歷史一次抓回來。大型 repo 或長歷史分支會直接浪費數百 MB 到數 GB 網路與磁碟 I/O,CI 時間也會被偷走;其實多數 PR 只需要有限 deepen 就能找到共同祖先。 **修改建議** 先做有上限、目標明確的 deepen base/head,仍失敗才把 `--unshallow` 當最後手段。這樣常見情境只付固定上限成本,不會一失敗就下載全歷史。 **建議寫法** ``` const strategies = [ [ 'deepen base', 'fetch', '--no-tags', '--deepen=1000', 'origin', `+refs/heads/${baseRef}:refs/remotes/${remoteBase}`, ], ['deepen HEAD', 'fetch', '--no-tags', '--deepen=1000', 'origin', 'HEAD'], ]; if (gitTrim(cwd, 'rev-parse', '--is-shallow-repository') === 'true') { strategies.push(['unshallow', 'fetch', '--no-tags', '--unshallow', 'origin']); } ```
Author
Owner

🔵 建議|🎼 Bard

位置readme.md 第 42–50 行

問題描述

流程圖的節點 ID 旋律走調了:S1 之後一路走到 S8,才突然接回 S2。雖然顯示文字說明「步驟 2 延後」,但 Mermaid 原始碼的閱讀順序變成倒敘,維護者改圖時很容易在編號與流程方向之間迷路。

修改建議

節點 ID 建議改成語意名稱,讓「顯示的步驟編號」與「Mermaid 內部識別碼」各司其職;延後執行的步驟 2 可命名為 ResolveOld,讀起來會比 S8 --> S2 更順。

建議寫法

flowchart TD
    FastPath[1 判斷 bot commit 標記] -->|命中| Done[直接回報 success/failure]
    FastPath -->|未命中| DetectTool[3 偵測 AI 工具並留言]
    DetectTool --> Diff[4 讀 .reviewignore 整理 diff 並留言]
    Diff --> AttackIntro[5 攻擊方登場留言]
    AttackIntro --> AttackRun[6 攻擊方 sub agent 並行找問題]
    AttackRun --> DefendIntro[7 防守方登場留言]
    DefendIntro --> DefendRun[8 防守方裁決 → 保存 findings + 誤判回寫 exclusions.json]
    DefendRun --> ResolveOld[2 延後將舊留言標記解決(成功產生結果後才執行)]
    ResolveOld --> Severe[9 嚴重問題逐條掛行留言]
    Severe --> Summary[10 警告+建議彙整表格留言]
    Summary --> Finish[收尾 commit/push + exit code]
<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`readme.md` 第 42–50 行 **問題描述** 流程圖的節點 ID 旋律走調了:`S1` 之後一路走到 `S8`,才突然接回 `S2`。雖然顯示文字說明「步驟 2 延後」,但 Mermaid 原始碼的閱讀順序變成倒敘,維護者改圖時很容易在編號與流程方向之間迷路。 **修改建議** 節點 ID 建議改成語意名稱,讓「顯示的步驟編號」與「Mermaid 內部識別碼」各司其職;延後執行的步驟 2 可命名為 `ResolveOld`,讀起來會比 `S8 --> S2` 更順。 **建議寫法** ``` flowchart TD FastPath[1 判斷 bot commit 標記] -->|命中| Done[直接回報 success/failure] FastPath -->|未命中| DetectTool[3 偵測 AI 工具並留言] DetectTool --> Diff[4 讀 .reviewignore 整理 diff 並留言] Diff --> AttackIntro[5 攻擊方登場留言] AttackIntro --> AttackRun[6 攻擊方 sub agent 並行找問題] AttackRun --> DefendIntro[7 防守方登場留言] DefendIntro --> DefendRun[8 防守方裁決 → 保存 findings + 誤判回寫 exclusions.json] DefendRun --> ResolveOld[2 延後將舊留言標記解決(成功產生結果後才執行)] ResolveOld --> Severe[9 嚴重問題逐條掛行留言] Severe --> Summary[10 警告+建議彙整表格留言] Summary --> Finish[收尾 commit/push + exit code] ```
Author
Owner

🔵 建議|🧰 Leo

位置readme.md 第 59–132 行

問題描述

README 的功能列表手動維護了大量 src/branch/develop/...#Lxx 深連結與行號。這次 PR 已經一次改動數十個 branch/line anchor,代表文件和原始碼行號高度耦合;下一次只要插入幾行程式,文件就會悄悄過期,維護者很難知道哪些連結還準。

修改建議

避免在手寫 README 綁定行號,改連到函式所在檔案或穩定章節錨點;若必須保留行號,請把這段改成產生式文件,讓 CI 或腳本從原始碼/JSDoc 重新生成,減少人工同步成本。

<!-- ai-code-review --> ### 🔵 建議|🧰 Leo **位置**:`readme.md` 第 59–132 行 **問題描述** README 的功能列表手動維護了大量 `src/branch/develop/...#Lxx` 深連結與行號。這次 PR 已經一次改動數十個 branch/line anchor,代表文件和原始碼行號高度耦合;下一次只要插入幾行程式,文件就會悄悄過期,維護者很難知道哪些連結還準。 **修改建議** 避免在手寫 README 綁定行號,改連到函式所在檔案或穩定章節錨點;若必須保留行號,請把這段改成產生式文件,讓 CI 或腳本從原始碼/JSDoc 重新生成,減少人工同步成本。
Author
Owner

🔵 建議|🎼 Bard

位置src/index.js 第 181–185 行

問題描述

issue 這個變數名太素,像樂譜上只寫「音符」卻不說是哪一聲部。此處承載的是建問題模式建立出的追蹤 issue,後面還會與 PR issue 編號、Gitea issue API 參數交錯出現,名稱過泛會讓閱讀節奏變濁。

修改建議

改成能表明角色的名稱,例如 trackingIssue。對應的 ensureIssueCreated 也可改為 ensureTrackingIssueCreated,讓閉包狀態與用途一眼對上。

建議寫法

const issueBuffer = [];
let trackingIssue = null;

const postComment = async (body) => {
  if (ctx.createIssue) {
    if (trackingIssue) return gitea.createCommentOnIssue(ctx, trackingIssue.number, body);
    issueBuffer.push(body);
    return null;
  }
  const created = await gitea.createIssueComment(ctx, body);
  currentRunCommentIds.add(created.id);
  return created;
};
<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`src/index.js` 第 181–185 行 **問題描述** `issue` 這個變數名太素,像樂譜上只寫「音符」卻不說是哪一聲部。此處承載的是建問題模式建立出的追蹤 issue,後面還會與 PR issue 編號、Gitea issue API 參數交錯出現,名稱過泛會讓閱讀節奏變濁。 **修改建議** 改成能表明角色的名稱,例如 `trackingIssue`。對應的 `ensureIssueCreated` 也可改為 `ensureTrackingIssueCreated`,讓閉包狀態與用途一眼對上。 **建議寫法** ``` const issueBuffer = []; let trackingIssue = null; const postComment = async (body) => { if (ctx.createIssue) { if (trackingIssue) return gitea.createCommentOnIssue(ctx, trackingIssue.number, body); issueBuffer.push(body); return null; } const created = await gitea.createIssueComment(ctx, body); currentRunCommentIds.add(created.id); return created; }; ```
Author
Owner

🔵 建議|🎼 Bard

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

問題描述

postComment 的命名與實際行為不再押韻:一般模式會立刻留言,但建問題模式在 issue 尚未建立時只是把內容塞進 issueBuffer,回傳 null。函式名唱的是「發布」,實際卻可能只是「暫存」,讀者得進函式內才知道節拍轉了。

修改建議

把名稱改成能涵蓋兩種行為的動詞,例如 queueOrPostCommentpublishReviewComment,並讓 JSDoc 第一行明講「可能暫存」。若想更清楚,也可拆成 postPrCommentqueueIssueComment,由呼叫點明示模式差異。

建議寫法

const queueOrPostComment = async (body) => {
  if (ctx.createIssue) {
    if (trackingIssue) return gitea.createCommentOnIssue(ctx, trackingIssue.number, body);
    issueBuffer.push(body);
    return null;
  }
  const created = await gitea.createIssueComment(ctx, body);
  currentRunCommentIds.add(created.id);
  return created;
};
<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`src/index.js` 第 194–203 行 **問題描述** `postComment` 的命名與實際行為不再押韻:一般模式會立刻留言,但建問題模式在 issue 尚未建立時只是把內容塞進 `issueBuffer`,回傳 `null`。函式名唱的是「發布」,實際卻可能只是「暫存」,讀者得進函式內才知道節拍轉了。 **修改建議** 把名稱改成能涵蓋兩種行為的動詞,例如 `queueOrPostComment` 或 `publishReviewComment`,並讓 JSDoc 第一行明講「可能暫存」。若想更清楚,也可拆成 `postPrComment` 與 `queueIssueComment`,由呼叫點明示模式差異。 **建議寫法** ``` const queueOrPostComment = async (body) => { if (ctx.createIssue) { if (trackingIssue) return gitea.createCommentOnIssue(ctx, trackingIssue.number, body); issueBuffer.push(body); return null; } const created = await gitea.createIssueComment(ctx, body); currentRunCommentIds.add(created.id); return created; }; ```
Author
Owner

🔵 建議|🧰 Leo

位置src/lib/review.js 第 14–75 行

問題描述

review.js 這次新增 redactSecrets()agentFailureDetail(),但這兩個函式處理的是 AI CLI 執行失敗診斷與機密遮罩,責任更接近 agents.js 或共用 log/sanitize 工具。現在審查結果整理模組同時負責 diff、裁決、issue 發文與 CLI 診斷格式,模組邊界越來越鬆;之後其他地方若也要記錄 agent 失敗,很容易複製一份遮罩邏輯或反向依賴 review.js

修改建議

將這兩個函式移到 src/lib/agents.js(例如匯出 formatAgentFailure()),或新增 src/lib/sanitize.js/src/lib/diagnostics.jsreview.js 只消費格式化後的錯誤摘要,避免讓審查編排模組承擔 CLI 診斷細節。

<!-- ai-code-review --> ### 🔵 建議|🧰 Leo **位置**:`src/lib/review.js` 第 14–75 行 **問題描述** `review.js` 這次新增 `redactSecrets()` 與 `agentFailureDetail()`,但這兩個函式處理的是 AI CLI 執行失敗診斷與機密遮罩,責任更接近 `agents.js` 或共用 log/sanitize 工具。現在審查結果整理模組同時負責 diff、裁決、issue 發文與 CLI 診斷格式,模組邊界越來越鬆;之後其他地方若也要記錄 agent 失敗,很容易複製一份遮罩邏輯或反向依賴 `review.js`。 **修改建議** 將這兩個函式移到 `src/lib/agents.js`(例如匯出 `formatAgentFailure()`),或新增 `src/lib/sanitize.js`/`src/lib/diagnostics.js`。`review.js` 只消費格式化後的錯誤摘要,避免讓審查編排模組承擔 CLI 診斷細節。
Author
Owner

🔵 建議|🎼 Bard

位置src/lib/templates.js 第 388–405 行

問題描述

issueLinkComment 產生的是 PR 上唯一的建問題模式回貼留言,但名稱少了 PR 的聲部;同檔已有 issueBodyissueFindingComment,乍看會以為這也是 issue 內留言模板,命名層次不夠分明。

修改建議

改名為 prIssueLinkCommenttrackingIssueLinkComment,讓模板的投遞位置與用途直接寫在名稱裡,避免與 issue 內文、issue finding 留言混成一團。

建議寫法

function prIssueLinkComment({ issueNumber, issueUrl, severeCount, otherCount }) {
  return `${MARK}
## 🔍 AI Code Review|已建立追蹤問題

本次審查結果已彙整到 issue [#${issueNumber}](${issueUrl})(🔴 嚴重 ${severeCount} 條、🟠🔵 警告+建議 ${otherCount} 條),請至該問題追蹤與討論。`;
}
<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`src/lib/templates.js` 第 388–405 行 **問題描述** `issueLinkComment` 產生的是 PR 上唯一的建問題模式回貼留言,但名稱少了 PR 的聲部;同檔已有 `issueBody`、`issueFindingComment`,乍看會以為這也是 issue 內留言模板,命名層次不夠分明。 **修改建議** 改名為 `prIssueLinkComment` 或 `trackingIssueLinkComment`,讓模板的投遞位置與用途直接寫在名稱裡,避免與 issue 內文、issue finding 留言混成一團。 **建議寫法** ``` function prIssueLinkComment({ issueNumber, issueUrl, severeCount, otherCount }) { return `${MARK} ## 🔍 AI Code Review|已建立追蹤問題 本次審查結果已彙整到 issue [#${issueNumber}](${issueUrl})(🔴 嚴重 ${severeCount} 條、🟠🔵 警告+建議 ${otherCount} 條),請至該問題追蹤與討論。`; } ```
Member

🧩 code-review-resolve 處理進度

本議題為 AI Code Review 建問題模式的追蹤議題。以 --issue all 併同 .gitea/ai-review/findings/ 逐條處理後結果如下(對照目前程式碼與 exclusions.json):

# 等級 審查員 位置 處理結果 說明
1 🔴 嚴重 Mage src/lib/gitrepo.js 第 140–140 行 已解決 現行 gitrepo.js 已改用 git rev-parse HEAD 取得 headSha,以 deepen PR HEAD 補抓目前 PR head 歷史,不再用 origin HEAD。
2 🟠 警告 Assassin action.yml 第 21–24 行 ⏭️待人工 action.yml 仍刻意建議傳入能觸發 CI 的 PAT(已載明用途理由),是否分離 push token 與限縮受信任事件屬安全設計取捨,需人工研判。
3 🟠 警告 Rogue src/lib/gitrepo.js 第 128–130 行 已解決 現行策略已先做有上限的 deepen base/PR HEAD,僅在仍失敗且為淺層 repo 時才把 --unshallow 當最後手段。
4 🔵 建議 Bard readme.md 第 42–50 行 🚫誤報 步驟 2 延後執行造成閱讀負擔的指控已列入 exclusions,屬已裁決誤報。
5 🔵 建議 Leo readme.md 第 59–132 行 ⏭️待人工 README 功能表硬編分支名與行號錨點易失準,屬可維護性取捨,skill 規範不得硬改。
6 🔵 建議 Bard src/index.js 第 181–185 行 ⏭️待人工 issue/issueBuffer 變數命名過泛屬風格取捨,不得硬改,需人工判斷是否更名。
7 🔵 建議 Bard src/index.js 第 194–203 行 已解決 現行程式碼已將 postComment 改名為 queueOrPostComment,語義已對齊暫存/發布行為。
8 🔵 建議 Leo src/lib/review.js 第 14–75 行 ⏭️待人工 將 redactSecrets/agentFailureDetail 移出 review.js 屬模組邊界劃分的設計取捨,需人工研判。
9 🔵 建議 Bard src/lib/templates.js 第 388–405 行 ⏭️待人工 issueLinkComment 命名缺 PR 語義屬風格取捨,需人工判斷是否更名。

小計 已解決 3 條、🚫 誤報(已列入 exclusions)1 條、⏭️ 待人工處理 5 條。

⏭️ 待人工處理項目屬設計/效能/慣例取捨(skill 規範不得硬改),已將「只來自議題」的待人工問題(依主題去重)寫回 .gitea/ai-review/findings/2026-07-20-18:31:07.json 追蹤,關閉本議題不會遺失待辦。

  • 已解決:問題於目前程式碼已修復(如 resolveMergeBase 補抓策略調整、deepen PR HEAD 改用 head SHA、留言閉包改名、push-token input 移除等)。
  • 🚫 誤報:與 .gitea/ai-review/exclusions.json 既有裁決等價,不重複新增排除條目。

處理完成,依 code-review-resolve 流程關閉本議題。

<!-- code-review-resolve --> ## 🧩 code-review-resolve 處理進度 本議題為 AI Code Review 建問題模式的追蹤議題。以 `--issue all` 併同 `.gitea/ai-review/findings/` 逐條處理後結果如下(對照目前程式碼與 `exclusions.json`): | # | 等級 | 審查員 | 位置 | 處理結果 | 說明 | | --- | --- | --- | --- | --- | --- | | 1 | 🔴 嚴重 | Mage | `src/lib/gitrepo.js` 第 140–140 行 | ✅已解決 | 現行 gitrepo.js 已改用 git rev-parse HEAD 取得 headSha,以 deepen PR HEAD 補抓目前 PR head 歷史,不再用 origin HEAD。 | | 2 | 🟠 警告 | Assassin | `action.yml` 第 21–24 行 | ⏭️待人工 | action.yml 仍刻意建議傳入能觸發 CI 的 PAT(已載明用途理由),是否分離 push token 與限縮受信任事件屬安全設計取捨,需人工研判。 | | 3 | 🟠 警告 | Rogue | `src/lib/gitrepo.js` 第 128–130 行 | ✅已解決 | 現行策略已先做有上限的 deepen base/PR HEAD,僅在仍失敗且為淺層 repo 時才把 --unshallow 當最後手段。 | | 4 | 🔵 建議 | Bard | `readme.md` 第 42–50 行 | 🚫誤報 | 步驟 2 延後執行造成閱讀負擔的指控已列入 exclusions,屬已裁決誤報。 | | 5 | 🔵 建議 | Leo | `readme.md` 第 59–132 行 | ⏭️待人工 | README 功能表硬編分支名與行號錨點易失準,屬可維護性取捨,skill 規範不得硬改。 | | 6 | 🔵 建議 | Bard | `src/index.js` 第 181–185 行 | ⏭️待人工 | issue/issueBuffer 變數命名過泛屬風格取捨,不得硬改,需人工判斷是否更名。 | | 7 | 🔵 建議 | Bard | `src/index.js` 第 194–203 行 | ✅已解決 | 現行程式碼已將 postComment 改名為 queueOrPostComment,語義已對齊暫存/發布行為。 | | 8 | 🔵 建議 | Leo | `src/lib/review.js` 第 14–75 行 | ⏭️待人工 | 將 redactSecrets/agentFailureDetail 移出 review.js 屬模組邊界劃分的設計取捨,需人工研判。 | | 9 | 🔵 建議 | Bard | `src/lib/templates.js` 第 388–405 行 | ⏭️待人工 | issueLinkComment 命名缺 PR 語義屬風格取捨,需人工判斷是否更名。 | **小計**:✅ 已解決 3 條、🚫 誤報(已列入 exclusions)1 條、⏭️ 待人工處理 5 條。 > ⏭️ 待人工處理項目屬設計/效能/慣例取捨(skill 規範不得硬改),已將「只來自議題」的待人工問題(依主題去重)寫回 `.gitea/ai-review/findings/2026-07-20-18:31:07.json` 追蹤,關閉本議題不會遺失待辦。 - ✅ 已解決:問題於目前程式碼已修復(如 `resolveMergeBase` 補抓策略調整、`deepen PR HEAD` 改用 head SHA、留言閉包改名、`push-token` input 移除等)。 - 🚫 誤報:與 `.gitea/ai-review/exclusions.json` 既有裁決等價,不重複新增排除條目。 處理完成,依 code-review-resolve 流程關閉本議題。
Sign in to join this conversation.
No labels
2 Participants
Notifications
Due Date
No due date set.
Reference: node-actions/ai-code-review#19