Refactor Scan
偵測,絕不擅自寫入。 提出接下來可以進行的工作,並留意自上次巡迴後已自行解決的事項——絕不建立議題,也絕不決定結果。refactor-design 會為已選擇的工作建立議題;refactor-learn 則根據此技能偵測到的結果採取行動。
流程
1. 檢查前置條件
- 沒有 Git 儲存庫 → 停止本次巡迴,報告此事,不提出任何建議。
- 有五個或以上的開啟中
refactor:candidate議題 → 停止,不提出新的建議;讓現有工作先處理完畢。
2. 先恢復待辦工作
讀取重構筆記的 bookkeeping.md 中的 Pending candidates 欄位(skills/continuous-refactoring/references/refactoring-bookkeeping.md)。若其中有命名一個議題,表示前一次巡迴的 refactor-design 已建立該議題,但在提出合併請求之前被中斷。直接提出該議題並停止——完成待辦工作優先於提出新的工作。
3. 偵測已關閉/已合併的記憶狀態
取得記住的集合——docs/agents/issue-tracker.md 命名了一個原生標籤追蹤器(GitHub、GitLab)→ 每個開啟中的 refactor:candidate 議題,各自解析出其連結的拉取請求(透過追蹤器本身的原生議題↔關閉 PR 交叉參照,refactor-implement 步驟 5 已經將 Closes #<n> 放入交付的合併請求中);尚未有連結 PR 的議題則無需在此步驟進行調整。否則 → 讀取重構筆記中 merge-requests.md 的每個條目。對每個條目檢查外部追蹤器/git:該 MR 是否仍開啟?該議題是否仍開啟?
若無 gh/glab(或其他 forge API/權杖)可用 → 退回純 git 調解,而不是跳過此步驟(也絕不在此嘗試安裝 gh/glab——將其缺失視為此回退的觸發條件):skills/refactor-scan/references/git-only-reconciliation.md。若完全沒有遠端(git remote -v 為空)→ 同一檔案的本機變體——記住的候選可能已被僅在本機操作的人類合併或拒絕,根據 opening-a-merge-request.md 的「無 forge/遠端可用」說明。
-
已合併 → 發現:已交付。
-
已關閉但未合併 → 發現:已拒絕——注意關閉評論是否給出了維護者的結構性原因(超出範圍的材料)或未給出。
-
仍開啟,且有審查者活動(審查或評論)比分支的最後提交更新 → 這是恢復候選,而非發現——沒有人對此做出決定,只是需要再檢查一次。若有 API 存取權限 → 同時讀取實際的審查狀態與時間戳記(
gh pr view <n> --json reviews,reviewDecision或等效指令)——不要僅因「有變化」就停下:CHANGES_REQUESTED,且未處理(沒有比審查更新的提交)→ 仍然是恢復候選,但除了分支之外,也要將審查本身的評論/主體內容一併傳遞——refactor-implement步驟 1 會讀取並處理該特定回饋,而不只是從頭重新檢查分支。- 有評論,或
APPROVED審查且無阻擋性回饋 → 現有的通用恢復候選處理方式;無需附加其他事項。
按照步驟 2 傳遞
Pending candidates條目的方式傳遞:直接交給refactor-implement,跳過refactor-prioritize/refactor-design(它已經有設計和開啟中的 MR;僅適用修復迴圈——refactor-implement步驟 1 已經支援恢復現有分支)。沒有 API 存取(純 git 回退)→ 審查狀態無法取得,正如git-only-reconciliation.md所記錄;此處的改進不適用。 -
仍開啟,且無任何變化 → 沒有發現。
同時檢查重構筆記中 out-of-scope/<node>.md 的每個條目,尋找命名了 **Blocked by:** PHP >= X.Y 條件的項目(tooling_tree.py 的 detect_nodes() 在執行時會直接報告此資訊;若手動操作,則將目標目前的 composer.json require.php/config.platform.php 與之比較)——若目標目前的 PHP 版本現在滿足該條件,則是發現:此拒絕被撤銷了。沒有 Blocked by: 欄位,或條件仍未滿足 → 絕不是發現。
將所有發現交給 refactor-learn——此技能僅負責通知;絕不將任何事項標記為 done/wontfix,也絕不自行寫入重構筆記的 out-of-scope/ 目錄。
3b. 偵測外部標籤的候選
若有 API 存取權限(非純 git 回退)→ 同時查詢尚未被計算在內的開啟中 refactor:candidate 議題:不是步驟 2 的 Pending candidates 條目,也不是步驟 3 的記憶集合(有連結拉取請求的議題已在進行中)。剩下的就是人類(或其他程序)直接標籤的候選,此套件從未對其進行設計或實作——在正常操作中,套件自己的候選總是屬於上述兩者之一,因此無需額外區分「我們的」與「別人的」。將每個此類候選作為提案傳遞,與步驟 4 的工具樹提案一起加入列表——refactor-prioritize 會根據其通常的因子與所有其他提案一起排序;它僅因存在而競爭,絕不會因此插隊。沒有 API 存取(純 git 回退)→ 完全跳過此步驟,僅使用 git 無法按標籤枚舉議題。
4. 提出工具樹節點
如果步驟 2 已提出待辦候選,則跳過此步驟。
執行 python3 skills/refactor-scan/references/tooling_tree.py <target-repo> 並讀取 JSON 的 next 欄位——實際的、目前未被阻擋的集合,已排除被拒絕的節點(重構筆記 out-of-scope/<node>.md 中已有的條目),無論有多少條目都照單全收。不是 roadmap(前瞻模擬,不是當前的實際選項)。同時讀取 withheld:那些原本會在 next 中,但因等待一個未決定的建議父節點而被保留的節點——每個條目會命名其等待的父節點。沒有 python3,或不被允許 → 派遣一個子代理,使用 skills/refactor-scan/references/tree-walk-prompt.md 的提示({N}=all)——它會手動走訪相同的樹文檔(先讀取重構筆記 bookkeeping.md 的 Fulfilled nodes 以跳過重新推導快取狀態,跳過任何有 out-of-scope 條目的節點);沒有子代理機制 → 自行內聯執行其步驟。
- 普通工具節點(
loop-config,以及語言特化節點,例如skills/refactor-scan/references/php-tooling-tree.md)——以其名稱(絕非原始 slug)提出;每個節點在其樹文檔中已完全指定。 structural-scan——在每個以resolved邊指向它的節點都解決(已履行,或根據重構筆記的out-of-scope/明確拒絕)後提出:editorconfig(在通用根節點下),加上活躍語言特化自身的聚合節點(PHP:php-structural-scan),而該聚合節點本身在其每個 resolved 父節點都解決後才解決(skills/refactor-scan/references/tooling-tree.md)。僅structural-scan會以這種方式提出——php-structural-scan是純管道,絕不是候選。提出它只是命名它;程式碼庫的走訪發生在refactor-design中,僅針對實際被選擇的節點。- 未識別到語言樹:
structural-scan仍然等待editorconfig(通用根葉節點)——不會因為沒有語言特定樹可應用就立即變得可提出。
輸出
由協調器直接傳遞:
- 哪個前置條件停止了本次巡迴(如果有的話)——本次巡迴不適用以下項目。
- 發現(可能為空)→
refactor-learn。 - 恢復候選(如果偵測到的話)→ 直接交給
refactor-implement,跳過refactor-prioritize/refactor-design。 - 提案——單獨的待辦候選,或每個目前未被阻擋的節點的名稱(絕非 slug,無上限)加上步驟 3b 的任何外部標籤候選,或無提案 →
refactor-prioritize。每個目前未被阻擋的節點(必需的父節點已履行、未被拒絕、每個建議的父節點已確定)——絕非優先級截斷的子集。同時,列出每個withheld節點以及它正在等待的父節點(例如「Rector: Type Coverage Set — 等待中:PHP CS Fixer」)。
完成條件
發現(如果有的話)已交給 refactor-learn,恢復候選(如果有的話)已直接交給 refactor-implement,提案(如果有的話)已交給 refactor-prioritize——或者前置條件停止了本次巡迴,且報告說明了是哪個。絕不會有節點與 structural-scan 之後的條目出現在同一個列表中。