feat/pr-comments-and-fix/main #47

Merged
admin merged 6 commits from feat/pr-comments-and-fix/main into master 2026-09-17 08:48:24 +00:00
Member

摘要

/sdlc-fix:reviewer 留完意見,跑這一段,三類留言被逐條處理並回覆,不漏掉任何一則。

需求議題

#1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組

工作包議題

#14 — 以 sdlc-fix 處理 PR 留言

變更內容

commit 內容
feat(pr-comments) / test(pr-comments) 讀 PR 上的三類留言
feat(pr-reply) / test(pr-reply) 回覆一則 PR 留言並標記已處理
feat(sdlc-fix) / test(sdlc-fix-assets) 新增 sdlc-fix 流程正本

新增 scripts/pr-comments.js、scripts/pr-reply.js、prompts/sdlc-fix.md。全部是新檔,
未改動任何既有檔案。

設計重點

  • 讀寫分開兩支。 pr-comments 只讀不寫,pr-reply 一次處理一則。對應既有的
    issue-extract/issue-update 分野,也讓「讀留言」這個動作不會有副作用。
  • 三類留言的「已處理」機制不同:一般留言與 review 總評用 +1 reaction,行內留言用
    resolve。契約把差異收斂成 已處理 與 可標記 兩個欄位,下游不必自己判斷。
  • 已處理 認的是自己打的 +1。 reviewer 對留言按讚是「我同意」,不是「這則處理過
    了」——當成已處理會讓那一則被靜靜跳過,而「不漏掉任何一則」正是這個指令的目的。
  • 位置不由呼叫端給。 pr-reply 拿留言 id 去查出檔案、行號、在哪一側、屬於哪個
    commit。手抄行號是這一段最容易錯的地方。
  • 分類與詢問留在正本。 必改/建議的判斷、不確定時停下來問、最後那則摘要,腳本擋不住,
    只有正本做得到。

解決的問題

Code review 抓出五個缺陷,都已修掉並各自補上回歸測試。其中第一個是我自己造成的:

1. 我把未經查證的推測寫成了「平台限制」。 初版斷言 review 總評既沒有 reaction 也沒有
resolve、因此「標不了」,並把這句話寫進程式碼註解與正本。實測推翻:

用 review id (1062) 打 reactions        → 404
用 timeline 給的 comment id (10176) 打  → 200

Gitea 的 review 總評在 issue comment 表裡另有一份,timeline 的 type: 'review' 項目
帶著 review_id 可以對應。三類都標記得了,只是總評的 id 要換個地方拿。把猜測寫成
已知限制,會被後面的人當成前提——比程式有 bug 更難發現。

2. 三類清單有兩類沒分頁。 這個站台的預設頁大小是 30:第 31 個 review 之後,
總評與它底下的行內留言整批消失,而 pr-reply 還會對合法的 id 報 COMMENT_NOT_FOUND。

3. 留在刪除行的留言位置抓不到。 Gitea 只填 position 與 original_position 其中
一個。只讀前者,留在被刪掉那一行的留言得到 undefined,回覆會落到別的地方去。

4. 回覆沒帶 commit_id。 PR 之後又推了新 commit 的話,同一個行號在新 commit 上指的
是別的程式碼。

5. 已處理 不分是誰打的 +1。 見上面「設計重點」。

影響的功能

  • 全部是新檔,沒有改動任何既有腳本或正本;lib.js 的 pages/preflight 照既有用法使用。
  • /sdlc-fix 產出的修正摘要只印在終端,不自動張貼到 PR、也不改 PR 的 review 狀態。
  • 被 #41(pr-watch)與 #42(sdlc-fix 定位工作樹)擋著的兩顆工作包,在此之後解除阻擋。

待裁示:pr-reply 不在議題 #1 的腳本清單裡(#1 只列了 pr-comments)。讀寫分離的理由
如上,而 schedule/prompt/status 也都是後來加進來的前例。建議把 pr-reply 補進 #1
的清單,或指示我把兩支合併。

測試結果

在最新 master(3084c910,已含 worktree 那條線的 #46)之上實際執行 npm test:

ℹ tests 691
ℹ suites 0
ℹ pass 691
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0

master 既有 633,本分支新增 58。該分支的 lib.js 在本工作包進行期間被別的工作包改過,
已在改動後的版本上重跑確認相容。

三類留言的讀取、三種「已處理」機制、分頁、刪除行的位置、PENDING 的 review、空留言與系統
事件各有覆蓋;pr-reply 的三類回覆路徑、先回覆後標記的順序、回覆失敗不標記、輸出形狀
固定也都釘住。

實機驗證(Gitea 1.27.0):reaction 端點對 review id 回 404、對 timeline 給的 comment id
回 200;pulls/comments/{id}/resolve 端點存在;本 repo 既有 PR 上那些 APPROVED 但
body 為空的 review 確實不該被當成總評,實作也確實跳過了它們。

🤖 Generated with Claude Code

## 摘要 `/sdlc-fix`:reviewer 留完意見,跑這一段,三類留言被逐條處理並回覆,不漏掉任何一則。 ## 需求議題 #1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組 ## 工作包議題 #14 — 以 sdlc-fix 處理 PR 留言 ## 變更內容 | commit | 內容 | | --- | --- | | `feat(pr-comments)` / `test(pr-comments)` | 讀 PR 上的三類留言 | | `feat(pr-reply)` / `test(pr-reply)` | 回覆一則 PR 留言並標記已處理 | | `feat(sdlc-fix)` / `test(sdlc-fix-assets)` | 新增 sdlc-fix 流程正本 | 新增 `scripts/pr-comments.js`、`scripts/pr-reply.js`、`prompts/sdlc-fix.md`。全部是新檔, 未改動任何既有檔案。 ## 設計重點 - **讀寫分開兩支。** `pr-comments` 只讀不寫,`pr-reply` 一次處理一則。對應既有的 `issue-extract`/`issue-update` 分野,也讓「讀留言」這個動作不會有副作用。 - **三類留言的「已處理」機制不同**:一般留言與 review 總評用 `+1` reaction,行內留言用 resolve。契約把差異收斂成 `已處理` 與 `可標記` 兩個欄位,下游不必自己判斷。 - **`已處理` 認的是自己打的 `+1`。** reviewer 對留言按讚是「我同意」,不是「這則處理過 了」——當成已處理會讓那一則被靜靜跳過,而「不漏掉任何一則」正是這個指令的目的。 - **位置不由呼叫端給。** `pr-reply` 拿留言 id 去查出檔案、行號、在哪一側、屬於哪個 commit。手抄行號是這一段最容易錯的地方。 - **分類與詢問留在正本。** 必改/建議的判斷、不確定時停下來問、最後那則摘要,腳本擋不住, 只有正本做得到。 ## 解決的問題 Code review 抓出五個缺陷,都已修掉並各自補上回歸測試。其中第一個是我自己造成的: **1. 我把未經查證的推測寫成了「平台限制」。** 初版斷言 review 總評既沒有 reaction 也沒有 resolve、因此「標不了」,並把這句話寫進程式碼註解**與正本**。實測推翻: ``` 用 review id (1062) 打 reactions → 404 用 timeline 給的 comment id (10176) 打 → 200 ``` Gitea 的 review 總評在 issue comment 表裡另有一份,`timeline` 的 `type: 'review'` 項目 帶著 `review_id` 可以對應。三類**都標記得了**,只是總評的 id 要換個地方拿。把猜測寫成 已知限制,會被後面的人當成前提——比程式有 bug 更難發現。 **2. 三類清單有兩類沒分頁。** 這個站台的預設頁大小是 **30**:第 31 個 review 之後, 總評與它底下的行內留言整批消失,而 `pr-reply` 還會對合法的 id 報 `COMMENT_NOT_FOUND`。 **3. 留在刪除行的留言位置抓不到。** Gitea 只填 `position` 與 `original_position` 其中 一個。只讀前者,留在被刪掉那一行的留言得到 `undefined`,回覆會落到別的地方去。 **4. 回覆沒帶 `commit_id`。** PR 之後又推了新 commit 的話,同一個行號在新 commit 上指的 是別的程式碼。 **5. `已處理` 不分是誰打的 `+1`。** 見上面「設計重點」。 ## 影響的功能 - 全部是新檔,沒有改動任何既有腳本或正本;`lib.js` 的 `pages`/`preflight` 照既有用法使用。 - `/sdlc-fix` 產出的修正摘要只印在終端,不自動張貼到 PR、也不改 PR 的 review 狀態。 - 被 `#41`(pr-watch)與 `#42`(sdlc-fix 定位工作樹)擋著的兩顆工作包,在此之後解除阻擋。 **待裁示**:`pr-reply` 不在議題 #1 的腳本清單裡(#1 只列了 `pr-comments`)。讀寫分離的理由 如上,而 `schedule`/`prompt`/`status` 也都是後來加進來的前例。建議把 `pr-reply` 補進 #1 的清單,或指示我把兩支合併。 ## 測試結果 在**最新 master**(`3084c910`,已含 worktree 那條線的 #46)之上實際執行 `npm test`: ``` ℹ tests 691 ℹ suites 0 ℹ pass 691 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ``` master 既有 633,本分支新增 58。該分支的 `lib.js` 在本工作包進行期間被別的工作包改過, 已在改動後的版本上重跑確認相容。 三類留言的讀取、三種「已處理」機制、分頁、刪除行的位置、PENDING 的 review、空留言與系統 事件各有覆蓋;`pr-reply` 的三類回覆路徑、先回覆後標記的順序、回覆失敗不標記、輸出形狀 固定也都釘住。 實機驗證(Gitea 1.27.0):reaction 端點對 review id 回 404、對 timeline 給的 comment id 回 200;`pulls/comments/{id}/resolve` 端點存在;本 repo 既有 PR 上那些 `APPROVED` 但 body 為空的 review 確實不該被當成總評,實作也確實跳過了它們。 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jiantw83 added 6 commits 2026-09-17 08:47:30 +00:00
一般留言、review 總評、行內留言分散在三個端點,漏掉任何一類就會有意見沒被處理——
而那正是 /sdlc-fix 存在的理由。只讀不寫,必改/建議的分類由讀到內容的人判斷。

三類的「已處理」機制不同:一般留言與總評看自己打的 +1,行內留言看有沒有被 resolve。
總評的 reaction 掛在它在 issue comment 表裡那一份的 id 上,由 timeline 對應得出來;
拿 review 自己的 id 去打會 404,兩個 id 不同命名空間。

reaction 要是自己打的才算已處理:reviewer 對留言按讚是「我同意」,不是「這則處理過了」,
當成已處理會讓那一則被靜靜跳過。

行內留言的位置分兩側:新檔那側在 position,被刪掉的那行在 original_position,Gitea 只填
其中一個。輸出把兩者收斂成「行」與「側」,回覆時才知道該送哪個欄位。也帶出 commit,
讓回覆落在原留言的那個 commit 上。

三種清單都逐頁讀完:這個站台的預設頁大小是 30,沒分頁的話第 31 個 review 之後整批消失。
一般留言、review 總評、行內留言分散在三個端點,漏掉任何一類就會有意見沒被處理——
而那正是 /sdlc-fix 存在的理由。只讀不寫,必改/建議的分類由讀到內容的人判斷。

三類的「已處理」機制不同:一般留言與總評看自己打的 +1,行內留言看有沒有被 resolve。
總評的 reaction 掛在它在 issue comment 表裡那一份的 id 上,由 timeline 對應得出來;
拿 review 自己的 id 去打會 404,兩個 id 不同命名空間。

reaction 要是自己打的才算已處理:reviewer 對留言按讚是「我同意」,不是「這則處理過了」,
當成已處理會讓那一則被靜靜跳過。

行內留言的位置分兩側:新檔那側在 position,被刪掉的那行在 original_position,Gitea 只填
其中一個。輸出把兩者收斂成「行」與「側」,回覆時才知道該送哪個欄位。也帶出 commit,
讓回覆落在原留言的那個 commit 上。

三種清單都逐頁讀完:這個站台的預設頁大小是 30,沒分頁的話第 31 個 review 之後整批消失。
「回在原本那一串底下」對三類是三件不同的事。行內留言沒有「回覆某一則」的端點,
把新留言指向同一個檔案與同一行,Gitea 才會把它排在原留言底下——位置是串的識別。位置不由
呼叫端給而是拿 id 查出來:手抄行號是這一段最容易錯的地方。回覆還帶上原留言的 commit_id,
否則 PR 之後又推了新 commit 時,同一個行號指的是別的程式碼。

標記排在回覆之後,回覆沒成功就不標記:沒回就標記等於謊稱處理過。

輸出三類同形:用不到的欄位填 null 而不是讓它消失,下游不必為了少一欄多寫一種分支。
「回在原本那一串底下」對三類是三件不同的事。行內留言沒有「回覆某一則」的端點,
把新留言指向同一個檔案與同一行,Gitea 才會把它排在原留言底下——位置是串的識別。位置不由
呼叫端給而是拿 id 查出來:手抄行號是這一段最容易錯的地方。回覆還帶上原留言的 commit_id,
否則 PR 之後又推了新 commit 時,同一個行號指的是別的程式碼。

標記排在回覆之後,回覆沒成功就不標記:沒回就標記等於謊稱處理過。

輸出三類同形:用不到的欄位填 null 而不是讓它消失,下游不必為了少一欄多寫一種分支。
分類必改/建議、不確定時停下來問、最後那則摘要——這三件腳本擋不住,只有正本做得到。

標不了的那幾則要在摘要裡單獨點出來,否則 reviewer 掃 reaction 與 resolve 時會以為它們
被跳過了。留言指向的程式碼已被改掉時不要硬試,列進「無法處理」讓使用者自己回。
分類必改/建議、不確定時停下來問、最後那則摘要——這三件腳本擋不住,只有正本做得到。

標不了的那幾則要在摘要裡單獨點出來,否則 reviewer 掃 reaction 與 resolve 時會以為它們
被跳過了。留言指向的程式碼已被改掉時不要硬試,列進「無法處理」讓使用者自己回。
admin approved these changes 2026-09-17 08:48:20 +00:00
admin merged commit 86bdfd9007 into master 2026-09-17 08:48:24 +00:00
admin deleted branch feat/pr-comments-and-fix/main 2026-09-17 08:48:24 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: plugins/tea-sdlc#47