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

Closed
opened 2026-07-21 08:00:33 +00:00 by admin · 10 comments
Owner

變更摘要

本分支持續處理 AI Code Review findings,最新推送新增以下修正:

  • 建問題模式 issue finding 留言改為依序送出,避免 Gitea 非同步寫入造成排序錯亂。
  • 精簡 main() JSDoc,保留職責、模式差異與 exit code 契約,細節留在流程區塊與 README。
  • 重新命名建問題模式狀態:pendingIssueCommentBodiestrackingIssue,降低 PR issue 與追蹤 issue 混淆。
  • 重新命名 PR 回貼模板為 prIssueLinkComment,並釐清 addIssueDependency 的 blocked/blocking issue 參數方向。
  • 收斂 action.yml token 註解,避免 input manifest 承載過多實作細節。
  • README mermaid 流程圖節點改用中性 ID,避免節點 ID 與視覺流程順序衝突。
  • 測試輔助函式 fn 改為 callback,並更新 issue 留言順序測試。
  • 回寫 findings wrapper:本輪移除 15 筆已解決或已排除 findings,剩餘 29 筆皆為警告/建議。

影響範圍

  • src/index.js:建問題模式狀態命名、JSDoc 精簡、PR 回貼模板呼叫。
  • src/lib/review.js:issue finding 留言順序送出。
  • src/lib/gitea.js:issue dependency 參數命名。
  • src/lib/templates.js:PR issue 連結留言模板命名。
  • src/lib/diagnostics.js / test/*.test.js:診斷與測試輔助命名。
  • action.yml / readme.md:manifest 註解與流程圖整理。
  • .gitea/ai-review/findings/*.json:移除本輪已處理 findings。

驗證

  • npm test 通過:10 tests / 0 failed。
  • git diff --check 通過。

風險與注意事項

  • issue 留言改為順序送出,保留閱讀順序,但多筆 findings 時會增加 API 等待時間。
  • 剩餘 findings 未在本輪硬改,包含 README 深連結、手動時間戳、merge-base / push 流程測試與較大的主流程抽象拆分。

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

<!-- ai-code-review --> ## 變更摘要 本分支持續處理 AI Code Review findings,最新推送新增以下修正: - 建問題模式 issue finding 留言改為依序送出,避免 Gitea 非同步寫入造成排序錯亂。 - 精簡 `main()` JSDoc,保留職責、模式差異與 exit code 契約,細節留在流程區塊與 README。 - 重新命名建問題模式狀態:`pendingIssueCommentBodies`、`trackingIssue`,降低 PR issue 與追蹤 issue 混淆。 - 重新命名 PR 回貼模板為 `prIssueLinkComment`,並釐清 `addIssueDependency` 的 blocked/blocking issue 參數方向。 - 收斂 `action.yml` token 註解,避免 input manifest 承載過多實作細節。 - README mermaid 流程圖節點改用中性 ID,避免節點 ID 與視覺流程順序衝突。 - 測試輔助函式 `fn` 改為 `callback`,並更新 issue 留言順序測試。 - 回寫 findings wrapper:本輪移除 15 筆已解決或已排除 findings,剩餘 29 筆皆為警告/建議。 ## 影響範圍 - `src/index.js`:建問題模式狀態命名、JSDoc 精簡、PR 回貼模板呼叫。 - `src/lib/review.js`:issue finding 留言順序送出。 - `src/lib/gitea.js`:issue dependency 參數命名。 - `src/lib/templates.js`:PR issue 連結留言模板命名。 - `src/lib/diagnostics.js` / `test/*.test.js`:診斷與測試輔助命名。 - `action.yml` / `readme.md`:manifest 註解與流程圖整理。 - `.gitea/ai-review/findings/*.json`:移除本輪已處理 findings。 ## 驗證 - `npm test` 通過:10 tests / 0 failed。 - `git diff --check` 通過。 ## 風險與注意事項 - issue 留言改為順序送出,保留閱讀順序,但多筆 findings 時會增加 API 等待時間。 - 剩餘 findings 未在本輪硬改,包含 README 深連結、手動時間戳、merge-base / push 流程測試與較大的主流程抽象拆分。 --- > 本問題由 AI Code Review 依 PR #6 的審查結果自動建立,問題明細見下方留言。
Author
Owner

🤖 AI Code Review|審查工具

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

📋 變更摘要(送審 git diff)

檔案 用途 git diff 長度 最後更新時間
action.yml 定義 Action 介面與執行入口 86 行/3883 字元 2026/07/21 14:39:42
package.json 管理套件資訊與 npm 指令 15 行/417 字元 2026/07/21 13:46:43
readme.md 說明專案用途與使用方式 280 行/23916 字元(過長截斷送審) 2026/07/21 14:39:42
src/index.js 編排 AI Code Review 主流程 428 行/19279 字元(過長截斷送審) 2026/07/21 15:57:53
src/lib/agents.js 偵測並執行 AI CLI 工具 14 行/503 字元 2026/07/20 09:46:12
src/lib/context.js 載入 workflow 執行環境脈絡 15 行/769 字元 2026/07/20 17:24:18
src/lib/diagnostics.js 整理並遮罩 AI 失敗診斷 89 行/3096 字元 2026/07/21 15:57:53
src/lib/gitea.js 封裝 Gitea API 操作 130 行/5824 字元 2026/07/21 14:39:42
src/lib/gitrepo.js 封裝 git 差異與推送操作 275 行/11121 字元 2026/07/21 15:57:53
src/lib/review.js 處理審查流程核心邏輯 576 行/24543 字元(過長截斷送審) 2026/07/21 15:57:53
src/lib/roles.js 載入並分類審查角色設定 14 行/586 字元 2026/07/20 09:46:12
src/lib/templates.js 產生 PR 留言 Markdown 模板 165 行/5978 字元 2026/07/21 14:39:42
test/gitea.test.js 測試 Gitea API 封裝行為 80 行/2220 字元 2026/07/21 14:39:42
test/gitrepo.test.js 測試 git 分支安全檢查 31 行/836 字元 2026/07/21 13:46:43
test/review.test.js 測試審查與診斷輔助邏輯 143 行/4469 字元 2026/07/21 15:57:53

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

<!-- ai-code-review --> ## 📋 變更摘要(送審 git diff) | 檔案 | 用途 | git diff 長度 | 最後更新時間 | | --- | --- | --- | --- | | `action.yml` | 定義 Action 介面與執行入口 | 86 行/3883 字元 | 2026/07/21 14:39:42 | | `package.json` | 管理套件資訊與 npm 指令 | 15 行/417 字元 | 2026/07/21 13:46:43 | | `readme.md` | 說明專案用途與使用方式 | 280 行/23916 字元(過長截斷送審) | 2026/07/21 14:39:42 | | `src/index.js` | 編排 AI Code Review 主流程 | 428 行/19279 字元(過長截斷送審) | 2026/07/21 15:57:53 | | `src/lib/agents.js` | 偵測並執行 AI CLI 工具 | 14 行/503 字元 | 2026/07/20 09:46:12 | | `src/lib/context.js` | 載入 workflow 執行環境脈絡 | 15 行/769 字元 | 2026/07/20 17:24:18 | | `src/lib/diagnostics.js` | 整理並遮罩 AI 失敗診斷 | 89 行/3096 字元 | 2026/07/21 15:57:53 | | `src/lib/gitea.js` | 封裝 Gitea API 操作 | 130 行/5824 字元 | 2026/07/21 14:39:42 | | `src/lib/gitrepo.js` | 封裝 git 差異與推送操作 | 275 行/11121 字元 | 2026/07/21 15:57:53 | | `src/lib/review.js` | 處理審查流程核心邏輯 | 576 行/24543 字元(過長截斷送審) | 2026/07/21 15:57:53 | | `src/lib/roles.js` | 載入並分類審查角色設定 | 14 行/586 字元 | 2026/07/20 09:46:12 | | `src/lib/templates.js` | 產生 PR 留言 Markdown 模板 | 165 行/5978 字元 | 2026/07/21 14:39:42 | | `test/gitea.test.js` | 測試 Gitea API 封裝行為 | 80 行/2220 字元 | 2026/07/21 14:39:42 | | `test/gitrepo.test.js` | 測試 git 分支安全檢查 | 31 行/836 字元 | 2026/07/21 13:46:43 | | `test/review.test.js` | 測試審查與診斷輔助邏輯 | 143 行/4469 字元 | 2026/07/21 15:57:53 | > 共 15 個檔案納入審查;另有 12 個檔案依 `.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

🔴 嚴重|🗡️ Assassin

位置src/index.js 第 105–116 行

問題描述

這裡把審查結果 commit/push 失敗吞掉並回傳 false,而本次變更又把主流程改成「本輪審查不因嚴重問題直接 exit 1,靠下一輪讀到 [failure] commit 才失敗」。攻擊者只要讓結果 commit 推不上去,例如在 PR head 競態推送、讓 token 沒有 push 權限、或讓來源分支拒絕 bot push,就能讓嚴重安全 finding 已產生但沒有 failure commit、也沒有下一輪失敗檢查,等同把必要檢查繞過。

修改建議

嚴重問題存在時,結果 commit/push 失敗必須直接讓本輪 workflow 失敗;只有 success 結果或無變更時才可降級不阻擋。呼叫端應檢查 commitFindings 回傳值,或讓 commitFindingsresult === 'failure' 時重拋錯誤。

建議寫法

const committed = commitFindings({ cwd, ctx, files: filesToCommit, result });
if (result === 'failure' && !committed) {
  log('收尾', 'ERR', '存在嚴重問題,但無法推送 failure 結果 commit;本輪直接失敗以避免繞過檢查。');
  return 1;
}
return 0;
<!-- ai-code-review --> ### 🔴 嚴重|🗡️ Assassin **位置**:`src/index.js` 第 105–116 行 **問題描述** 這裡把審查結果 commit/push 失敗吞掉並回傳 `false`,而本次變更又把主流程改成「本輪審查不因嚴重問題直接 exit 1,靠下一輪讀到 `[failure]` commit 才失敗」。攻擊者只要讓結果 commit 推不上去,例如在 PR head 競態推送、讓 token 沒有 push 權限、或讓來源分支拒絕 bot push,就能讓嚴重安全 finding 已產生但沒有 failure commit、也沒有下一輪失敗檢查,等同把必要檢查繞過。 **修改建議** 嚴重問題存在時,結果 commit/push 失敗必須直接讓本輪 workflow 失敗;只有 success 結果或無變更時才可降級不阻擋。呼叫端應檢查 `commitFindings` 回傳值,或讓 `commitFindings` 在 `result === 'failure'` 時重拋錯誤。 **建議寫法** ``` const committed = commitFindings({ cwd, ctx, files: filesToCommit, result }); if (result === 'failure' && !committed) { log('收尾', 'ERR', '存在嚴重問題,但無法推送 failure 結果 commit;本輪直接失敗以避免繞過檢查。'); return 1; } return 0; ```
Author
Owner

🔵 建議|🎼 Bard

位置action.yml 第 18–19 行

問題描述

中文敘述裡混入 PR/issuefindings/exclusions 這種半形斜線寫法,但同一份變更其他地方大量使用 PR/issue警告+建議 這類全形符號。標點像節拍器,這裡忽然換拍,讓 manifest 的文字風格不夠一致。

修改建議

統一中文文件與註解中的分隔符號,建議在中文語境使用全形斜線:PR/issuefindings/exclusions;若是程式路徑或指令片段才保留半形 /

<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`action.yml` 第 18–19 行 **問題描述** 中文敘述裡混入 `PR/issue`、`findings/exclusions` 這種半形斜線寫法,但同一份變更其他地方大量使用 `PR/issue`、`警告+建議` 這類全形符號。標點像節拍器,這裡忽然換拍,讓 manifest 的文字風格不夠一致。 **修改建議** 統一中文文件與註解中的分隔符號,建議在中文語境使用全形斜線:`PR/issue`、`findings/exclusions`;若是程式路徑或指令片段才保留半形 `/`。
Author
Owner

🔵 建議|🎼 Bard

位置src/lib/gitrepo.js 第 299–344 行

問題描述

pushWithCredential 的 JSDoc 幾乎把安全設計、CI 觸發語意、checkout extraheader 行為全部寫成一篇短文。資訊本身有價值,但集中在函式註解裡會壓過函式簽名,讀者想找參數與責任邊界時,得先穿過一大段敘事。

修改建議

保留函式層級的摘要與關鍵安全不變式,其餘背景可移到較短的段落或專門文件。JSDoc 建議聚焦在「做什麼、為何不能改、參數怎麼用」,避免把完整決策紀錄塞進 API 註解。

<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`src/lib/gitrepo.js` 第 299–344 行 **問題描述** `pushWithCredential` 的 JSDoc 幾乎把安全設計、CI 觸發語意、checkout extraheader 行為全部寫成一篇短文。資訊本身有價值,但集中在函式註解裡會壓過函式簽名,讀者想找參數與責任邊界時,得先穿過一大段敘事。 **修改建議** 保留函式層級的摘要與關鍵安全不變式,其餘背景可移到較短的段落或專門文件。JSDoc 建議聚焦在「做什麼、為何不能改、參數怎麼用」,避免把完整決策紀錄塞進 API 註解。
Author
Owner

🔵 建議|🧰 Leo

位置src/lib/gitrepo.js 第 367–369 行

問題描述

為了測試把內部函式掛在 module.exports.__test,會讓 production module 的公開形狀混入測試專用 API。未來其他程式碼可能誤用 __test.assertSafeBranchRef,而維護者也得在重構時顧慮這個非正式出口,模組邊界會慢慢變模糊。

修改建議

把分支名稱驗證抽到獨立小模組並正常匯出,例如 src/lib/gitref.js,讓 production code 與測試都依賴同一個正式 API;或若它只屬於 gitrepo 內部,就改由測試 resolveMergeBasecommitAndPushFindings 的外部行為覆蓋,不暴露 __test

<!-- ai-code-review --> ### 🔵 建議|🧰 Leo **位置**:`src/lib/gitrepo.js` 第 367–369 行 **問題描述** 為了測試把內部函式掛在 `module.exports.__test`,會讓 production module 的公開形狀混入測試專用 API。未來其他程式碼可能誤用 `__test.assertSafeBranchRef`,而維護者也得在重構時顧慮這個非正式出口,模組邊界會慢慢變模糊。 **修改建議** 把分支名稱驗證抽到獨立小模組並正常匯出,例如 `src/lib/gitref.js`,讓 production code 與測試都依賴同一個正式 API;或若它只屬於 gitrepo 內部,就改由測試 `resolveMergeBase`/`commitAndPushFindings` 的外部行為覆蓋,不暴露 `__test`。
Author
Owner

🔴 嚴重|🗡️ Assassin

位置src/index.js 第 105–116 行

問題描述

這裡把審查結果 commit/push 失敗吞掉並回傳 false,而本次變更又把主流程改成「本輪審查不因嚴重問題直接 exit 1,靠下一輪讀到 [failure] commit 才失敗」。攻擊者只要讓結果 commit 推不上去,例如在 PR head 競態推送、讓 token 沒有 push 權限、或讓來源分支拒絕 bot push,就能讓嚴重安全 finding 已產生但沒有 failure commit、也沒有下一輪失敗檢查,等同把必要檢查繞過。

修改建議

嚴重問題存在時,結果 commit/push 失敗必須直接讓本輪 workflow 失敗;只有 success 結果或無變更時才可降級不阻擋。呼叫端應檢查 commitFindings 回傳值,或讓 commitFindingsresult === 'failure' 時重拋錯誤。

建議寫法

const committed = commitFindings({ cwd, ctx, files: filesToCommit, result });
if (result === 'failure' && !committed) {
  log('收尾', 'ERR', '存在嚴重問題,但無法推送 failure 結果 commit;本輪直接失敗以避免繞過檢查。');
  return 1;
}
return 0;

請把這個問題加入排除事項

> <!-- ai-code-review --> > ### 🔴 嚴重|🗡️ Assassin > > **位置**:`src/index.js` 第 105–116 行 > > **問題描述** > > 這裡把審查結果 commit/push 失敗吞掉並回傳 `false`,而本次變更又把主流程改成「本輪審查不因嚴重問題直接 exit 1,靠下一輪讀到 `[failure]` commit 才失敗」。攻擊者只要讓結果 commit 推不上去,例如在 PR head 競態推送、讓 token 沒有 push 權限、或讓來源分支拒絕 bot push,就能讓嚴重安全 finding 已產生但沒有 failure commit、也沒有下一輪失敗檢查,等同把必要檢查繞過。 > > **修改建議** > > 嚴重問題存在時,結果 commit/push 失敗必須直接讓本輪 workflow 失敗;只有 success 結果或無變更時才可降級不阻擋。呼叫端應檢查 `commitFindings` 回傳值,或讓 `commitFindings` 在 `result === 'failure'` 時重拋錯誤。 > > **建議寫法** > > ``` > const committed = commitFindings({ cwd, ctx, files: filesToCommit, result }); > if (result === 'failure' && !committed) { > log('收尾', 'ERR', '存在嚴重問題,但無法推送 failure 結果 commit;本輪直接失敗以避免繞過檢查。'); > return 1; > } > return 0; > ``` 請把這個問題加入排除事項
Member

本輪 code-review-resolve 處理結果

等級 位置 處理結果
🔴 嚴重 src/index.js 🚫 已依人工裁示寫入 exclusions.json,並從來源 wrapper 移除。理由:現行主流程已在 result === 'failure' && !resultCommitted 時直接回傳 1,此 finding 指向的 fail-open 情境已由既有防線涵蓋。
🔵 建議 action.yml 已修正:中文敘述統一使用 PR/issuefindings/exclusions
🔵 建議 src/lib/gitrepo.js 已修正:精簡 pushWithCredential JSDoc,保留安全不變式與參數責任。
🔵 建議 src/lib/gitrepo.js 已修正:新增正式 src/lib/gitref.js 匯出 assertSafeBranchRef,移除 production module 的 __test 測試出口。

驗證:npm test 通過(11 tests / 0 failed),git diff --check 通過。

來源 wrapper 已回寫:.gitea/ai-review/findings/2026-07-21-16:00:33.json 目前保留 0 筆 finding。

## 本輪 code-review-resolve 處理結果 | 等級 | 位置 | 處理結果 | | --- | --- | --- | | 🔴 嚴重 | `src/index.js` | 🚫 已依人工裁示寫入 `exclusions.json`,並從來源 wrapper 移除。理由:現行主流程已在 `result === 'failure' && !resultCommitted` 時直接回傳 1,此 finding 指向的 fail-open 情境已由既有防線涵蓋。 | | 🔵 建議 | `action.yml` | ✅ 已修正:中文敘述統一使用 `PR/issue`、`findings/exclusions`。 | | 🔵 建議 | `src/lib/gitrepo.js` | ✅ 已修正:精簡 `pushWithCredential` JSDoc,保留安全不變式與參數責任。 | | 🔵 建議 | `src/lib/gitrepo.js` | ✅ 已修正:新增正式 `src/lib/gitref.js` 匯出 `assertSafeBranchRef`,移除 production module 的 `__test` 測試出口。 | 驗證:`npm test` 通過(11 tests / 0 failed),`git diff --check` 通過。 來源 wrapper 已回寫:`.gitea/ai-review/findings/2026-07-21-16:00:33.json` 目前保留 0 筆 finding。
Sign in to join this conversation.
No labels
2 Participants
Notifications
Due Date
No due date set.
Reference: node-actions/ai-code-review#29