docs(ai-review 對話收斂): 補階段十三 PR 對話收斂流程與驗收說明
AI / 計算版本號 (pull_request) Successful in 2s
AI / Code Review (pull_request) Failing after 2m46s

This commit is contained in:
Jeffery
2026-06-23 11:09:50 +08:00
parent 7a29a5be1c
commit 374253d4cf
2 changed files with 12 additions and 1 deletions
+7 -1
View File
@@ -11,8 +11,9 @@
- 若有提供 `GITEA_COMMENT_TOKEN`,額外用它驗證可用(呼叫 `GET /api/v1/user`),確保後續發 comment 不會因 token 失效而中斷
- git push 認證可用:用與第 8 點 commit/push 完全相同的 askpass + remote URL 機制跑一次唯讀的 `git ls-remote`,提前抓出 askpass 無法執行或 HTTP 認證失敗(例如 `could not read Username`)的問題。此路徑與上面的 REST API 不同,API token 有效不代表 git push 一定能用,故獨立驗證
- 已選定一個 LLM provider,且其 API Key 至少有一把通過驗證:實際送出一個最小請求確認認證可用;逗號分隔的多把 Key 只要一把成功即可,逐把記錄成敗;Ollama 無 Key,改為檢查 `OLLAMA_BASE_URL` 可連線
2.5. PR 對話收斂(前置驗證通過、且非 AI 助理自動提交後):讀取 PR 上所有行內 review comment,依「檔案路徑+行號」收斂成對話,跳過已 resolve 的對話;取每個對話所在檔案在 PR head 的最新內容,請 AI 判斷該對話指出的問題是否已解決。已解決者呼叫 Gitea 官方 API(`POST /repos/{repo}/pulls/comments/{id}/resolve`)解決對話,並在後續 Step4 從問題清單移除對應問題;未解決且可解析回 bot finding 格式者,於 Step4 加回問題清單(涵蓋「問題仍在但 `findings.json` 已遺漏」的情況)。納入判斷的對話包含所有人的留言;任一外部呼叫失敗都降級為「視為未解決」,不中斷整體流程
3. 檢查是否為 AI 助理自動提交;若不是,選定 LLM provider/model、載入角色、取得 PR diff,將服務名稱、模型名稱與角色資訊 Comment 到 Pull Request,並讓每個角色個別分析 Git Diff 產生新問題表格(問題等級、角色名稱、問題位置或行數、修改建議)
4. 讀取來源分支中的所有未解決舊問題(問題檔案 `.gitea/ai-review/findings.json`)加上新問題後,去除重複產生本次 PR 的問題表格(PR問題表格)覆蓋問題檔案
4. 讀取來源分支中的所有未解決舊問題(問題檔案 `.gitea/ai-review/findings.json`),先套用步驟 2.5 的對話收斂結果(移除已解決對話對應的問題、加回未解決但已遺漏的問題;以「檔案路徑+建議內容」比對,避免行號漂移誤判),再加上新問題後,去除重複產生本次 PR 的問題表格(PR問題表格)覆蓋問題檔案
5. 讀取來源分支中的排除問題檔案(`.gitea/ai-review/exclusions.json`),用來過濾 PR 問題表格中不需要處理的問題
6. 將 PR 問題表格寫入 `.gitea/ai-review/findings.json`,並發布一個 Gitea Review:Review 本文只統計本次新發現的問題,使用「嚴重/警告/建議」三欄呈現各等級數量;之後將可找出檔案與行數的問題依照嚴重等級排序後加入 Review Comments 內,每個 Comment 包含嚴重等級/審查員/問題/建議,其中「問題」是審查員判斷該處有問題的原因,不是檔案路徑或行號
7. 驗證來源分支中的 `findings.json``exclusions.json` 是否為合法 JSON array;格式錯誤時先嘗試透過 AI 修正內容,再重新驗證;修正後仍不合法才 exit 1;檔案不存在則建立並寫入 `[]`
@@ -32,6 +33,11 @@
9. 傳給 AI 的 findings 只保留必要欄位(level、role、location、problem、suggestion),排除 `is_new` 等內部欄位;system prompt 精簡為指令核心;exclusions hint 只傳 location 與 suggestion,減少 token 用量
10. 執行時會額外記錄來源分支狀態、`findings.json` / `exclusions.json` 的檔案路徑、大小、mtime 與 raw/normalized 筆數,方便追查讀檔與分支內容不一致的問題
11. action 一啟動就先做「前置驗證」(流程第 2 點):集中檢查 Gitea REST API token、comment token、git push 認證與 LLM 的所有驗證相關設定是否可用,全部通過才往下跑。驗證邏輯獨立成 `app/preflight.js`git push 驗證委派給 `app/git.js``verifyRemoteAccess`),由 `main.js` 在 Step1 之後、其餘步驟之前呼叫;任何一項失敗都印出是哪一項、原因為何後 `exit 1`,避免在分析到一半、發 comment 或最後 push 時才因 token / key / 認證無效而中斷
12. PR 對話收斂(流程第 2.5 點)邏輯獨立成 `app/resolve.js`,由 `main.js` 在前置驗證與自動提交檢查之後以 `Step2` 呼叫:
- 透過 `app/gitea.js``listAllReviewComments` 取得所有行內 review comment`groupConversations` 以「path+line」收斂並偵測 `resolver`(已解決);`reconcileConversations` 取 PR head 最新檔案內容(`getFileContentAtRef`contents API base64 解碼)取目標行附近視窗,交 `judgeConversationsResolved` 由 AI 批次判斷
- 已解決對話以官方 API `resolvePullReviewComment``POST /pulls/comments/{id}/resolve`)解決
- 與既有 findings 流程的銜接:`dropResolvedFindings` 移除已解決問題、`addCarriedFindings` 加回未解決但遺漏的問題,皆以「檔案路徑+正規化建議內容」為簽章比對,對行號漂移與標點差異穩定,避免重複
- 為降低 token 用量只送目標行附近視窗;任一外部呼叫失敗都降級為「視為未解決」並繼續流程
# 使用說明
+5
View File
@@ -69,3 +69,8 @@
- 驗收:log 中能看到 `Step1.5`(或對等)前置驗證的每一項結果(成功/失敗),任一失敗時 log 指出是哪一項與錯誤訊息,且 workflow 狀態為失敗;全部通過時 log 出「前置驗證通過」後才進入後續流程;驗證邏輯由 `app/preflight.js` 提供並有單元測試覆蓋(成功、缺環境變數、Gitea token 無效、comment token 無效、所有 LLM key 失敗、Ollama base url 等情境)。
- 補充紀錄:前置驗證不應發布任何 PR comment,只做唯讀的認證/連線確認;LLM 驗證請用最小 payload,避免浪費 token。
- 已驗收:`app/preflight.js` 提供 `checkRequiredEnv` / `verifyGiteaToken` / `verifyCommentToken` / `verifyLLM` / `runPreflight`git push 認證驗證由 `app/git.js``verifyRemoteAccess``git ls-remote`)提供;`main.js` 已在 Step1 之後、bot-check 之前呼叫 `runPreflight(WORKSPACE)`,未通過即印出原因並 `exit 1``app/preflight.test.js``app/git.test.js` 覆蓋上述情境(含 git push 認證成功/失敗、token 不外洩、askpass 清理),`node --test *.test.js` 全數通過。
## 階段十三:PR 對話收斂(讀留言判斷解決狀態)
- 目標:前置驗證通過、且非 AI 助理自動提交後(Step2),讀取 PR 上所有行內 review comment 並收斂成對話,請 AI 對照 PR head 最新程式碼判斷每個對話指出的問題是否已解決:已解決者用 Gitea 官方 API resolve 對話,並在 Step4 從問題清單移除;未解決且可解析回 bot finding 者,於 Step4 加回問題清單。納入判斷的對話包含所有人的留言;任一外部呼叫失敗都降級為「視為未解決」,不中斷流程。
- 驗收:log 中能看到 `Step2` 的對話總數/已解決/待判斷統計,以及 `對話已解決並 resolve: <path>:<line>``對話收斂完成: resolved=.. unresolved=.. 加回 findings=..`Step4 能看到 `對話收斂套用: N -> M 筆`resolve / list comments / 取檔案內容 / AI 判斷任一失敗時有對應降級警告。
- 已驗收:`app/resolve.js` 提供 `parseBotReviewComment` / `groupConversations` / `codeWindow` / `judgeConversationsResolved` / `reconcileConversations` / `dropResolvedFindings` / `addCarriedFindings``app/gitea.js` 新增 `listPullReviews` / `getPullReviewComments` / `listAllReviewComments` / `resolvePullReviewComment` / `getFileContentAtRef``main.js``Step2` 呼叫並於 `Step4` 套用結果;`app/resolve.test.js` 與擴充後的 `app/gitea.test.js` 覆蓋解析、收斂、AI 判斷對齊、resolve/降級、移除/加回去重等情境,`node --test *.test.js` 全數通過。