feat/implement-and-tick-todos/main #44

Merged
admin merged 5 commits from feat/implement-and-tick-todos/main into master 2026-09-17 07:42:52 +00:00
Member

摘要

/sdlc-feat 的第二段:一項一項把待辦做完並即時勾選,讓議題頁的進度條隨時反映真實狀態。
勾選以抽取契約給的 raw 做精確字串替換,只動目標那一行。

需求議題

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

工作包議題

#12 — 以 sdlc-feat 逐項實作並即時勾選待辦

變更內容

commit 內容
feat(議題解析) 勾選 checkbox 的精確替換,並統一清單項的文法
feat(issue-update) 以 --tick 勾待辦,並在沒東西可改時不送空的 PATCH
feat(規則正本) 新增實作規範與註解格式對照表
feat(流程正本) sdlc-feat 加入第二段「逐項實作」
test(逐項實作) 覆蓋勾選的五種危險、兩份規則正本與正本第二段

新增 references/coding-standards.md、references/comment-styles.md;
scripts/issue-body.js 增加 tickLine 與共用的 LIST_ITEM 文法;
scripts/issue-update.js 增加 --tick 與 --section。

設計重點

  • 勾選是 issue-body.js 裡唯一會寫回議題的路徑,所以它必須守住全檔的兩個前提:
    跳過圍欄、限定段落。理由與 upsertLineInSection 相同——弄錯的代價是靜靜改壞內容。
  • 清單項的文法收斂成一份 LIST_ITEM,抽取端(parseChecklistItem)與勾選端
    (tickLine/parseTick)共用。兩端各寫一份就會鬆緊不一致。
  • [ ]、[x]、[X] 指的是同一行。 [X] 是合法的 GFM,Gitea 也渲染成已勾。
  • --tick 只驗「是不是清單項」,不要求方框。 抽取端會把忘了寫 checkbox 的項目也收成
    一項待辦,那種 raw 要走到 tickLine 才拿得到「去議題上補成 checkbox」這句指路。
  • 規則正本由流程正本指名讀取,不在 prompts 裡複述——抄過來就會有兩份各自演化的規則。

解決的問題

Code review 抓出五個缺陷,全是「會靜靜改壞議題」那一類,都已修掉並各自補上回歸測試:

1. tickLine 繞過了圍欄判斷。 issue-body.js 全檔的前提是「圍欄裡的東西不是內容」,
而工作包模板的架構圖就是一塊 fenced mermaid——裡面出現減號開頭的行是常態。
實測:圍欄裡一行 - [ ] 甲 會被真的勾下去,改壞的是一張圖。

2. 同一個疏漏造成假的「分不出是哪一行」。 待辦與整體驗收常有一模一樣的一句話,
不限定段落就會回報 RAW_AMBIGUOUS,而使用者其實講得很清楚。新增 --section。

3. 大寫 [X] 重跑會硬失敗。 只認小寫的話,中斷後重跑得到 RAW_NOT_FOUND,
錯誤訊息還會誣指「議題被改過」——但議題沒被改過。這直接打破「中斷後自動接續」。

4. 抽取端與勾選端的文法鬆緊不一致。 - [ ]甲(方框後沒有空白)抽得出來卻勾不動,
正本那句「一律用 wp-extract 給的 raw」就成了做不到的指示。

5. --dry-run 會預告一個實跑根本不會發的請求。 「沒東西可改就不送 PATCH」的判斷
原本放在試跑分支之後。試跑印出漂亮的計畫、實跑什麼都不送,是最難查的那種落差。

影響的功能

  • scripts/issue-body.js 的 parseChecklistItem 改用共用文法,wp-extract 的輸出不變
    (既有 44 個測試全數通過)。
  • issue-update 的 --estimate-days/--overview-url 在「值沒有變化」時不再送空的 PATCH。
    空的 PATCH 會把議題的 updated_at 推新,在列表上浮起來像是有人動過。兩條既有斷言
    已更新為這個更強的保證。
  • test/helpers/stub-gitea.js 新增 patchOf,取代先前散在三個測試檔的同名複本。
  • 尚未實作的 #13 會接在這一段之後:分批提交、開立 PR、停錶。

測試結果

在最新 master(1e93b77a)的完整樹上套用本分支後實際執行 npm test:

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

master 既有 451,本分支新增 54。

勾選的測試全部繞著「會不會改錯行」打轉:圍欄裡的假 checkbox 不被動到、不同段落的
同一句話靠 --section 分得開、大寫 [X] 重跑是 no-op、方框後沒空白照樣勾得到、
沒有方框的項目給的是指路的錯誤而不是謊報已勾過。

另外釘住抽取端與勾選端的契約一致性:wp-extract 交得出來的每一種 raw
(CRLF、無空白、大寫、缺方框)--tick 都要收得下或給出指路的錯誤。這兩端是分開寫的,
先前沒有任何測試把它們接起來驗。

實機驗證:對真實議題 #12 執行 --tick --dry-run,確認只有目標那一行變 [x],
其餘七行原封不動;RAW_NOT_FOUND 的路徑也對真實 Gitea 驗過。

🤖 Generated with Claude Code

## 摘要 `/sdlc-feat` 的第二段:一項一項把待辦做完並即時勾選,讓議題頁的進度條隨時反映真實狀態。 勾選以抽取契約給的 `raw` 做精確字串替換,只動目標那一行。 ## 需求議題 #1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組 ## 工作包議題 #12 — 以 sdlc-feat 逐項實作並即時勾選待辦 ## 變更內容 | commit | 內容 | | --- | --- | | `feat(議題解析)` | 勾選 checkbox 的精確替換,並統一清單項的文法 | | `feat(issue-update)` | 以 `--tick` 勾待辦,並在沒東西可改時不送空的 PATCH | | `feat(規則正本)` | 新增實作規範與註解格式對照表 | | `feat(流程正本)` | `sdlc-feat` 加入第二段「逐項實作」 | | `test(逐項實作)` | 覆蓋勾選的五種危險、兩份規則正本與正本第二段 | 新增 `references/coding-standards.md`、`references/comment-styles.md`; `scripts/issue-body.js` 增加 `tickLine` 與共用的 `LIST_ITEM` 文法; `scripts/issue-update.js` 增加 `--tick` 與 `--section`。 ## 設計重點 - **勾選是 `issue-body.js` 裡唯一會寫回議題的路徑**,所以它必須守住全檔的兩個前提: 跳過圍欄、限定段落。理由與 `upsertLineInSection` 相同——弄錯的代價是靜靜改壞內容。 - **清單項的文法收斂成一份 `LIST_ITEM`**,抽取端(`parseChecklistItem`)與勾選端 (`tickLine`/`parseTick`)共用。兩端各寫一份就會鬆緊不一致。 - **`[ ]`、`[x]`、`[X]` 指的是同一行。** `[X]` 是合法的 GFM,Gitea 也渲染成已勾。 - **`--tick` 只驗「是不是清單項」,不要求方框。** 抽取端會把忘了寫 checkbox 的項目也收成 一項待辦,那種 `raw` 要走到 `tickLine` 才拿得到「去議題上補成 checkbox」這句指路。 - **規則正本由流程正本指名讀取,不在 prompts 裡複述**——抄過來就會有兩份各自演化的規則。 ## 解決的問題 Code review 抓出五個缺陷,全是「會靜靜改壞議題」那一類,都已修掉並各自補上回歸測試: **1. `tickLine` 繞過了圍欄判斷。** `issue-body.js` 全檔的前提是「圍欄裡的東西不是內容」, 而工作包模板的**架構圖就是一塊 fenced mermaid**——裡面出現減號開頭的行是常態。 實測:圍欄裡一行 `- [ ] 甲` 會被真的勾下去,改壞的是一張圖。 **2. 同一個疏漏造成假的「分不出是哪一行」。** 待辦與整體驗收常有一模一樣的一句話, 不限定段落就會回報 `RAW_AMBIGUOUS`,而使用者其實講得很清楚。新增 `--section`。 **3. 大寫 `[X]` 重跑會硬失敗。** 只認小寫的話,中斷後重跑得到 `RAW_NOT_FOUND`, 錯誤訊息還會誣指「議題被改過」——但議題沒被改過。這直接打破「中斷後自動接續」。 **4. 抽取端與勾選端的文法鬆緊不一致。** `- [ ]甲`(方框後沒有空白)抽得出來卻勾不動, 正本那句「一律用 `wp-extract` 給的 `raw`」就成了做不到的指示。 **5. `--dry-run` 會預告一個實跑根本不會發的請求。** 「沒東西可改就不送 PATCH」的判斷 原本放在試跑分支之後。試跑印出漂亮的計畫、實跑什麼都不送,是最難查的那種落差。 ## 影響的功能 - `scripts/issue-body.js` 的 `parseChecklistItem` 改用共用文法,`wp-extract` 的輸出不變 (既有 44 個測試全數通過)。 - `issue-update` 的 `--estimate-days`/`--overview-url` 在「值沒有變化」時不再送空的 PATCH。 空的 PATCH 會把議題的 `updated_at` 推新,在列表上浮起來像是有人動過。兩條既有斷言 已更新為這個更強的保證。 - `test/helpers/stub-gitea.js` 新增 `patchOf`,取代先前散在三個測試檔的同名複本。 - 尚未實作的 `#13` 會接在這一段之後:分批提交、開立 PR、停錶。 ## 測試結果 在**最新 master**(`1e93b77a`)的完整樹上套用本分支後實際執行 `npm test`: ``` ℹ tests 505 ℹ suites 0 ℹ pass 505 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ``` master 既有 451,本分支新增 54。 勾選的測試全部繞著「會不會改錯行」打轉:圍欄裡的假 checkbox 不被動到、不同段落的 同一句話靠 `--section` 分得開、大寫 `[X]` 重跑是 no-op、方框後沒空白照樣勾得到、 沒有方框的項目給的是指路的錯誤而不是謊報已勾過。 另外釘住**抽取端與勾選端的契約一致性**:`wp-extract` 交得出來的每一種 `raw` (CRLF、無空白、大寫、缺方框)`--tick` 都要收得下或給出指路的錯誤。這兩端是分開寫的, 先前沒有任何測試把它們接起來驗。 實機驗證:對真實議題 #12 執行 `--tick --dry-run`,確認只有目標那一行變 `[x]`, 其餘七行原封不動;`RAW_NOT_FOUND` 的路徑也對真實 Gitea 驗過。 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jiantw83 added 5 commits 2026-09-17 07:40:52 +00:00
tickLine 把指定那一行的方框換成已勾,其餘一字不動。四件事決定它會不會靜靜改壞議題:

- **跳過圍欄。** 這是 issue-body.js 全檔的前提,而勾選是本檔唯一會寫回議題的路徑。
  工作包模板的架構圖就是一塊 fenced mermaid,裡面出現減號開頭的行是常態,
  把它當成待辦勾下去,改壞的是一張圖。
- **限定段落。** 待辦與整體驗收常有一模一樣的一句話,不限定就會回報「分不出來」,
  而使用者其實講得很清楚。理由與 upsertLineInSection 相同:弄錯的代價是靜靜改壞內容。
- **整行比對,認不出就交回 ambiguous。** 巢狀待辦底下常有一樣的驗收,賭第一個會讓
  進度條指著錯的那一項,而沒有人會去比對編輯紀錄。
- **[ ]、[x]、[X] 指的是同一行。** [X] 是合法的 GFM,Gitea 也渲染成已勾;只認小寫的話,
  中斷後重跑會硬失敗,錯誤訊息還會誣指「議題被改過」。

清單項的文法收斂成一份 LIST_ITEM,parseChecklistItem 與 tickLine 共用。先前兩端各寫一份,
鬆緊不一致:`- [ ]甲` 抽得出來卻勾不動,正本那句「一律用 wp-extract 給的 raw」就成了
做不到的指示。沒有方框的項目交回 no-checkbox,不再謊報「已經勾過」。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
--tick 收抽取契約交出的那一整行 raw,--section 指出它在哪一個段落。四種擋下來的情況
各有錯誤碼,因為使用者的下一步不同:找不到(抽取結果過期,重抽)、同段落出現多次
(請改寫議題上重複的說法)、那一項沒有方框(去議題上補)、段落不存在(對照輸出確認)。
一律報錯不盲改——改壞了議題的進度條會說謊,而沒有人會去比對 body 的編輯紀錄。

--tick 的輸入只驗「是不是清單項」,不要求方框。抽取端會把忘了寫 checkbox 的項目也收成
一項待辦,那種 raw 要走到 tickLine 才拿得到「去議題上補成 checkbox」這句話;
在入口就擋掉,使用者只會得到一個看不出該怎麼辦的格式錯誤。

沒有任何欄位要改時整個 PATCH 都不送:空的 PATCH 會把議題的 updated_at 推新,在列表上
浮起來像是有人動過。這個判斷做在試跑分支之前——放在後面的話,試跑會預告一個實跑根本
不會發的請求,而那是最難查的那種落差。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
兩份規則只存在於本 plugin 裡,由流程正本指名讀取,不寫進目標專案的任何檔案。

coding-standards.md 管規則:六種專案檔對應語言、認不出就停下來問;分層看職責不看目錄,
三層各寫功能/邏輯/資料源註解,服務層要標註呼叫的方法讓 reviewer 追得到呼叫鏈;
屬性的用途註解遞迴到每一層,並附真實資料範例,優先取自 MCP,推理來的要明講未經驗證
——不註明的話,會有人照著沒對過的格式寫解析。

comment-styles.md 只管格式:六種語言各一節,都附可照抄的方法註解與屬性註解範例。
Go 的「以識別字開頭」與 Python 的「docstring 在定義的下一行」各自點名,那是最常被
照抄成別的語言寫法的兩處。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
一項一項做完並即時勾選,讓議題頁的進度條隨時反映真實狀態。

過程不打斷:二十項待辦不按二十次同意,只印進度;也不為了勾選留留言——勾選改的是 body,
進度條自己會動,逐項留言會把議題洗版,reviewer 得從一堆「已完成第 N 項」裡找真正的討論。
真正該停下來問的只有三種,列出來了。

規則正本指名讀取,不在這裡複述——抄過來就會有兩份各自演化的規則。

中斷後重跑從 Gitea 的勾選狀態接續,不看任何本機檔案;重複勾選是安靜的 no-op,
所以不確定某一項有沒有勾到時直接再勾一次即可,不必先查。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
勾選的測試全部繞著「會不會改錯行」打轉,五種都是 code review 抓出來的實際缺陷:
圍欄裡長得像 checkbox 的那一行不會被改到、不同段落的同一句話靠 --section 分得開、
大寫 [X] 重跑是 no-op、方框後沒有空白照樣勾得到、沒有方框的項目給的是指路的錯誤
而不是謊報已勾過。

另外釘住抽取端與勾選端的一致性:wp-extract 交得出來的每一種 raw,--tick 都要收得下。

patchOf 收進 helpers——它先前在三個測試檔裡各有一份一模一樣的定義。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
admin approved these changes 2026-09-17 07:42:49 +00:00
admin merged commit 1c6fb8aaad into master 2026-09-17 07:42:52 +00:00
admin deleted branch feat/implement-and-tick-todos/main 2026-09-17 07:42:52 +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#44