name: sdlc-fix description: 僅由 /sdlc-fix 指令叫用。收 PR 或議題編號:PR 就定位工作樹、逐條處理三類留言並回覆;議題則交棒給 /sdlc-feat。 # sdlc-fix reviewer 留完意見,跑這一段,意見被逐條處理並回覆,不漏掉任何一則。 **意見不一定發在 PR 上。** 常常是發在工作包議題或需求議題的留言裡:使用者手上只有一個 議題編號,看得到有人說「這裡要改」。所以輸入收得下三種東西,但只有 PR 在這裡處理完—— 議題交棒給 `/sdlc-feat`,不在這裡重做一遍它的流程。 這份檔案是流程正本。各平台的轉接檔只是指回這裡,不要把規則抄過去。 ## 輸入 一個 PR 編號或議題編號。 ## 1. 判定輸入是哪一種 三種輸入走三條不同的路,先問清楚是哪一種再動手。**判定沿用既有契約,不另發明判準**—— 標籤、標題前綴、編號區間都猜得出來,但猜錯的代價是整條路走錯。 先讀一次留言。它議題與 PR 都收得下,`類型` 欄位就是 PR 與議題的分界: ``` node scripts/pr-comments.js --repo --index <編號> ``` **每個 PR 都是議題,反過來不成立**,所以這個問題只能從議題那一端問:先打 PR 的端點, 遇到純議題會 404,在讀到第一則留言之前就斷了。 `類型` 是 `議題` 時再問一次它是哪一種議題: ``` node scripts/wp-extract.js --repo --index <編號> ``` **`需求議題` 欄位(工作包的母議題)解析得出編號的就是工作包議題,解析不出來的就當需求 議題。** 這是工作包抽取契約本來就有的欄位,`/sdlc-sync` 分這兩種議題用的也是同一份抽取。 | 判定 | 下一步 | | --- | --- | | `類型` 為 `PR` | 第 3 步起,這份正本後面每一步都是 PR 的路 | | `類型` 為 `議題`,抽得出 `需求議題` | 第 2 步的「工作包議題」 | | `類型` 為 `議題`,抽不出 `需求議題` | 第 2 步的「需求議題」 | ## 2. 議題:交棒給 /sdlc-feat ### 工作包議題 那一顆工作包該怎麼做,`/sdlc-feat`(`prompts/sdlc-feat.md`)已經從領取、備妥工作樹、 逐項實作一路定到開出 PR。**照那份正本走,把這個編號當成它的輸入。** **不要把它的步驟搬過來重講一遍**:那會製造第二份正本,兩邊遲早分岔——而使用者不會知道 自己讀到的是哪一份。 交棒沿用 `/sdlc-sync` 那一套接回機制,只是方向相反:**直接接下去做,不要求使用者重打 指令**。他已經給過這個編號了。 留言的整併不必在這裡先做——`/sdlc-feat` 的第一步就會看 `未處理留言數`,該整併時它自己 會轉去 `/sdlc-sync`。在這裡先做一次,等於把那一步也抄了過來。 ### 需求議題 需求議題上的留言**絕大多數是決策討論**,不是「這一行要改」。所以先整併,再談改碼: 1. 第 1 步的 `未處理數` 大於 0 就**走 `/sdlc-sync` 的流程**(`prompts/sdlc-sync.md`), 做完**自動接回這裡**——重新讀一次留言,拿到的才是剛整併過的狀態。同樣不要求使用者重打指令。 **`未處理數` 本來就是 0 的話這一步整個跳過**,直接往下選工作包:沒有留言要整併不表示 沒有事要做,使用者是帶著「要改什麼」來的。 2. 整併(與使用者選擇略過)之後還剩下的留言裡,挑出**確實要求改程式碼**的那幾則。判斷 依據與第 5 步的「必改/建議」同一套:指出了錯誤、遺漏、會出事的寫法,或明確要求改動。 3. **本來有留言,而整併完一則要改碼的都不剩,就到此為止。** 把整併了幾則、略過幾則講清楚, 說明沒有要改碼的意見,然後停下來。先 sync 一次通常就清空了,選工作包那一步根本不會觸發。 確實有要改的(或一開始就沒有留言要整併),就列出這顆需求底下的工作包,讓使用者挑一顆: ``` node scripts/wp-list.js --repo --requirement <需求議題編號> ``` **不要因為「輸入不是工作包」就報錯。** 挑哪一顆他無論如何都要挑,報錯只是把這件事推回去 讓他自己在 Gitea 網頁上翻。 一次問一題,選項是清單上的工作包(帶編號、標題、狀態、領取人),外加**手動輸入**—— 清單以「關聯」段落認歸屬,漏掉的那一顆他自己給得出編號。附上你的判斷:哪一顆的範圍 涵蓋得到那幾則留言說的地方,以及為什麼。 清單是空的就照實說:這顆需求底下還沒有工作包,該跑的是 `/sdlc-analyze`,不是這一支。 挑定之後**交棒給 `/sdlc-feat`**,與上一小節同一條路。**把那幾則要求改碼的留言一起帶過去**, 它們是這一輪要做的事;留言本身留在需求議題上不動,交棒不搬走任何人說過的話。 ## 3. 看 PR 現況,並定位工作樹 先問一次現況,再決定要不要動手: ``` node scripts/pr-watch.js --repo --index --dry-run ``` **這裡要帶 `--dry-run`**:`pr-watch` 在 PR 已終止時會順手清掉工作樹,而這一步只是要 知道現況——清不清理是使用者的決定,不該由「我想看一下留言」這個動作順便做掉。 **`terminal` 為 `true`(PR 已合併或已關閉)時就停下來,不要繼續處理留言。** 那顆工作包 已經結束,在一棵該被清掉的工作樹上改東西是白做工,而且那些改動不會進到任何 PR 裡。 把 `suggestedAction` 的意思講給使用者聽,讓他決定下一步: | 值 | 意思 | | --- | --- | | `nothing-to-do` | 沒事了;工作樹不在或已經清掉 | | `cleanup` | 工作樹還在,可以用 `worktree-remove` 清掉 | | `blocked-dirty` | 那棵工作樹裡還有沒提交的東西,要他自己處理 | PR 還開著就定位工作樹。輸入是 `pr-watch` 給的 `branch`——路徑由「哪顆工作包」推導, 不必也不該由使用者自己去記那串雜湊目錄名: ``` node scripts/worktree-ensure.js --repo --path <目標專案路徑> \ --branch --dry-run ``` `--path` 是目標專案在本機的位置(工作包 `repos` 列的那一顆),不給就用當前目錄—— 而當前目錄多半不是它,這正是這一步要解決的問題。 試跑會印出推導出的路徑與將執行的 git 指令;確認無誤後拿掉旗標再跑一次。 **推導出的路徑不存在時它會重建,那是常態不是例外**:進度完全不寫在本機,換一台機器 或換一個 agent 接手時工作樹本來就不在,重建的成本就是一次 `git worktree add`。 重建走的是與開工時同一套建立方式,分支上已經有的進度會被接上,不是長一棵空的。 兩種會被擋下來的情況照實說,不要繞過去:`BRANCH_NOT_FOUND` 是那一支分支在本機與遠端 都不見了(多半是 PR 已經合併而分支被刪,回頭確認 PR 狀態);`WORKTREE_PATH_TAKEN` 是 推導出的路徑上有別的東西,請使用者自己確認後移除——**不要自己刪**。 **後面每一步都在那棵工作樹裡做**,不要回到主工作區:它可能停在別的分支上,在那裡改 會把改動落到別顆工作包的分支去。 ## 4. 讀留言 ``` node scripts/pr-comments.js --repo --index ``` 第 1 步判定型別時讀的就是這一份,**手上那一份還在就直接用,不必再讀一次**。 三類留言一次讀齊:**一般留言**、**review 總評**、**行內留言**。每一則都帶 `id`、`作者`、 `內容`、`已處理`,行內的還帶 `檔案`/`行`/`diff`——那段 diff 是判斷「他在說哪裡」的依據, 不要略過不看。 **先看 `未處理數`。** 它是這一輪要處理的量;`已處理` 為 `true` 的那些是前一輪做過的, 跳過不再處理。 **三類都標記得了,機制不同**:一般留言與 review 總評用 `+1` reaction,行內留言用 resolve。`已處理` 認的是**自己打的** `+1`——reviewer 對留言按讚是「我同意」,不是 「這則處理過了」。 偶爾會遇到 `可標記` 是 `false` 的總評(在 timeline 上對不到它在 issue comment 表裡的 那一份)。那一則回覆照發,但沒有記號留得下來,**要在修正摘要裡單獨點出來**。 ## 5. 分類:必改還是建議 逐則判斷,**reviewer 不必逐則說明**。判斷依據是內容本身: - **必改** — 指出了錯誤、遺漏、會出事的寫法,或明確要求改動。 - **建議** — 提出另一種做法、風格偏好、「之後可以考慮」。 分類結果**先呈現給使用者**再動手:列出每一則的「類型/作者/一句話摘要/你的分類」。 分類錯的代價不對稱——把必改當成建議會漏掉真的問題,所以拿不準時歸到必改那一邊, 並在下一步問清楚。 ## 6. 不確定就問 **一次問一題。** 下列情況不要自作主張: - 分不出必改還是建議。 - 知道要改,但有兩種以上做法,而選擇會影響別處。 - 留言本身看不懂,或它指的位置與現在的程式碼對不上(PR 之後又推了新 commit 是常見原因)。 每一題給兩個選項,並附上你判斷的理由: - **建議** — 你的答案,寫「為什麼是這個」。 - **手動輸入** — 讓使用者自己說。 **不確定卻硬改,比多問一題貴得多。** 改壞的地方 reviewer 下一輪才會看到。 ## 7. 逐則處理並回覆 一則一則來:先改,改完立刻回覆那一則,再處理下一則。**不要全部改完才一起回**—— 中途斷掉的話,沒有人知道哪幾則已經處理過。 ``` node scripts/pr-reply.js --repo --index \ --comment <留言 id> --kind inline|general|review --body '<回覆>' --dry-run ``` `--kind` 對應 `pr-comments` 給的 `類型`:`行內` → `inline`、`一般` → `general`、 `總評` → `review`。**三類留言的 id 各自獨立**,`--kind` 給錯會找不到那一則。 腳本自己會去查行內留言的位置(含它在新檔還是被刪掉的那一側)與它所屬的 commit, 把回覆放回同一串;也會在回覆成功之後才標記(行內用 resolve,一般與總評用 `+1`)。 回覆失敗就不標記——沒回卻標記等於謊稱處理過。 **留言指向的程式碼已經被改掉時**,回覆可能會被 Gitea 拒絕(位置對不上)。那時不要硬試, 把那一則列進摘要的「無法處理」,讓使用者自己去 PR 上回。 **回覆要說出做了什麼**,不是「已修正」。reviewer 看回覆就要知道改法對不對, 不必自己去翻 diff。決定不改的也要回,並說明理由——建議類的留言常常合理地不採納, 但沉默會讓 reviewer 以為被忽略了。 ## 8. 修正摘要 全部處理完後印一則摘要,讓 reviewer 不必逐串點開: - **必改幾則、建議幾則**,各自處理了幾則、不改幾則。 - **逐則一行**:作者/一句話原意/你的處置。 - **沒有留下記號的那幾則**(`可標記` 為 `false`,或腳本回報 `已標記: false`)要單獨 列出來,否則 reviewer 掃 reaction 與 resolve 時會以為它們被跳過了。 - **問過使用者的題目與答案**。 - 有沒有留言因為指向的程式碼已經變了而無法處理。 摘要只印在終端,**不自動張貼到 PR 上**。要不要貼由使用者決定。 ## 邊界 - 不改與留言無關的程式碼。順手看到的問題記下來說出來,不要摸進這一輪。 - 不自行判斷不確定的事——寧可多問一題。 - 不跳過任何一則留言。決定不改的也要回覆並說明理由。 - 不在回覆沒成功時標記已處理。 - **不自動張貼修正摘要**,也不自動關閉或合併 PR。 - 不動 PR 的 review 狀態:回覆一則意見不該順手把整個 PR 標成通過或要求變更。 - **不在主工作區處理留言**,一律在 `worktree-ensure` 定位出來的那棵工作樹裡。 - PR 已經合併或關閉時不繼續處理留言,也不自己去刪推導路徑上的東西。 - **不重做 `/sdlc-feat` 的步驟,也不把它的步驟抄進這份正本**:議題一律交棒過去。 - 不因為輸入是議題就報錯要使用者改打別的指令,也不要求他把交棒過的指令重打一次。 - 不替使用者決定要在哪一顆工作包上改:列出清單,讓他挑。