feat(ai-review 對話收斂): 讀 PR review 留言判斷解決狀態並收斂 findings #42

Merged
jiantw83 merged 68 commits from ai-review-resolve/20260623-110950 into develop 2026-06-23 08:29:38 +00:00
Member

變更摘要

新增「階段十三:PR 對話收斂」功能。前置驗證通過、且非 AI 助理自動提交後(Step2),讀取 PR 上所有行內 review comment,依「檔案路徑+行號」收斂成對話,對照 PR head 最新程式碼由 AI 判斷各對話指出的問題是否已解決:

  • 已解決的對話 → 以 Gitea 官方 API(POST /repos/{repo}/pulls/comments/{id}/resolve)resolve,並於 Step4findings.json 問題清單移除。
  • 未解決且可解析回 bot finding 者 → 於 Step4 加回問題清單(涵蓋「問題仍在但 findings.json 已遺漏」的情況)。
  • 納入判斷的對話包含所有人的留言;任一外部呼叫失敗都降級為「視為未解決」,不中斷整體流程。

影響範圍與重點檔案

  • app/resolve.js(新增):對話收斂核心。提供 parseBotReviewCommentgroupConversationscodeWindowjudgeConversationsResolvedreconcileConversationsdropResolvedFindingsaddCarriedFindings。移除/加回皆以「檔案路徑+正規化建議內容」為簽章比對,對行號漂移與標點差異穩定,避免重複。
  • app/gitea.js:新增 listPullReviewsgetPullReviewCommentslistAllReviewCommentsresolvePullReviewCommentgetFileContentAtRef(contents API base64 解碼)。
  • app/main.js:以 Step2 呼叫 reconcileConversations,於 Step4 套用 dropResolvedFindings / addCarriedFindings
  • app/resolve.test.js(新增)、app/gitea.test.js(擴充):覆蓋解析、收斂、AI 判斷對齊、resolve/降級、移除/加回去重等情境。
  • README.mdTODO.md:補上流程第 2.5 點與階段十三的說明與驗收紀錄。

風險與注意事項

  • 為降低 token 用量,AI 判斷只送目標行附近的程式碼視窗。
  • resolve / list comments / 取檔案內容 / AI 判斷任一失敗時皆降級為「視為未解決」並繼續流程,不會中斷 action。
  • node --test *.test.js 全數通過。
## 變更摘要 新增「階段十三:PR 對話收斂」功能。前置驗證通過、且非 AI 助理自動提交後(`Step2`),讀取 PR 上所有行內 review comment,依「檔案路徑+行號」收斂成對話,對照 PR head 最新程式碼由 AI 判斷各對話指出的問題是否已解決: - 已解決的對話 → 以 Gitea 官方 API(`POST /repos/{repo}/pulls/comments/{id}/resolve`)resolve,並於 `Step4` 從 `findings.json` 問題清單移除。 - 未解決且可解析回 bot finding 者 → 於 `Step4` 加回問題清單(涵蓋「問題仍在但 `findings.json` 已遺漏」的情況)。 - 納入判斷的對話包含所有人的留言;任一外部呼叫失敗都降級為「視為未解決」,不中斷整體流程。 ## 影響範圍與重點檔案 - `app/resolve.js`(新增):對話收斂核心。提供 `parseBotReviewComment`、`groupConversations`、`codeWindow`、`judgeConversationsResolved`、`reconcileConversations`、`dropResolvedFindings`、`addCarriedFindings`。移除/加回皆以「檔案路徑+正規化建議內容」為簽章比對,對行號漂移與標點差異穩定,避免重複。 - `app/gitea.js`:新增 `listPullReviews`、`getPullReviewComments`、`listAllReviewComments`、`resolvePullReviewComment`、`getFileContentAtRef`(contents API base64 解碼)。 - `app/main.js`:以 `Step2` 呼叫 `reconcileConversations`,於 `Step4` 套用 `dropResolvedFindings` / `addCarriedFindings`。 - `app/resolve.test.js`(新增)、`app/gitea.test.js`(擴充):覆蓋解析、收斂、AI 判斷對齊、resolve/降級、移除/加回去重等情境。 - `README.md`、`TODO.md`:補上流程第 2.5 點與階段十三的說明與驗收紀錄。 ## 風險與注意事項 - 為降低 token 用量,AI 判斷只送目標行附近的程式碼視窗。 - resolve / list comments / 取檔案內容 / AI 判斷任一失敗時皆降級為「視為未解決」並繼續流程,不會中斷 action。 - `node --test *.test.js` 全數通過。
jiantw83 added 3 commits 2026-06-23 03:13:56 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:gemini 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:gemini 模型:gemini-2.5-flash
admin reviewed 2026-06-23 03:16:44 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議
舊問題 0 筆 0 筆 0 筆
新問題 3 筆 5 筆 1 筆
## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | | --- | --- | --- | --- | | 舊問題 | 0 筆 | 0 筆 | 0 筆 | | 新問題 | 3 筆 | 5 筆 | 1 筆 |
@@ -0,0 +37,4 @@
level: level || 'warning',
role: role || 'AI Review',
problem: problem || '',
suggestion: suggestion || problem || '',
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 parseBotReviewComment 缺少對 levelRaw 為空但其他欄位存在時的測試案例。程式碼有 level: level || 'warning' 處理,但此行為應被明確驗證。
建議:請新增測試案例,模擬評論內文缺少 嚴重等級等級 欄位,但有 審查員問題/建議 欄位時,確認 level 會正確地預設為 warning

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `parseBotReviewComment` 缺少對 `levelRaw` 為空但其他欄位存在時的測試案例。程式碼有 `level: level || 'warning'` 處理,但此行為應被明確驗證。 **建議**:請新增測試案例,模擬評論內文缺少 `嚴重等級` 或 `等級` 欄位,但有 `審查員` 和 `問題`/`建議` 欄位時,確認 `level` 會正確地預設為 `warning`。
admin marked this conversation as resolved
@@ -0,0 +38,4 @@
role: role || 'AI Review',
problem: problem || '',
suggestion: suggestion || problem || '',
};
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 parseBotReviewComment 缺少對 problem 存在但 suggestion 為空字串的測試案例。程式碼有 suggestion: suggestion || problem || '' 處理,但此行為應被明確驗證。
建議:請新增測試案例,模擬評論內文只包含 問題 欄位而無 建議 欄位時,確認 suggestion 會正確地使用 problem 的內容。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `parseBotReviewComment` 缺少對 `problem` 存在但 `suggestion` 為空字串的測試案例。程式碼有 `suggestion: suggestion || problem || ''` 處理,但此行為應被明確驗證。 **建議**:請新增測試案例,模擬評論內文只包含 `問題` 欄位而無 `建議` 欄位時,確認 `suggestion` 會正確地使用 `problem` 的內容。
admin marked this conversation as resolved
@@ -0,0 +67,4 @@
return [...groups.values()].map(g => ({ ...g, thread: g.bodies.join('\n---\n') }));
}
/** 取目標行附近的程式碼片段(含行號),讓 AI 對照判斷問題是否已解決。 */
Owner

嚴重等級🔵 建議
審查員:Mage
問題:在 groupConversations 函式中,若行內 review comment 缺乏 pathposition/original_position 資訊,它們將會被歸類到一個共同的 key (例如 |0)。這可能導致多個實際上不相關的、缺乏位置資訊的留言被錯誤地歸類為同一個對話群組。雖然這類留言通常不屬於「行內」評論,且 parseBotReviewComment 可能會將其視為非 bot 留言,但這種歸類方式可能與預期不符。
建議:考慮是否應明確地過濾掉缺乏 path 或有效 position 的留言,或為這些留言提供一個更具區分性的預設 key,以避免不相關的留言被意外地歸併。例如,可以在迴圈開始時增加判斷:if (!c?.path || (!c?.position && !c?.original_position)) continue;

**嚴重等級**:🔵 建議 **審查員**:Mage **問題**:在 `groupConversations` 函式中,若行內 review comment 缺乏 `path` 或 `position`/`original_position` 資訊,它們將會被歸類到一個共同的 `key` (例如 `|0`)。這可能導致多個實際上不相關的、缺乏位置資訊的留言被錯誤地歸類為同一個對話群組。雖然這類留言通常不屬於「行內」評論,且 `parseBotReviewComment` 可能會將其視為非 bot 留言,但這種歸類方式可能與預期不符。 **建議**:考慮是否應明確地過濾掉缺乏 `path` 或有效 `position` 的留言,或為這些留言提供一個更具區分性的預設 `key`,以避免不相關的留言被意外地歸併。例如,可以在迴圈開始時增加判斷:`if (!c?.path || (!c?.position && !c?.original_position)) continue;`。
admin marked this conversation as resolved
@@ -0,0 +87,4 @@
const payload = items.map(it => ({ idx: it.idx, path: it.path, line: it.line, thread: it.thread, code: it.code }));
const result = await chatFn(systemPrompt, JSON.stringify(payload));
const byIdx = new Map(
(Array.isArray(result) ? result : [])
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 judgeConversationsResolved 缺少對 chatFn 拋出錯誤情境的測試。雖然上層呼叫者有處理,但此函式本身的錯誤行為應被驗證。
建議:請新增測試案例,模擬 chatFn 拋出錯誤時,確認 judgeConversationsResolved 會正確地將錯誤向上拋出,以便呼叫者處理。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `judgeConversationsResolved` 缺少對 `chatFn` 拋出錯誤情境的測試。雖然上層呼叫者有處理,但此函式本身的錯誤行為應被驗證。 **建議**:請新增測試案例,模擬 `chatFn` 拋出錯誤時,確認 `judgeConversationsResolved` 會正確地將錯誤向上拋出,以便呼叫者處理。
admin marked this conversation as resolved
@@ -0,0 +88,4 @@
const result = await chatFn(systemPrompt, JSON.stringify(payload));
const byIdx = new Map(
(Array.isArray(result) ? result : [])
.filter(r => Number.isInteger(r?.idx))
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 judgeConversationsResolved 缺少對 AI 回傳結果中元素缺少 idxresolved 欄位的測試案例。雖然程式碼有過濾處理,但此邊界條件應被明確驗證。
建議:請新增測試案例,模擬 chatFn 回傳的陣列中,有些物件缺少 idxresolved 屬性時,確認這些無效的結果會被正確過濾,且其他有效結果能被正確處理。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `judgeConversationsResolved` 缺少對 AI 回傳結果中元素缺少 `idx` 或 `resolved` 欄位的測試案例。雖然程式碼有過濾處理,但此邊界條件應被明確驗證。 **建議**:請新增測試案例,模擬 `chatFn` 回傳的陣列中,有些物件缺少 `idx` 或 `resolved` 屬性時,確認這些無效的結果會被正確過濾,且其他有效結果能被正確處理。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +129,4 @@
line(`對話收斂: 對話總數=${conversations.length} 已解決/不可處理=${alreadyResolved} 待判斷=${open.length}`);
if (open.length === 0) return { ...EMPTY };
const fileCache = new Map();
Owner

嚴重等級🔴 嚴重
審查員:Maya
問題:函式 reconcileConversations 在取得單一檔案內容 (getFileContent) 失敗時,會中斷整個對話收斂流程。這會導致即使只有一個檔案出錯,整個 PR 的收斂都無法完成。
建議:請修改 reconcileConversations,在 fileCache.set(filePath, await getFileContent(filePath)) 的迴圈中,為 getFileContent 加上 try-catch 區塊。當單一檔案取得失敗時,應記錄警告並將該檔案的內容視為空字串,而不是中斷整個流程,以確保其他檔案的處理不受影響。

**嚴重等級**:🔴 嚴重 **審查員**:Maya **問題**:函式 `reconcileConversations` 在取得單一檔案內容 (`getFileContent`) 失敗時,會中斷整個對話收斂流程。這會導致即使只有一個檔案出錯,整個 PR 的收斂都無法完成。 **建議**:請修改 `reconcileConversations`,在 `fileCache.set(filePath, await getFileContent(filePath))` 的迴圈中,為 `getFileContent` 加上 `try-catch` 區塊。當單一檔案取得失敗時,應記錄警告並將該檔案的內容視為空字串,而不是中斷整個流程,以確保其他檔案的處理不受影響。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +141,4 @@
thread: c.thread,
code: codeWindow(fileCache.get(c.path) || '', c.line),
}));
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 reconcileConversations 缺少對 judge 拋出錯誤情境的明確測試。雖然程式碼有 try-catch 處理,但應有專門的測試案例來驗證此失敗路徑的行為。
建議:請新增測試案例,模擬 judge 函式拋出錯誤時,確認 reconcileConversations 能正確捕獲錯誤,記錄警告,並將所有待判斷的對話都視為未解決(即 verdicts 應全部為 resolved: false)。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `reconcileConversations` 缺少對 `judge` 拋出錯誤情境的明確測試。雖然程式碼有 `try-catch` 處理,但應有專門的測試案例來驗證此失敗路徑的行為。 **建議**:請新增測試案例,模擬 `judge` 函式拋出錯誤時,確認 `reconcileConversations` 能正確捕獲錯誤,記錄警告,並將所有待判斷的對話都視為未解決(即 `verdicts` 應全部為 `resolved: false`)。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +151,4 @@
}
const resolvedSet = new Set(verdicts.filter(v => v.resolved).map(v => v.idx));
const resolvedFindings = [];
Owner

嚴重等級🔴 嚴重
審查員:Rogue
問題:這裡又在浪費時間!reconcileConversations 函式在取得所有獨特的檔案路徑後,又在迴圈裡對每個檔案路徑依序呼叫 getFileContent。如果有很多檔案需要檢查,這會導致 F 次遠端 API 呼叫依序執行,嚴重拖慢整體流程。
建議:改用 Promise.allPromise.allSettled 來並行發送所有 getFileContent 的請求。這樣可以大幅減少等待時間,讓檔案內容的取得幾乎同時完成。

**嚴重等級**:🔴 嚴重 **審查員**:Rogue **問題**:這裡又在浪費時間!`reconcileConversations` 函式在取得所有獨特的檔案路徑後,又在迴圈裡對每個檔案路徑依序呼叫 `getFileContent`。如果有很多檔案需要檢查,這會導致 `F` 次遠端 API 呼叫依序執行,嚴重拖慢整體流程。 **建議**:改用 `Promise.all` 或 `Promise.allSettled` 來並行發送所有 `getFileContent` 的請求。這樣可以大幅減少等待時間,讓檔案內容的取得幾乎同時完成。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +170,4 @@
pushCarried(carriedFindings, c);
}
const unresolvedCount = open.length - resolvedCount;
Owner

嚴重等級🔴 嚴重
審查員:Rogue
問題:又來了!reconcileConversations 函式在迴圈裡對每個需要解決的對話依序呼叫 resolveComment。這又是一個 N+1 查詢問題,如果有很多對話需要解決,會導致 N_open 次遠端 API 呼叫依序執行,效率極差。
建議:改用 Promise.allSettled 來並行發送所有 resolveComment 的請求。這樣可以大幅減少等待時間,讓對話的解決幾乎同時完成,即使部分失敗也不會中斷其他請求。

**嚴重等級**:🔴 嚴重 **審查員**:Rogue **問題**:又來了!`reconcileConversations` 函式在迴圈裡對每個需要解決的對話依序呼叫 `resolveComment`。這又是一個 N+1 查詢問題,如果有很多對話需要解決,會導致 `N_open` 次遠端 API 呼叫依序執行,效率極差。 **建議**:改用 `Promise.allSettled` 來並行發送所有 `resolveComment` 的請求。這樣可以大幅減少等待時間,讓對話的解決幾乎同時完成,即使部分失敗也不會中斷其他請求。
admin marked this conversation as resolved
admin added 1 commit 2026-06-23 03:16:47 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 5s
7af84900b0
jiantw83 added 3 commits 2026-06-23 03:30:33 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:gemini 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:gemini 模型:gemini-2.5-flash
admin reviewed 2026-06-23 03:33:16 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議
舊問題 0 筆 0 筆 1 筆
新問題 2 筆 2 筆 0 筆
## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | | --- | --- | --- | --- | | 舊問題 | 0 筆 | 0 筆 | 1 筆 | | 新問題 | 2 筆 | 2 筆 | 0 筆 |
app/resolve.js Outdated
@@ -0,0 +49,4 @@
const groups = new Map();
for (const c of comments || []) {
const filePath = typeof c?.path === 'string' ? c.path : '';
if (!filePath) continue; // 無檔案路徑的留言無法定位,跳過以免併入共用群組
Owner

嚴重等級🟡 警告
審查員:Assassin
問題:在 parseBotReviewComment 函式中,從 Gitea comment 內文解析出的 problemsuggestion 欄位,若包含惡意 HTML 或 JavaScript 程式碼,且這些內容在後續的處理或顯示中未經適當的輸出編碼,可能導致跨網站指令碼(XSS)攻擊。
建議:確保所有從外部來源解析出的字串(特別是 problemsuggestion)在任何將其渲染到網頁或其他使用者介面的地方,都必須經過嚴格的上下文相關輸出編碼(例如 HTML 實體編碼、JavaScript 字串編碼等),以防止 XSS 攻擊。

**嚴重等級**:🟡 警告 **審查員**:Assassin **問題**:在 `parseBotReviewComment` 函式中,從 Gitea comment 內文解析出的 `problem` 和 `suggestion` 欄位,若包含惡意 HTML 或 JavaScript 程式碼,且這些內容在後續的處理或顯示中未經適當的輸出編碼,可能導致跨網站指令碼(XSS)攻擊。 **建議**:確保所有從外部來源解析出的字串(特別是 `problem` 和 `suggestion`)在任何將其渲染到網頁或其他使用者介面的地方,都必須經過嚴格的上下文相關輸出編碼(例如 HTML 實體編碼、JavaScript 字串編碼等),以防止 XSS 攻擊。
admin marked this conversation as resolved
@@ -0,0 +67,4 @@
}
return [...groups.values()].map(g => ({ ...g, thread: g.bodies.join('\n---\n') }));
}
Owner

嚴重等級🔵 建議
審查員:Mage
問題:在 groupConversations 函式中,若行內 review comment 缺乏 pathposition/original_position 資訊,它們將會被歸類到一個共同的 key (例如 |0)。這可能導致多個實際上不相關的、缺乏位置資訊的留言被錯誤地歸類為同一個對話群組。雖然這類留言通常不屬於「行內」評論,且 parseBotReviewComment 可能會將其視為非 bot 留言,但這種歸類方式可能與預期不符。
建議:考慮是否應明確地過濾掉缺乏 path 或有效 position 的留言,或為這些留言提供一個更具區分性的預設 key,以避免不相關的留言被意外地歸併。例如,可以在迴圈開始時增加判斷:if (!c?.path || (!c?.position && !c?.original_position)) continue;

**嚴重等級**:🔵 建議 **審查員**:Mage **問題**:在 `groupConversations` 函式中,若行內 review comment 缺乏 `path` 或 `position`/`original_position` 資訊,它們將會被歸類到一個共同的 `key` (例如 `|0`)。這可能導致多個實際上不相關的、缺乏位置資訊的留言被錯誤地歸類為同一個對話群組。雖然這類留言通常不屬於「行內」評論,且 `parseBotReviewComment` 可能會將其視為非 bot 留言,但這種歸類方式可能與預期不符。 **建議**:考慮是否應明確地過濾掉缺乏 `path` 或有效 `position` 的留言,或為這些留言提供一個更具區分性的預設 `key`,以避免不相關的留言被意外地歸併。例如,可以在迴圈開始時增加判斷:`if (!c?.path || (!c?.position && !c?.original_position)) continue;`。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +142,4 @@
}
}));
const items = open.map((c, idx) => ({
Owner

嚴重等級🔴 嚴重
審查員:Assassin
問題:在 judgeConversationsResolved 函式中,thread(來自 Gitea comment 內容)和 code(來自 PR 檔案內容)被直接拼接進傳給 LLM 的 payload 中。如果攻擊者能夠控制這些內容,他們可以透過注入惡意指令來劫持 LLM 的行為,例如使其始終將特定問題判斷為已解決,或嘗試從 LLM 獲取敏感資訊(提示詞注入)。
建議:對所有傳遞給 LLM 的外部輸入(如 threadcode)進行嚴格的淨化和隔離。考慮使用結構化輸入而非直接拼接字串,並在 LLM 提示詞中明確指示其忽略任何試圖改變其行為的指令。對於敏感操作,應建立多層驗證機制,不單純依賴 LLM 的判斷。

**嚴重等級**:🔴 嚴重 **審查員**:Assassin **問題**:在 `judgeConversationsResolved` 函式中,`thread`(來自 Gitea comment 內容)和 `code`(來自 PR 檔案內容)被直接拼接進傳給 LLM 的 `payload` 中。如果攻擊者能夠控制這些內容,他們可以透過注入惡意指令來劫持 LLM 的行為,例如使其始終將特定問題判斷為已解決,或嘗試從 LLM 獲取敏感資訊(提示詞注入)。 **建議**:對所有傳遞給 LLM 的外部輸入(如 `thread` 和 `code`)進行嚴格的淨化和隔離。考慮使用結構化輸入而非直接拼接字串,並在 LLM 提示詞中明確指示其忽略任何試圖改變其行為的指令。對於敏感操作,應建立多層驗證機制,不單純依賴 LLM 的判斷。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +177,4 @@
const c = open[i];
const outcome = resolveOutcome.get(i);
if (outcome?.status === 'fulfilled') {
resolvedCount += 1;
Owner

嚴重等級🔴 嚴重
審查員:Assassin
問題:在 reconcileConversations 函式中,從外部 Gitea comment 取得的 c.path(檔案路徑)未經額外驗證或淨化,直接傳遞給了 getFileContent(即 getFileContentAtRef)。由於 getFileContentAtRef 存在路徑穿越漏洞,攻擊者可以透過在 PR 中建立惡意檔案名稱,並在該檔案上留言,來觸發路徑穿越,讀取伺服器上的任意檔案。
建議:在將 c.path 傳遞給 getFileContent 之前,必須對其進行嚴格的白名單驗證,確保它只包含預期的檔案名稱字元,且不包含任何路徑穿越序列(例如 ../)。或者,確保 getFileContentAtRef 的路徑處理是絕對安全的,不允許任何形式的路徑穿越。

**嚴重等級**:🔴 嚴重 **審查員**:Assassin **問題**:在 `reconcileConversations` 函式中,從外部 Gitea comment 取得的 `c.path`(檔案路徑)未經額外驗證或淨化,直接傳遞給了 `getFileContent`(即 `getFileContentAtRef`)。由於 `getFileContentAtRef` 存在路徑穿越漏洞,攻擊者可以透過在 PR 中建立惡意檔案名稱,並在該檔案上留言,來觸發路徑穿越,讀取伺服器上的任意檔案。 **建議**:在將 `c.path` 傳遞給 `getFileContent` 之前,必須對其進行嚴格的白名單驗證,確保它只包含預期的檔案名稱字元,且不包含任何路徑穿越序列(例如 `..` 或 `/`)。或者,確保 `getFileContentAtRef` 的路徑處理是絕對安全的,不允許任何形式的路徑穿越。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +204,4 @@
.trim()
.toLowerCase();
}
Owner

嚴重等級🟡 警告
審查員:Leo
問題:函式 normalizeKey 對建議內容進行了非常積極的正規化,移除了所有標點符號、符號和空白字元。雖然這有助於避免行號漂移和微小措辭差異造成的重複判斷,但過度正規化可能會導致不同但語意相近的建議被視為相同,進而影響問題追蹤的精確性。
建議:請評估這種積極正規化是否會導致誤判。如果發現有不同建議被錯誤合併的情況,可以考慮放寬正規化規則,例如只移除空白字元和部分標點符號,或加入其他判斷維度(如關鍵字比對)來提高精確度。

**嚴重等級**:🟡 警告 **審查員**:Leo **問題**:函式 `normalizeKey` 對建議內容進行了非常積極的正規化,移除了所有標點符號、符號和空白字元。雖然這有助於避免行號漂移和微小措辭差異造成的重複判斷,但過度正規化可能會導致不同但語意相近的建議被視為相同,進而影響問題追蹤的精確性。 **建議**:請評估這種積極正規化是否會導致誤判。如果發現有不同建議被錯誤合併的情況,可以考慮放寬正規化規則,例如只移除空白字元和部分標點符號,或加入其他判斷維度(如關鍵字比對)來提高精確度。
admin marked this conversation as resolved
admin added 1 commit 2026-06-23 03:33:18 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 4s
980f45308d
jiantw83 added 1 commit 2026-06-23 03:37:38 +00:00
將 AI 助理改為 OpenCode
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 39s
0cddd0976f
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 03:38:19 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議
舊問題 1 筆 0 筆 0 筆
新問題 2 筆 8 筆 4 筆
## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | | --- | --- | --- | --- | | 舊問題 | 1 筆 | 0 筆 | 0 筆 | | 新問題 | 2 筆 | 8 筆 | 4 筆 |
app/resolve.js Outdated
@@ -0,0 +5,4 @@
const EMPTY = { resolvedFindings: [], carriedFindings: [], resolvedCount: 0, unresolvedCount: 0 };
/** 取出 "**label**value" 這一行的 value(單行)。 */
function fieldValue(body, label) {
Owner

嚴重等級🔵 建議
審查員:Bard
問題:RegExp 在函式內部重複建立,造成不必要的效能損耗。
建議:將正則表達式移至函式外部宣告為常數。

**嚴重等級**:🔵 建議 **審查員**:Bard **問題**:RegExp 在函式內部重複建立,造成不必要的效能損耗。 **建議**:將正則表達式移至函式外部宣告為常數。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +15,4 @@
if (raw.includes('嚴重')) return 'critical';
if (raw.includes('警告')) return 'warning';
if (raw.includes('建議')) return 'info';
return null;
Owner

嚴重等級🟡 警告
審查員:Assassin
問題:函式 parseBotReviewComment 動態產生正規表達式,且輸入來源 body 為外部輸入,存在 Regex Injection 風險。
建議:將正規表達式改為靜態定義,並透過 String.raw 或更安全的字串處理方式來匹配標籤,確保輸入不包含特殊 regex 字元。

**嚴重等級**:🟡 警告 **審查員**:Assassin **問題**:函式 `parseBotReviewComment` 動態產生正規表達式,且輸入來源 `body` 為外部輸入,存在 Regex Injection 風險。 **建議**:將正規表達式改為靜態定義,並透過 `String.raw` 或更安全的字串處理方式來匹配標籤,確保輸入不包含特殊 regex 字元。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +49,4 @@
const groups = new Map();
for (const c of comments || []) {
const filePath = typeof c?.path === 'string' ? c.path : '';
if (!filePath) continue; // 無檔案路徑的留言無法定位,跳過以免併入共用群組
Owner

嚴重等級🟡 警告
審查員:Assassin
問題:在 parseBotReviewComment 函式中,從 Gitea comment 內文解析出的 problemsuggestion 欄位若包含惡意內容且未經適當輸出編碼,可能導致 XSS 攻擊。
建議:確保所有從外部來源解析出的字串在渲染到任何介面時,都必須經過嚴格的上下文相關輸出編碼(例如 HTML 實體編碼),以防止 XSS 攻擊。

**嚴重等級**:🟡 警告 **審查員**:Assassin **問題**:在 `parseBotReviewComment` 函式中,從 Gitea comment 內文解析出的 `problem` 和 `suggestion` 欄位若包含惡意內容且未經適當輸出編碼,可能導致 XSS 攻擊。 **建議**:確保所有從外部來源解析出的字串在渲染到任何介面時,都必須經過嚴格的上下文相關輸出編碼(例如 HTML 實體編碼),以防止 XSS 攻擊。
admin marked this conversation as resolved
@@ -0,0 +67,4 @@
}
return [...groups.values()].map(g => ({ ...g, thread: g.bodies.join('\n---\n') }));
}
Owner

嚴重等級🔵 建議
審查員:Mage
問題:缺乏位置資訊的留言會被歸類到同一個預設 key,可能導致不相關留言被錯誤歸併。
建議:明確過濾缺乏 pathposition 的留言,或提供更具區分性的預設 key。

**嚴重等級**:🔵 建議 **審查員**:Mage **問題**:缺乏位置資訊的留言會被歸類到同一個預設 key,可能導致不相關留言被錯誤歸併。 **建議**:明確過濾缺乏 `path` 或 `position` 的留言,或提供更具區分性的預設 key。
admin marked this conversation as resolved
@@ -0,0 +74,4 @@
const lines = content.split('\n');
const center = Number.isFinite(lineNum) && lineNum > 0 ? lineNum - 1 : 0;
const start = Math.max(0, center - radius);
const end = Math.min(lines.length, center + radius + 1);
Owner

嚴重等級🔴 嚴重
審查員:Mage
問題:在 judgeConversationsResolved 函式中,對 chatFn 的結果結構缺乏足夠的嚴格檢查。若回傳結構不符合預期,可能導致所有對話被錯誤判定為「未解決」。
建議:增加對 result 結構的嚴格檢查。如果 result 不是預期的陣列結構,應拋出例外或進行更謹慎的錯誤處理,而不是默默地將所有對話視為未解決。

**嚴重等級**:🔴 嚴重 **審查員**:Mage **問題**:在 `judgeConversationsResolved` 函式中,對 `chatFn` 的結果結構缺乏足夠的嚴格檢查。若回傳結構不符合預期,可能導致所有對話被錯誤判定為「未解決」。 **建議**:增加對 `result` 結構的嚴格檢查。如果 `result` 不是預期的陣列結構,應拋出例外或進行更謹慎的錯誤處理,而不是默默地將所有對話視為未解決。
Owner

嚴重等級🟡 警告
審查員:Leo
問題:程式碼片段定位邏輯(如字串拼接行號)與上下文擷取策略(如 radius)寫死在函式內,擴展性與維護性不足。
建議:建立明確的 Location 物件封裝定位資訊,並將 radius 或擷取策略抽離為配置參數或常數。

**嚴重等級**:🟡 警告 **審查員**:Leo **問題**:程式碼片段定位邏輯(如字串拼接行號)與上下文擷取策略(如 radius)寫死在函式內,擴展性與維護性不足。 **建議**:建立明確的 `Location` 物件封裝定位資訊,並將 `radius` 或擷取策略抽離為配置參數或常數。
Owner

嚴重等級🟡 警告
審查員:Rogue
問題:大量使用字串拼接產生暫存物件,以及並行請求未限制數量,在高負載下可能導致 GC 壓力或觸發 API 限流。
建議:對於大量 comments,考慮使用複合物件或分層 Map 結構。引入請求並行限制(如 p-limit)來確保系統穩定性。

**嚴重等級**:🟡 警告 **審查員**:Rogue **問題**:大量使用字串拼接產生暫存物件,以及並行請求未限制數量,在高負載下可能導致 GC 壓力或觸發 API 限流。 **建議**:對於大量 comments,考慮使用複合物件或分層 Map 結構。引入請求並行限制(如 `p-limit`)來確保系統穩定性。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +141,4 @@
fileCache.set(filePath, '');
}
}));
Owner

嚴重等級🟡 警告
審查員:Maya
問題:缺少關鍵邊界條件與異常路徑的測試案例。包含 judge 拋出錯誤、chatFn 解析異常、levelRawsuggestion 空值、getFileContent 失敗以及混合正確/錯誤的判斷數據等場景。
建議:請在 app/resolve.test.js 中新增這些邊界條件的測試案例,確保系統在面對 AI 異常輸出、API 失敗、或輸入欄位缺失時,仍能穩健處理並符合預期行為。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:缺少關鍵邊界條件與異常路徑的測試案例。包含 `judge` 拋出錯誤、`chatFn` 解析異常、`levelRaw` 或 `suggestion` 空值、`getFileContent` 失敗以及混合正確/錯誤的判斷數據等場景。 **建議**:請在 `app/resolve.test.js` 中新增這些邊界條件的測試案例,確保系統在面對 AI 異常輸出、API 失敗、或輸入欄位缺失時,仍能穩健處理並符合預期行為。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +142,4 @@
}
}));
const items = open.map((c, idx) => ({
Owner

嚴重等級🔴 嚴重
審查員:Assassin
問題:LLM 提示詞注入風險:在 judgeConversationsResolved 函式中,外部來源的 threadcode 被直接拼接進傳給 LLM 的 payload 中,攻擊者可能注入惡意指令來劫持 LLM 行為。
建議:對所有傳遞給 LLM 的外部輸入進行嚴格的淨化和隔離。使用結構化輸入而非直接拼接字串,並在提示詞中明確指示 AI 忽略任何試圖下達指令的內容,僅對邏輯進行判斷。對於敏感操作,應建立多層驗證機制。

**嚴重等級**:🔴 嚴重 **審查員**:Assassin **問題**:LLM 提示詞注入風險:在 `judgeConversationsResolved` 函式中,外部來源的 `thread` 和 `code` 被直接拼接進傳給 LLM 的 `payload` 中,攻擊者可能注入惡意指令來劫持 LLM 行為。 **建議**:對所有傳遞給 LLM 的外部輸入進行嚴格的淨化和隔離。使用結構化輸入而非直接拼接字串,並在提示詞中明確指示 AI 忽略任何試圖下達指令的內容,僅對邏輯進行判斷。對於敏感操作,應建立多層驗證機制。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +170,4 @@
resolveTargets.map(({ c }) => resolveComment(c.commentIds[0])),
);
const resolveOutcome = new Map();
resolveTargets.forEach(({ i }, j) => resolveOutcome.set(i, settled[j]));
Owner

嚴重等級🔵 建議
審查員:Rogue
問題Promise.allSettled 的結果處理邏輯過於冗長,產生不必要的中間變數。
建議:優化處理邏輯,直接在迴圈內處理或使用更緊湊的寫法。

**嚴重等級**:🔵 建議 **審查員**:Rogue **問題**:`Promise.allSettled` 的結果處理邏輯過於冗長,產生不必要的中間變數。 **建議**:優化處理邏輯,直接在迴圈內處理或使用更緊湊的寫法。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +177,4 @@
const c = open[i];
const outcome = resolveOutcome.get(i);
if (outcome?.status === 'fulfilled') {
resolvedCount += 1;
Owner

嚴重等級🔴 嚴重
審查員:Assassin
問題:在 reconcileConversations 函式中,從外部 Gitea comment 取得的 c.path(檔案路徑)未經額外驗證或淨化,直接傳遞給了 getFileContent(即 getFileContentAtRef)。由於 getFileContentAtRef 存在路徑穿越漏洞,攻擊者可以透過在 PR 中建立惡意檔案名稱,並在該檔案上留言,來觸發路徑穿越,讀取伺服器上的任意檔案。
建議:在將 c.path 傳遞給 getFileContent 之前,必須對其進行嚴格的白名單驗證,確保它只包含預期的檔案名稱字元,且不包含任何路徑穿越序列(例如 ../)。或者,確保 getFileContentAtRef 的路徑處理是絕對安全的,不允許任何形式的路徑穿越。

**嚴重等級**:🔴 嚴重 **審查員**:Assassin **問題**:在 `reconcileConversations` 函式中,從外部 Gitea comment 取得的 `c.path`(檔案路徑)未經額外驗證或淨化,直接傳遞給了 `getFileContent`(即 `getFileContentAtRef`)。由於 `getFileContentAtRef` 存在路徑穿越漏洞,攻擊者可以透過在 PR 中建立惡意檔案名稱,並在該檔案上留言,來觸發路徑穿越,讀取伺服器上的任意檔案。 **建議**:在將 `c.path` 傳遞給 `getFileContent` 之前,必須對其進行嚴格的白名單驗證,確保它只包含預期的檔案名稱字元,且不包含任何路徑穿越序列(例如 `..` 或 `/`)。或者,確保 `getFileContentAtRef` 的路徑處理是絕對安全的,不允許任何形式的路徑穿越。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +184,4 @@
}
if (outcome?.status === 'rejected') {
warn(`resolve 對話失敗(保留為未解決): ${c.path}:${c.line} error=${outcome.reason?.message}`);
}
Owner

嚴重等級🟡 警告
審查員:Mage
問題:在 reconcileConversations 函式中,並行(Promise.all)呼叫 resolveComment,即使個別呼叫失敗,也僅在 settled 中記錄為 rejected 並印出 warn。然而,若 resolveComment 失敗是因為 Authorization token 過期或權限不足,後續所有的 resolve 呼叫都會失敗,此時程式碼沒有對這些特定的錯誤進行分類處理。
建議:應判斷 outcome.reason 的錯誤類型。若是連線/權限相關的嚴重錯誤,應立即停止後續的 resolve 嘗試,避免在已知無法成功的情況下發出無效請求。

**嚴重等級**:🟡 警告 **審查員**:Mage **問題**:在 `reconcileConversations` 函式中,並行(`Promise.all`)呼叫 `resolveComment`,即使個別呼叫失敗,也僅在 `settled` 中記錄為 `rejected` 並印出 `warn`。然而,若 `resolveComment` 失敗是因為 `Authorization` token 過期或權限不足,後續所有的 `resolve` 呼叫都會失敗,此時程式碼沒有對這些特定的錯誤進行分類處理。 **建議**:應判斷 `outcome.reason` 的錯誤類型。若是連線/權限相關的嚴重錯誤,應立即停止後續的 `resolve` 嘗試,避免在已知無法成功的情況下發出無效請求。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +192,4 @@
ok(`對話收斂完成: resolved=${resolvedCount} unresolved=${unresolvedCount} 加回 findings=${carriedFindings.length}`);
return { resolvedFindings, carriedFindings, resolvedCount, unresolvedCount };
}
Owner

嚴重等級🔵 建議
審查員:Mage
問題:對 botFinding 的存取缺乏防禦性檢查。
建議:在 push 之前增加防禦性檢查,確保物件完整性。

**嚴重等級**:🔵 建議 **審查員**:Mage **問題**:對 `botFinding` 的存取缺乏防禦性檢查。 **建議**:在 `push` 之前增加防禦性檢查,確保物件完整性。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +204,4 @@
.trim()
.toLowerCase();
}
Owner

嚴重等級🟡 警告
審查員:Leo
問題:正規化邏輯(normalizeKey 等)過於激進且未快取,既可能導致語意相近建議被誤判為相同,也在頻繁比較時造成效能浪費。
建議:請評估目前的正規化規則,若發現誤判,放寬規則或加入關鍵字比對。將簽章產生邏輯抽離為獨立 Helper 函式,並在產生時進行快取(Memoize)以提升效能。

**嚴重等級**:🟡 警告 **審查員**:Leo **問題**:正規化邏輯(`normalizeKey` 等)過於激進且未快取,既可能導致語意相近建議被誤判為相同,也在頻繁比較時造成效能浪費。 **建議**:請評估目前的正規化規則,若發現誤判,放寬規則或加入關鍵字比對。將簽章產生邏輯抽離為獨立 Helper 函式,並在產生時進行快取(Memoize)以提升效能。
admin marked this conversation as resolved
admin added 1 commit 2026-06-23 03:38:21 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 3s
e6d1a17b78
jiantw83 added 5 commits 2026-06-23 04:58:54 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 04:59:43 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議
舊問題 0 筆 5 筆 0 筆
新問題 0 筆 2 筆 1 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 9 次呼叫)

提示 token 回應 token 合計
164,737 6,268 234,648

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | | --- | --- | --- | --- | | 舊問題 | 0 筆 | 5 筆 | 0 筆 | | 新問題 | 0 筆 | 2 筆 | 1 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 9 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 164,737 | 6,268 | 234,648 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -0,0 +37,4 @@
export function parseBotReviewComment(body) {
if (typeof body !== 'string' || !body.includes('**')) return null;
const normalized = body.replace(/\r\n/g, '\n');
const levelRaw = fieldValue(normalized, '嚴重等級') || fieldValue(normalized, '等級');
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 parseBotReviewComment 缺少對 levelRaw 為空但其他欄位存在時的測試案例。程式碼有 level: level || 'warning' 處理,但此行為應被明確驗證。
建議:請新增測試案例,模擬評論內文缺少 嚴重等級等級 欄位,但有 審查員問題/建議 欄位時,確認 level 會正確地預設為 warning

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `parseBotReviewComment` 缺少對 `levelRaw` 為空但其他欄位存在時的測試案例。程式碼有 `level: level || 'warning'` 處理,但此行為應被明確驗證。 **建議**:請新增測試案例,模擬評論內文缺少 `嚴重等級` 或 `等級` 欄位,但有 `審查員` 和 `問題`/`建議` 欄位時,確認 `level` 會正確地預設為 `warning`。
admin marked this conversation as resolved
@@ -0,0 +38,4 @@
if (typeof body !== 'string' || !body.includes('**')) return null;
const normalized = body.replace(/\r\n/g, '\n');
const levelRaw = fieldValue(normalized, '嚴重等級') || fieldValue(normalized, '等級');
const role = fieldValue(normalized, '審查員');
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 parseBotReviewComment 缺少對 problem 存在但 suggestion 為空字串的測試案例。程式碼有 suggestion: suggestion || problem || '' 處理,但此行為應被明確驗證。
建議:請新增測試案例,模擬評論內文只包含 問題 欄位而無 建議 欄位時,確認 suggestion 會正確地使用 problem 的內容。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `parseBotReviewComment` 缺少對 `problem` 存在但 `suggestion` 為空字串的測試案例。程式碼有 `suggestion: suggestion || problem || ''` 處理,但此行為應被明確驗證。 **建議**:請新增測試案例,模擬評論內文只包含 `問題` 欄位而無 `建議` 欄位時,確認 `suggestion` 會正確地使用 `problem` 的內容。
admin marked this conversation as resolved
@@ -0,0 +87,4 @@
if (!content) return '';
const lines = content.split('\n');
const center = Number.isFinite(lineNum) && lineNum > 0 ? lineNum - 1 : 0;
const start = Math.max(0, center - radius);
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 judgeConversationsResolved 缺少對 chatFn 拋出錯誤情境的測試。雖然上層呼叫者有處理,但此函式本身的錯誤行為應被驗證。
建議:請新增測試案例,模擬 chatFn 拋出錯誤時,確認 judgeConversationsResolved 會正確地將錯誤向上拋出,以便呼叫者處理。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `judgeConversationsResolved` 缺少對 `chatFn` 拋出錯誤情境的測試。雖然上層呼叫者有處理,但此函式本身的錯誤行為應被驗證。 **建議**:請新增測試案例,模擬 `chatFn` 拋出錯誤時,確認 `judgeConversationsResolved` 會正確地將錯誤向上拋出,以便呼叫者處理。
admin marked this conversation as resolved
@@ -0,0 +88,4 @@
const lines = content.split('\n');
const center = Number.isFinite(lineNum) && lineNum > 0 ? lineNum - 1 : 0;
const start = Math.max(0, center - radius);
const end = Math.min(lines.length, center + radius + 1);
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 judgeConversationsResolved 缺少對 AI 回傳結果中元素缺少 idxresolved 欄位的測試案例。雖然程式碼有過濾處理,但此邊界條件應被明確驗證。
建議:請新增測試案例,模擬 chatFn 回傳的陣列中,有些物件缺少 idxresolved 屬性時,確認這些無效的結果會被正確過濾,且其他有效結果能被正確處理。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `judgeConversationsResolved` 缺少對 AI 回傳結果中元素缺少 `idx` 或 `resolved` 欄位的測試案例。雖然程式碼有過濾處理,但此邊界條件應被明確驗證。 **建議**:請新增測試案例,模擬 `chatFn` 回傳的陣列中,有些物件缺少 `idx` 或 `resolved` 屬性時,確認這些無效的結果會被正確過濾,且其他有效結果能被正確處理。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +141,4 @@
* 4. 未解決且可解析為 bot finding 收集為加回問題列表清單
* 任一外部呼叫失敗都降級處理保守視為未解決不中斷整體 pipeline
*/
export async function reconcileConversations(deps = {}) {
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 reconcileConversations 缺少對 judge 拋出錯誤情境的明確測試。雖然程式碼有 try-catch 處理,但應有專門的測試案例來驗證此失敗路徑的行為。
建議:請新增測試案例,模擬 judge 函式拋出錯誤時,確認 reconcileConversations 能正確捕獲錯誤,記錄警告,並將所有待判斷的對話都視為未解決(即 verdicts 應全部為 resolved: false)。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `reconcileConversations` 缺少對 `judge` 拋出錯誤情境的明確測試。雖然程式碼有 `try-catch` 處理,但應有專門的測試案例來驗證此失敗路徑的行為。 **建議**:請新增測試案例,模擬 `judge` 函式拋出錯誤時,確認 `reconcileConversations` 能正確捕獲錯誤,記錄警告,並將所有待判斷的對話都視為未解決(即 `verdicts` 應全部為 `resolved: false`)。
admin marked this conversation as resolved
@@ -0,0 +12,4 @@
/**
* 把各平台回應中的 token usage 正規化成 { promptTokens, completionTokens, totalTokens }
* 支援OpenAI 相容 usageOpenAI Responsesinput/output_tokens
* Gemini usageMetadataOllama 原生 eval_countOpenCode tokens
Owner

嚴重等級🟡 警告
審查員:Mage
問題:extractUsage 中對於 OpenAI 相容格式的處理:const total = num(u.total_tokens) || prompt + completion;。如果 API 回傳了 total_tokens: 0(雖然極少見但非零可能),這裡的邏輯會觸發 prompt + completion 的計算,導致數值不準確。
建議:應明確判斷 u.total_tokens != null 而非僅檢查其 truthiness,以確保在 API 明確回傳 0 時能正確讀取。

**嚴重等級**:🟡 警告 **審查員**:Mage **問題**:extractUsage 中對於 OpenAI 相容格式的處理:`const total = num(u.total_tokens) || prompt + completion;`。如果 API 回傳了 `total_tokens: 0`(雖然極少見但非零可能),這裡的邏輯會觸發 `prompt + completion` 的計算,導致數值不準確。 **建議**:應明確判斷 `u.total_tokens != null` 而非僅檢查其 truthiness,以確保在 API 明確回傳 0 時能正確讀取。
admin marked this conversation as resolved
@@ -0,0 +163,4 @@
*/
export async function fetchAccountQuota(provider, config = {}, deps = {}) {
const get = deps.get || axios.get;
const strategy = QUOTA_STRATEGIES[provider];
Owner

嚴重等級🟡 警告
審查員:Assassin
問題:在 fetchAccountQuota 中,使用 axios.get 直接請求傳入的 baseURL。如果 baseURL 是由設定檔動態讀取,攻擊者可能會透過修改設定檔將其導向惡意伺服器(SSRF),進而竊取 API Key 或發送偽造請求。
建議:應對 baseURL 進行嚴格的白名單校驗,確保其僅能連線至合法的 API 提供商域名。不要信任外部設定檔中的 URL。

**嚴重等級**:🟡 警告 **審查員**:Assassin **問題**:在 `fetchAccountQuota` 中,使用 `axios.get` 直接請求傳入的 `baseURL`。如果 `baseURL` 是由設定檔動態讀取,攻擊者可能會透過修改設定檔將其導向惡意伺服器(SSRF),進而竊取 API Key 或發送偽造請求。 **建議**:應對 `baseURL` 進行嚴格的白名單校驗,確保其僅能連線至合法的 API 提供商域名。不要信任外部設定檔中的 URL。
admin marked this conversation as resolved
admin added 1 commit 2026-06-23 04:59:45 +00:00
chore: update ai-review findings [ai-review-bot][success]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Successful in 3s
7b311f1e8f
jiantw83 added 3 commits 2026-06-23 05:07:37 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 05:08:31 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議
舊問題 0 筆 1 筆 0 筆
新問題 4 筆 2 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 9 次呼叫)

提示 token 回應 token 合計
140,813 9,555 238,458

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | | --- | --- | --- | --- | | 舊問題 | 0 筆 | 1 筆 | 0 筆 | | 新問題 | 4 筆 | 2 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 9 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 140,813 | 9,555 | 238,458 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -0,0 +74,4 @@
if (!g.botFinding) {
const finding = parseBotReviewComment(body);
if (finding) g.botFinding = { ...finding, location: lineNum ? `${filePath}:${lineNum}` : filePath };
}
Owner

嚴重等級🟡 警告
審查員:Maya
問題:在 codeWindow 函數中,缺乏對輸入的邊界檢查,特別是當 lineNum 為 0 或負數,或是大於總行數時,可能導致行為不預期或 slice 產生錯誤。
建議:建議在計算 startend 時,增加明確的邊界檢核與處理,確保即使 lineNum 異常時也能安全返回或處理。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:在 `codeWindow` 函數中,缺乏對輸入的邊界檢查,特別是當 `lineNum` 為 0 或負數,或是大於總行數時,可能導致行為不預期或 slice 產生錯誤。 **建議**:建議在計算 `start` 和 `end` 時,增加明確的邊界檢核與處理,確保即使 `lineNum` 異常時也能安全返回或處理。
admin marked this conversation as resolved
@@ -0,0 +14,4 @@
* 支援OpenAI 相容 usageOpenAI Responsesinput/output_tokens
* Gemini usageMetadataOllama 原生 eval_countOpenCode tokens
* 回應中沒有任何可辨識的 usage 時回傳 null
*/
Owner

嚴重等級🔴 嚴重
審查員:Mage
問題:在 extractUsage 中,對於 data.usage 的屬性存取直接使用 num(...),這在 data.usage 如果是 null 或其他 falsy 值但被 typeof 判斷通過時(JS 的 typeof null === 'object'),會導致錯誤。
建議:應明確檢查 u 是否為嚴格的 object 且非 null,例如 if (u && typeof u === 'object' && !Array.isArray(u))

**嚴重等級**:🔴 嚴重 **審查員**:Mage **問題**:在 `extractUsage` 中,對於 `data.usage` 的屬性存取直接使用 `num(...)`,這在 `data.usage` 如果是 `null` 或其他 falsy 值但被 `typeof` 判斷通過時(JS 的 `typeof null === 'object'`),會導致錯誤。 **建議**:應明確檢查 `u` 是否為嚴格的 `object` 且非 `null`,例如 `if (u && typeof u === 'object' && !Array.isArray(u))`。
admin marked this conversation as resolved
@@ -0,0 +103,4 @@
}
if (remaining == null || limit == null) return;
rateLimit.hasData = true;
Owner

嚴重等級🔴 嚴重
審查員:Assassin
問題:函數 isOpenRouterBaseURL 僅使用 new URL(baseURL).hostname.endsWith('.openrouter.ai') 來判斷,這極易受到偽造域名攻擊(如 openrouter.ai.malicious.com),導致惡意主機被信任為 OpenRouter,進而洩漏 API Key。
建議:應修改為嚴格比對,例如 hostname === 'openrouter.ai',且必須包含 protocol 檢查(如 https),並建議採用白名單機制而非簡單的 endsWith

**嚴重等級**:🔴 嚴重 **審查員**:Assassin **問題**:函數 `isOpenRouterBaseURL` 僅使用 `new URL(baseURL).hostname.endsWith('.openrouter.ai')` 來判斷,這極易受到偽造域名攻擊(如 `openrouter.ai.malicious.com`),導致惡意主機被信任為 OpenRouter,進而洩漏 API Key。 **建議**:應修改為嚴格比對,例如 `hostname === 'openrouter.ai'`,且必須包含 protocol 檢查(如 `https`),並建議採用白名單機制而非簡單的 `endsWith`。
admin marked this conversation as resolved
@@ -0,0 +112,4 @@
/** 取得最近一次的速率配額快照(複本)。 */
export function getRateLimit() {
return { ...rateLimit };
}
Owner

嚴重等級🟡 警告
審查員:Mage
問題:在 recordRateLimit 中,處理 Header 時將所有 Key 轉為小寫並存入物件 h,如果原始 Header 中存在多個相同名稱但不同大小寫的 Header(雖然 HTTP 標準規定 Key 不區分大小寫,但某些實作可能會有不一致),可能會造成覆蓋。
建議:雖然 HTTP 規範不區分,但為了安全起見,應先確認環境使用的 axios 版本對 Header 的處理方式,或確保在轉換前沒有遺漏必要資訊。

**嚴重等級**:🟡 警告 **審查員**:Mage **問題**:在 `recordRateLimit` 中,處理 Header 時將所有 Key 轉為小寫並存入物件 `h`,如果原始 Header 中存在多個相同名稱但不同大小寫的 Header(雖然 HTTP 標準規定 Key 不區分大小寫,但某些實作可能會有不一致),可能會造成覆蓋。 **建議**:雖然 HTTP 規範不區分,但為了安全起見,應先確認環境使用的 axios 版本對 Header 的處理方式,或確保在轉換前沒有遺漏必要資訊。
admin marked this conversation as resolved
app/usage.js Outdated
@@ -0,0 +129,4 @@
* `openrouter.ai.evil.com` `evil.com/openrouter.ai`矇騙而把 API key 送往惡意主機
*/
function isOpenRouterBaseURL(baseURL) {
try {
Owner

嚴重等級🔴 嚴重
審查員:Assassin
問題:在 QUOTA_STRATEGIES 中,如果 config.apiKeys 是一個陣列,代碼只取 [0] 作為 API Key,但如果這個 key 是洩漏的或是環境配置錯誤,可能會導致敏感資訊在未經嚴格驗證的情況下被發送到 baseURL 指定的端點。
建議:請務必確保所有的 API 請求都經過完整的信任邊界審核,不要僅憑環境變數就自動信任該 Key 具備查詢帳號額度的權限,並在傳輸前對 baseURL 進行嚴格的白名單檢查。

**嚴重等級**:🔴 嚴重 **審查員**:Assassin **問題**:在 `QUOTA_STRATEGIES` 中,如果 `config.apiKeys` 是一個陣列,代碼只取 `[0]` 作為 API Key,但如果這個 key 是洩漏的或是環境配置錯誤,可能會導致敏感資訊在未經嚴格驗證的情況下被發送到 `baseURL` 指定的端點。 **建議**:請務必確保所有的 API 請求都經過完整的信任邊界審核,不要僅憑環境變數就自動信任該 Key 具備查詢帳號額度的權限,並在傳輸前對 baseURL 進行嚴格的白名單檢查。
admin marked this conversation as resolved
@@ -0,0 +163,4 @@
if (isOpenRouterBaseURL(cfg.baseURL)) return fetchOpenRouterQuota(cfg, get);
return { available: false, reason: 'OpenAI 帳號額度需 dashboard session 權限,API key 無法取得' };
},
claude: async () => ({ available: false, reason: 'Anthropic 額度需 Admin API 權限,一般 API key 無法取得' }),
Owner

嚴重等級🟡 警告
審查員:Assassin
問題:在 fetchAccountQuota 中,使用 axios.get 直接請求傳入的 baseURL。如果 baseURL 是由設定檔動態讀取,攻擊者可能會透過修改設定檔將其導向惡意伺服器(SSRF),進而竊取 API Key 或發送偽造請求。
建議:應對 baseURL 進行嚴格的白名單校驗,確保其僅能連線至合法的 API 提供商域名。不要信任外部設定檔中的 URL。

**嚴重等級**:🟡 警告 **審查員**:Assassin **問題**:在 `fetchAccountQuota` 中,使用 `axios.get` 直接請求傳入的 `baseURL`。如果 `baseURL` 是由設定檔動態讀取,攻擊者可能會透過修改設定檔將其導向惡意伺服器(SSRF),進而竊取 API Key 或發送偽造請求。 **建議**:應對 `baseURL` 進行嚴格的白名單校驗,確保其僅能連線至合法的 API 提供商域名。不要信任外部設定檔中的 URL。
admin marked this conversation as resolved
@@ -0,0 +173,4 @@
/**
* 取得指定平台的帳號額度任何失敗都降級為 { available: false, reason }不丟例外
* deps.get 可注入以利測試預設 axios.get
*/
Owner

嚴重等級🔴 嚴重
審查員:Mage
問題:在 fetchAccountQuota 中,呼叫 strategy 時傳入的 config 物件,如果在特定 strategy 中被意外修改,會影響到全域的 config 狀態,且傳入的 get 函數來源若未被嚴格隔離,可能存在潛在的請求偽造風險。
建議:傳入 strategy 的 config 應進行淺拷貝(shallow copy),確保不可變性。

**嚴重等級**:🔴 嚴重 **審查員**:Mage **問題**:在 `fetchAccountQuota` 中,呼叫 `strategy` 時傳入的 `config` 物件,如果在特定 `strategy` 中被意外修改,會影響到全域的 config 狀態,且傳入的 `get` 函數來源若未被嚴格隔離,可能存在潛在的請求偽造風險。 **建議**:傳入 `strategy` 的 config 應進行淺拷貝(shallow copy),確保不可變性。
admin marked this conversation as resolved
admin added 1 commit 2026-06-23 05:08:32 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 4s
03ecc224d9
jiantw83 added 5 commits 2026-06-23 05:16:06 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 05:17:01 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 1 筆 3 筆 0 筆 0 筆
舊問題 0 筆 5 筆 0 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 9 次呼叫)

提示 token 回應 token 合計
176,720 10,014 246,532

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 1 筆 | 3 筆 | 0 筆 | 0 筆 | | 舊問題 | 0 筆 | 5 筆 | 0 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 9 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 176,720 | 10,014 | 246,532 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -0,0 +37,4 @@
export function parseBotReviewComment(body) {
if (typeof body !== 'string' || !body.includes('**')) return null;
const normalized = body.replace(/\r\n/g, '\n');
const levelRaw = fieldValue(normalized, '嚴重等級') || fieldValue(normalized, '等級');
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 parseBotReviewComment 缺少對 levelRaw 為空但其他欄位存在時的測試案例。程式碼有 level: level || 'warning' 處理,但此行為應被明確驗證。
建議:請新增測試案例,模擬評論內文缺少 嚴重等級等級 欄位,但有 審查員問題/建議 欄位時,確認 level 會正確地預設為 warning

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `parseBotReviewComment` 缺少對 `levelRaw` 為空但其他欄位存在時的測試案例。程式碼有 `level: level || 'warning'` 處理,但此行為應被明確驗證。 **建議**:請新增測試案例,模擬評論內文缺少 `嚴重等級` 或 `等級` 欄位,但有 `審查員` 和 `問題`/`建議` 欄位時,確認 `level` 會正確地預設為 `warning`。
admin marked this conversation as resolved
@@ -0,0 +38,4 @@
if (typeof body !== 'string' || !body.includes('**')) return null;
const normalized = body.replace(/\r\n/g, '\n');
const levelRaw = fieldValue(normalized, '嚴重等級') || fieldValue(normalized, '等級');
const role = fieldValue(normalized, '審查員');
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 parseBotReviewComment 缺少對 problem 存在但 suggestion 為空字串的測試案例。程式碼有 suggestion: suggestion || problem || '' 處理,但此行為應被明確驗證。
建議:請新增測試案例,模擬評論內文只包含 問題 欄位而無 建議 欄位時,確認 suggestion 會正確地使用 problem 的內容。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `parseBotReviewComment` 缺少對 `problem` 存在但 `suggestion` 為空字串的測試案例。程式碼有 `suggestion: suggestion || problem || ''` 處理,但此行為應被明確驗證。 **建議**:請新增測試案例,模擬評論內文只包含 `問題` 欄位而無 `建議` 欄位時,確認 `suggestion` 會正確地使用 `problem` 的內容。
admin marked this conversation as resolved
@@ -0,0 +86,4 @@
export function codeWindow(content, lineNum, radius = CODE_WINDOW_RADIUS) {
if (!content) return '';
const lines = content.split('\n');
const center = Number.isFinite(lineNum) && lineNum > 0 ? lineNum - 1 : 0;
Owner

嚴重等級🟡 警告
審查員:Maya
問題:在 judgeConversationsResolved 函數中,AI 判斷回傳結構如果不符合預期(非陣列),雖有降級處理,但未驗證當 AI 回傳包含無效 idx 或缺少 resolved 欄位的物件時,對應邏輯是否正確過濾。
建議:補測試案例,模擬 AI 回傳包含無效結構(如 idx 為字串、缺少 resolved)的 JSON,確保系統能正確忽略無效項並將其視為未解決。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:在 `judgeConversationsResolved` 函數中,AI 判斷回傳結構如果不符合預期(非陣列),雖有降級處理,但未驗證當 AI 回傳包含無效 `idx` 或缺少 `resolved` 欄位的物件時,對應邏輯是否正確過濾。 **建議**:補測試案例,模擬 AI 回傳包含無效結構(如 `idx` 為字串、缺少 `resolved`)的 JSON,確保系統能正確忽略無效項並將其視為未解決。
admin marked this conversation as resolved
@@ -0,0 +87,4 @@
if (!content) return '';
const lines = content.split('\n');
const center = Number.isFinite(lineNum) && lineNum > 0 ? lineNum - 1 : 0;
const start = Math.max(0, center - radius);
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 judgeConversationsResolved 缺少對 chatFn 拋出錯誤情境的測試。雖然上層呼叫者有處理,但此函式本身的錯誤行為應被驗證。
建議:請新增測試案例,模擬 chatFn 拋出錯誤時,確認 judgeConversationsResolved 會正確地將錯誤向上拋出,以便呼叫者處理。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `judgeConversationsResolved` 缺少對 `chatFn` 拋出錯誤情境的測試。雖然上層呼叫者有處理,但此函式本身的錯誤行為應被驗證。 **建議**:請新增測試案例,模擬 `chatFn` 拋出錯誤時,確認 `judgeConversationsResolved` 會正確地將錯誤向上拋出,以便呼叫者處理。
admin marked this conversation as resolved
@@ -0,0 +88,4 @@
const lines = content.split('\n');
const center = Number.isFinite(lineNum) && lineNum > 0 ? lineNum - 1 : 0;
const start = Math.max(0, center - radius);
const end = Math.min(lines.length, center + radius + 1);
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 judgeConversationsResolved 缺少對 AI 回傳結果中元素缺少 idxresolved 欄位的測試案例。雖然程式碼有過濾處理,但此邊界條件應被明確驗證。
建議:請新增測試案例,模擬 chatFn 回傳的陣列中,有些物件缺少 idxresolved 屬性時,確認這些無效的結果會被正確過濾,且其他有效結果能被正確處理。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `judgeConversationsResolved` 缺少對 AI 回傳結果中元素缺少 `idx` 或 `resolved` 欄位的測試案例。雖然程式碼有過濾處理,但此邊界條件應被明確驗證。 **建議**:請新增測試案例,模擬 `chatFn` 回傳的陣列中,有些物件缺少 `idx` 或 `resolved` 屬性時,確認這些無效的結果會被正確過濾,且其他有效結果能被正確處理。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +139,4 @@
* 2. 取每個對話所在檔案的最新內容 AI 判斷問題是否已解決
* 3. 已解決者呼叫 Gitea resolve API 解決對話並記錄其 finding供移除舊問題
* 4. 未解決且可解析為 bot finding 收集為加回問題列表清單
* 任一外部呼叫失敗都降級處理保守視為未解決不中斷整體 pipeline
Owner

嚴重等級🔴 嚴重
審查員:Maya
問題reconcileConversations 核心流程中,對於 getFileContent 失敗或內容為空的處理邏輯,直接降級為空字串並視為未解決,但若檔案內容實際上非空且未解決,這可能導致判斷偏差。
建議:補測試案例,模擬 getFileContent 拋出錯誤時,reconcileConversations 是否正確地將對話保留為未解決,且後續統計數字(carriedFindings)是否正確。

**嚴重等級**:🔴 嚴重 **審查員**:Maya **問題**:`reconcileConversations` 核心流程中,對於 `getFileContent` 失敗或內容為空的處理邏輯,直接降級為空字串並視為未解決,但若檔案內容實際上非空且未解決,這可能導致判斷偏差。 **建議**:補測試案例,模擬 `getFileContent` 拋出錯誤時,`reconcileConversations` 是否正確地將對話保留為未解決,且後續統計數字(`carriedFindings`)是否正確。
admin marked this conversation as resolved
app/resolve.js Outdated
@@ -0,0 +141,4 @@
* 4. 未解決且可解析為 bot finding 收集為加回問題列表清單
* 任一外部呼叫失敗都降級處理保守視為未解決不中斷整體 pipeline
*/
export async function reconcileConversations(deps = {}) {
Owner

嚴重等級🟡 警告
審查員:Maya
問題:函式 reconcileConversations 缺少對 judge 拋出錯誤情境的明確測試。雖然程式碼有 try-catch 處理,但應有專門的測試案例來驗證此失敗路徑的行為。
建議:請新增測試案例,模擬 judge 函式拋出錯誤時,確認 reconcileConversations 能正確捕獲錯誤,記錄警告,並將所有待判斷的對話都視為未解決(即 verdicts 應全部為 resolved: false)。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:函式 `reconcileConversations` 缺少對 `judge` 拋出錯誤情境的明確測試。雖然程式碼有 `try-catch` 處理,但應有專門的測試案例來驗證此失敗路徑的行為。 **建議**:請新增測試案例,模擬 `judge` 函式拋出錯誤時,確認 `reconcileConversations` 能正確捕獲錯誤,記錄警告,並將所有待判斷的對話都視為未解決(即 `verdicts` 應全部為 `resolved: false`)。
admin marked this conversation as resolved
@@ -0,0 +170,4 @@
opencode: async () => ({ available: false, reason: '自架服務,無帳號額度概念' }),
};
/**
Owner

嚴重等級🟡 警告
審查員:Maya
問題fetchAccountQuota 策略在處理 API key 時,假設 apiKeys 陣列存在並取第一個,若傳入的 config.apiKeys 為空陣列或 undefined,缺乏明確的防禦與測試。
建議:補測試案例,模擬 config.apiKeys 為空或無效的情境,確認系統降級行為是否符合預期。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:`fetchAccountQuota` 策略在處理 API key 時,假設 `apiKeys` 陣列存在並取第一個,若傳入的 `config.apiKeys` 為空陣列或 undefined,缺乏明確的防禦與測試。 **建議**:補測試案例,模擬 `config.apiKeys` 為空或無效的情境,確認系統降級行為是否符合預期。
admin marked this conversation as resolved
@@ -0,0 +208,4 @@
/**
* 計算剩餘可用百分比依優先序擇一
* 1. 帳號額度quota 有上限 剩餘 credits / 上限
* 2. 速率配額rate limit header 當前視窗剩餘 / 上限
Owner

嚴重等級🟡 警告
審查員:Maya
問題resolveRemainingPercent 函數負責處理額度計算,但針對 quota.limit 為 0 的情況缺乏顯式處理,可能會導致除以零或錯誤的百分比計算結果。
建議:補測試案例,模擬 quota.limit 為 0 的情境,確認系統是否正確處理或返回錯誤訊息,避免計算偏差。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:`resolveRemainingPercent` 函數負責處理額度計算,但針對 `quota.limit` 為 0 的情況缺乏顯式處理,可能會導致除以零或錯誤的百分比計算結果。 **建議**:補測試案例,模擬 `quota.limit` 為 0 的情境,確認系統是否正確處理或返回錯誤訊息,避免計算偏差。
admin marked this conversation as resolved
admin added 1 commit 2026-06-23 05:17:03 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 4s
ff075c8438
jiantw83 added 2 commits 2026-06-23 05:35:01 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 05:36:21 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 0 筆 1 筆 3 筆 0 筆
舊問題 0 筆 0 筆 0 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 9 次呼叫)

提示 token 回應 token 合計
175,181 10,250 250,756

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 0 筆 | 1 筆 | 3 筆 | 0 筆 | | 舊問題 | 0 筆 | 0 筆 | 0 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 9 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 175,181 | 10,250 | 250,756 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -0,0 +4,4 @@
const EMPTY = { resolvedFindings: [], carriedFindings: [], resolvedCount: 0, unresolvedCount: 0 };
// 預先編譯各欄位標籤的擷取正則(靜態定義:避免每次呼叫重建,也排除以外部輸入動態組 regex 的風險)
Owner

嚴重等級🔵 建議
審查員:Bard
問題EMPTY 常數命名過於通用,容易與其他模組中的同名變數衝突,且定義在模組頂層略顯突兀。
建議:建議加上命名空間前綴,例如 RECONCILE_DEFAULT_STATE,以增加語義清晰度。

**嚴重等級**:🔵 建議 **審查員**:Bard **問題**:`EMPTY` 常數命名過於通用,容易與其他模組中的同名變數衝突,且定義在模組頂層略顯突兀。 **建議**:建議加上命名空間前綴,例如 `RECONCILE_DEFAULT_STATE`,以增加語義清晰度。
admin marked this conversation as resolved
@@ -0,0 +7,4 @@
// 預先編譯各欄位標籤的擷取正則(靜態定義:避免每次呼叫重建,也排除以外部輸入動態組 regex 的風險)
const FIELD_PATTERNS = {
嚴重等級: /\*\*嚴重等級\*\*[:]\s*(.+)/,
等級: /\*\*等級\*\*[:]\s*(.+)/,
Owner

嚴重等級🔵 建議
審查員:Bard
問題FIELD_PATTERNS 的正則表達式對於冒號的定義同時包含了全形與半形,雖然容錯性高,但建議統一規範以維持風格一致性。
建議:建議統一使用半形冒號,並在解析前進行正規化處理,而非在正則中處理所有可能性。

**嚴重等級**:🔵 建議 **審查員**:Bard **問題**:`FIELD_PATTERNS` 的正則表達式對於冒號的定義同時包含了全形與半形,雖然容錯性高,但建議統一規範以維持風格一致性。 **建議**:建議統一使用半形冒號,並在解析前進行正規化處理,而非在正則中處理所有可能性。
admin marked this conversation as resolved
@@ -0,0 +120,4 @@
rateLimit.remaining = null;
rateLimit.limit = null;
rateLimit.kind = null;
}
Owner

嚴重等級🟡 警告
審查員:Bard
問題recordRateLimit 函式中對於 headers 的處理,將所有 key 轉換為小寫後檢查,這雖然兼容了多種平台規範,但處理邏輯稍顯冗長,降低了程式碼的流暢度。
建議:建議提取一個專門處理 header 正規化的工具函式,使主邏輯更簡潔。

**嚴重等級**:🟡 警告 **審查員**:Bard **問題**:`recordRateLimit` 函式中對於 headers 的處理,將所有 key 轉換為小寫後檢查,這雖然兼容了多種平台規範,但處理邏輯稍顯冗長,降低了程式碼的流暢度。 **建議**:建議提取一個專門處理 header 正規化的工具函式,使主邏輯更簡潔。
admin marked this conversation as resolved
@@ -0,0 +164,4 @@
return { available: false, reason: 'OpenAI 帳號額度需 dashboard session 權限,API key 無法取得' };
},
claude: async () => ({ available: false, reason: 'Anthropic 額度需 Admin API 權限,一般 API key 無法取得' }),
gemini: async () => ({ available: false, reason: 'Gemini 額度由 Google Cloud quota 管理,API key 無法直接查詢' }),
Owner

嚴重等級🔵 建議
審查員:Bard
問題fetchAccountQuota 中的 QUOTA_STRATEGIES 物件定義龐大,將所有平台的策略硬編碼在此處,未來若新增更多 LLM 供應商,此處將變得難以維護。
建議:建議將各供應商的額度查詢策略抽離至獨立的檔案或策略模式處理,以保持 usage.js 的整潔。

**嚴重等級**:🔵 建議 **審查員**:Bard **問題**:`fetchAccountQuota` 中的 `QUOTA_STRATEGIES` 物件定義龐大,將所有平台的策略硬編碼在此處,未來若新增更多 LLM 供應商,此處將變得難以維護。 **建議**:建議將各供應商的額度查詢策略抽離至獨立的檔案或策略模式處理,以保持 `usage.js` 的整潔。
admin marked this conversation as resolved
admin added 1 commit 2026-06-23 05:36:23 +00:00
chore: update ai-review findings [ai-review-bot][success]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Successful in 4s
8e7c859026
jiantw83 added 6 commits 2026-06-23 05:51:45 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 05:52:37 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 0 筆 0 筆 0 筆 0 筆
舊問題 1 筆 7 筆 0 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 9 次呼叫)

提示 token 回應 token 合計
188,780 8,885 266,720

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 0 筆 | 0 筆 | 0 筆 | 0 筆 | | 舊問題 | 1 筆 | 7 筆 | 0 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 9 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 188,780 | 8,885 | 266,720 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
admin added 1 commit 2026-06-23 05:52:38 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 5s
abe9fde6d1
jiantw83 added 4 commits 2026-06-23 06:26:16 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 06:27:21 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 0 筆 2 筆 1 筆 0 筆
舊問題 1 筆 7 筆 0 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 19 次呼叫)

提示 token 回應 token 合計
249,179 8,917 417,762

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 0 筆 | 2 筆 | 1 筆 | 0 筆 | | 舊問題 | 1 筆 | 7 筆 | 0 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 19 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 249,179 | 8,917 | 417,762 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -271,3 +273,3 @@
REVIEW_SEVERITY_LABELS,
['🟡 警告', '🔵 建議'],
);
assert.deepEqual(
Owner

嚴重等級🟡 警告
審查員:Maya
問題:新增了 usageSection 功能,但測試案例中沒有驗證當 usageSection 為空字串或未傳入時,輸出的 body 是否正確排版(例如不會多出不必要的換行符號)。
建議:補充測試案例,驗證當 usageSection 為空時,輸出的 Markdown 結構是否如預期(沒有多餘的 `

` 結尾)。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:新增了 `usageSection` 功能,但測試案例中沒有驗證當 `usageSection` 為空字串或未傳入時,輸出的 body 是否正確排版(例如不會多出不必要的換行符號)。 **建議**:補充測試案例,驗證當 `usageSection` 為空時,輸出的 Markdown 結構是否如預期(沒有多餘的 ` ` 結尾)。
admin marked this conversation as resolved
@@ -0,0 +243,4 @@
falsePositiveCount += 1;
if (c.botFinding) excludedFindings.push(toExclusion(c.botFinding));
} else {
openCount += 1;
Owner

嚴重等級🟡 警告
審查員:Maya
問題reconcileConversations 中的 reconcile 流程包含多個步驟(取得 comments、group、判斷、resolve),一旦中間有外部呼叫失敗就降級。目前的測試案例主要覆蓋了「全部成功」或「特定某個失敗」,但缺乏對「部分 resolve 成功,部分 resolve 失敗」這種狀態的驗證。
建議:補充測試案例,模擬部分 resolveComment 成功、部分失敗的情境,驗證最終回傳的 closedCountresolvedFindings 等統計數據是否正確計算。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:`reconcileConversations` 中的 `reconcile` 流程包含多個步驟(取得 comments、group、判斷、resolve),一旦中間有外部呼叫失敗就降級。目前的測試案例主要覆蓋了「全部成功」或「特定某個失敗」,但缺乏對「部分 resolve 成功,部分 resolve 失敗」這種狀態的驗證。 **建議**:補充測試案例,模擬部分 `resolveComment` 成功、部分失敗的情境,驗證最終回傳的 `closedCount` 與 `resolvedFindings` 等統計數據是否正確計算。
admin marked this conversation as resolved
admin added 1 commit 2026-06-23 06:27:23 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 3s
AI / Code Review (pull_request) Failing after 2s
32038ab34c
jiantw83 added 5 commits 2026-06-23 06:58:25 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 06:59:26 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 2 筆 1 筆 0 筆 0 筆
舊問題 0 筆 2 筆 0 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 13 次呼叫)

提示 token 回應 token 合計
231,530 7,388 344,428

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 2 筆 | 1 筆 | 0 筆 | 0 筆 | | 舊問題 | 0 筆 | 2 筆 | 0 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 13 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 231,530 | 7,388 | 344,428 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
admin added 1 commit 2026-06-23 06:59:28 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 3s
0602f47100
jiantw83 added 5 commits 2026-06-23 07:18:11 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 07:19:06 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 1 筆 2 筆 0 筆 0 筆
舊問題 0 筆 1 筆 0 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 13 次呼叫)

提示 token 回應 token 合計
253,052 7,004 376,287

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 1 筆 | 2 筆 | 0 筆 | 0 筆 | | 舊問題 | 0 筆 | 1 筆 | 0 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 13 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 253,052 | 7,004 | 376,287 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
admin added 1 commit 2026-06-23 07:19:08 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 4s
942721009e
jiantw83 added 6 commits 2026-06-23 07:40:31 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 07:41:47 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 1 筆 1 筆 0 筆 0 筆
舊問題 0 筆 1 筆 0 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 12 次呼叫)

提示 token 回應 token 合計
280,175 7,010 384,588

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 1 筆 | 1 筆 | 0 筆 | 0 筆 | | 舊問題 | 0 筆 | 1 筆 | 0 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 12 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 280,175 | 7,010 | 384,588 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -271,3 +273,3 @@
REVIEW_SEVERITY_LABELS,
['🟡 警告', '🔵 建議'],
);
assert.deepEqual(
Owner

嚴重等級🔴 嚴重
審查員:Maya
問題:新增了 usageSection 功能,但測試案例中未針對該區段若包含惡意程式碼(例如注入 ## 🤖 AI 助理使用量)進行安全測試,若 usageSection 來源不可控,可能導致統計版面被偽造訊息覆蓋。
建議:補充一個測試案例,傳入帶有惡意 Markdown 格式或假統計資料的 usageSection,確認最終產出的 body 結構是否如預期被正確組裝,而非被惡意內容竄改結構。

**嚴重等級**:🔴 嚴重 **審查員**:Maya **問題**:新增了 `usageSection` 功能,但測試案例中未針對該區段若包含惡意程式碼(例如注入 `## 🤖 AI 助理使用量`)進行安全測試,若 `usageSection` 來源不可控,可能導致統計版面被偽造訊息覆蓋。 **建議**:補充一個測試案例,傳入帶有惡意 Markdown 格式或假統計資料的 `usageSection`,確認最終產出的 `body` 結構是否如預期被正確組裝,而非被惡意內容竄改結構。
admin marked this conversation as resolved
Owner

嚴重等級🟡 警告
審查員:Maya
問題:在 filterFalsePositivesWithAI 的測試中,雖然模擬了平行處理,但並未測試當多個並行裁決(Promise.all)中,部分成功、部分失敗時的結果一致性(即確保失敗者保守保留)。
建議:增加測試案例:模擬其中一個 sub-agent 拋出錯誤、另一個判為誤報、第三個判為成立,驗證最終結果是否正確地保留了「失敗者」與「成立者」,且只剔除「確認誤報者」。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:在 `filterFalsePositivesWithAI` 的測試中,雖然模擬了平行處理,但並未測試當多個並行裁決(Promise.all)中,部分成功、部分失敗時的結果一致性(即確保失敗者保守保留)。 **建議**:增加測試案例:模擬其中一個 sub-agent 拋出錯誤、另一個判為誤報、第三個判為成立,驗證最終結果是否正確地保留了「失敗者」與「成立者」,且只剔除「確認誤報者」。
admin marked this conversation as resolved
admin added 1 commit 2026-06-23 07:41:50 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 3s
AI / Code Review (pull_request) Failing after 4s
5685ac1729
jiantw83 added 2 commits 2026-06-23 07:44:58 +00:00
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 07:45:56 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 2 筆 2 筆 1 筆 0 筆
舊問題 0 筆 1 筆 0 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 14 次呼叫)

提示 token 回應 token 合計
289,641 5,913 409,939

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 2 筆 | 2 筆 | 1 筆 | 0 筆 | | 舊問題 | 0 筆 | 1 筆 | 0 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 14 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 289,641 | 5,913 | 409,939 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -248,3 +247,4 @@
it('posts inline comments only for new findings, not old ones', async () => {
const reviewCalls = [];
const findings = [
{ level: 'info', role: 'Maya', location: 'app/c.js:30', suggestion: 'I', is_new: true },
Owner

嚴重等級🔴 嚴重
審查員:Maya
問題:新增的 postFindingsReview 使用統計功能,但在測試中完全未驗證輸出內容。
建議:應斷言 reviewCalls[0].body 確實包含了預期的 usageSection 資訊與統計數據。

**嚴重等級**:🔴 嚴重 **審查員**:Maya **問題**:新增的 `postFindingsReview` 使用統計功能,但在測試中完全未驗證輸出內容。 **建議**:應斷言 `reviewCalls[0].body` 確實包含了預期的 `usageSection` 資訊與統計數據。
admin marked this conversation as resolved
Owner

嚴重等級🔴 嚴重
審查員:Maya
問題filterFalsePositivesWithAI 測試不足,缺乏對 judgeFindingIsFalsePositive 內部的獨立單元測試。
建議:為內部函數 judgeFindingIsFalsePositive 補寫測試,單獨驗證其對不同 Verdict 值(false_positive, confirmed, 異常值)的處理邏輯。

**嚴重等級**:🔴 嚴重 **審查員**:Maya **問題**:`filterFalsePositivesWithAI` 測試不足,缺乏對 `judgeFindingIsFalsePositive` 內部的獨立單元測試。 **建議**:為內部函數 `judgeFindingIsFalsePositive` 補寫測試,單獨驗證其對不同 Verdict 值(false_positive, confirmed, 異常值)的處理邏輯。
admin marked this conversation as resolved
@@ -142,6 +189,126 @@ describe('findings exclusions', () => {
assert.ok(capturedUserContent.includes('"suggestion":"update tests"'));
Owner

嚴重等級🟡 警告
審查員:Maya
問題:未測試 resolveMissingLineNumberschatFn 回傳無效行號時的處理。
建議:補上測試案例:模擬 chatFn 回傳無效行號,確保其進入 fallback 邏輯。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:未測試 `resolveMissingLineNumbers` 當 `chatFn` 回傳無效行號時的處理。 **建議**:補上測試案例:模擬 `chatFn` 回傳無效行號,確保其進入 fallback 邏輯。
admin marked this conversation as resolved
@@ -0,0 +18,4 @@
const f = parseBotReviewComment(reviewBody('🔴 嚴重', 'Assassin', '可能空指標', '加上 null 檢查'));
assert.deepEqual(f, { level: 'critical', role: 'Assassin', problem: '可能空指標', suggestion: '加上 null 檢查' });
});
Owner

嚴重等級🟡 警告
審查員:Maya
問題:在 parseBotReviewComment 的測試中,沒有驗證解析失敗時的行為。
建議:補上邊界測試:輸入不完整的內容,驗證函數是否正確回傳 null

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:在 `parseBotReviewComment` 的測試中,沒有驗證解析失敗時的行為。 **建議**:補上邊界測試:輸入不完整的內容,驗證函數是否正確回傳 `null`。
admin marked this conversation as resolved
@@ -0,0 +130,4 @@
const verdicts = await judgeConversations(items, chatFn);
assert.deepEqual(verdicts, [
{ idx: 0, verdict: 'open' },
{ idx: 1, verdict: 'resolved' },
Owner

嚴重等級🔵 建議
審查員:Maya
問題judgeConversations 的測試中,未對「AI 回傳空陣列」或「所有 Verdict 皆為空」的情境進行邊界驗證。
建議:補上邊界測試,驗證該情境下是否將所有對話歸類為 open(保守保留)。

**嚴重等級**:🔵 建議 **審查員**:Maya **問題**:`judgeConversations` 的測試中,未對「AI 回傳空陣列」或「所有 Verdict 皆為空」的情境進行邊界驗證。 **建議**:補上邊界測試,驗證該情境下是否將所有對話歸類為 `open`(保守保留)。
admin marked this conversation as resolved
admin added 1 commit 2026-06-23 07:45:59 +00:00
chore: update ai-review findings [ai-review-bot][failure]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 2s
66e42d605c
jiantw83 added 2 commits 2026-06-23 07:50:43 +00:00
jiantw83 added 1 commit 2026-06-23 08:25:20 +00:00
test: 提前清理成品
AI / 計算版本號 (pull_request) Successful in 19s
AI / Code Review (pull_request) Failing after 1s
b0b8560090
jiantw83 added 1 commit 2026-06-23 08:27:15 +00:00
Revert "test: 提前清理成品"
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Successful in 50s
e770952238
This reverts commit b0b8560090.
Owner

🤖 AI Code Review 團隊

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

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
admin reviewed 2026-06-23 08:28:08 +00:00
admin left a comment
Owner

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 0 筆 2 筆 0 筆 0 筆
舊問題 0 筆 0 筆 0 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 10 次呼叫)

提示 token 回應 token 合計
281,006 6,567 366,580

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 0 筆 | 2 筆 | 0 筆 | 0 筆 | | 舊問題 | 0 筆 | 0 筆 | 0 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 10 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 281,006 | 6,567 | 366,580 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -0,0 +143,4 @@
}
}
/**
Owner

嚴重等級🟡 警告
審查員:Rogue
問題:在 recordRateLimit 中頻繁呼叫 lowerCaseKeys,這會對每個請求的 headers 進行複製與轉換,增加記憶體分配開銷。
建議:建議直接存取 headers 時改用不區分大小寫的存取函式,避免複製整個物件。

**嚴重等級**:🟡 警告 **審查員**:Rogue **問題**:在 `recordRateLimit` 中頻繁呼叫 `lowerCaseKeys`,這會對每個請求的 headers 進行複製與轉換,增加記憶體分配開銷。 **建議**:建議直接存取 headers 時改用不區分大小寫的存取函式,避免複製整個物件。
@@ -0,0 +237,4 @@
it('summarises tokens and remaining percent on one line', () => {
const line = formatUsageStatsLine('openai', 'gpt-4o-mini', usage, { available: true, used: 1, limit: 10, remaining: 9, currency: 'USD' }, null);
assert.equal(line, '本次 openai/gpt-4o-mini: 提示100 + 回應20 = 120 token3 次呼叫);剩餘可用: 90%(帳號額度 USD 9/USD 10');
Owner

嚴重等級🟡 警告
審查員:Maya
問題formatUsageStatsLine 測試案例中,僅驗證了單一平台的格式,缺失了當 quotarate 資料缺失或包含無效數字(如 NaN)時的處理測試。
建議:補充針對 quotarate 傳入異常資料(如 limit: NaN)的測試,驗證 formatUsageStatsLine 是否能產生安全的預設文字,而非輸出 NaN 或破壞版面。

**嚴重等級**:🟡 警告 **審查員**:Maya **問題**:`formatUsageStatsLine` 測試案例中,僅驗證了單一平台的格式,缺失了當 `quota` 或 `rate` 資料缺失或包含無效數字(如 `NaN`)時的處理測試。 **建議**:補充針對 `quota` 或 `rate` 傳入異常資料(如 `limit: NaN`)的測試,驗證 `formatUsageStatsLine` 是否能產生安全的預設文字,而非輸出 `NaN` 或破壞版面。
admin added 1 commit 2026-06-23 08:28:10 +00:00
chore: update ai-review findings [ai-review-bot][success]
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Successful in 3s
f4cb5b15a3
jiantw83 merged commit 6773bfd926 into develop 2026-06-23 08:29:37 +00:00
jiantw83 deleted branch ai-review-resolve/20260623-110950 2026-06-23 08:29:38 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: old-actions/code-review#42