feat/implement-and-tick-todos/main
master
/sdlc-feat 的第二段:一項一項把待辦做完並即時勾選,讓議題頁的進度條隨時反映真實狀態。 勾選以抽取契約給的 raw 做精確字串替換,只動目標那一行。
/sdlc-feat
raw
#1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組
#12 — 以 sdlc-feat 逐項實作並即時勾選待辦
feat(議題解析)
feat(issue-update)
--tick
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。
references/coding-standards.md
references/comment-styles.md
scripts/issue-body.js
tickLine
LIST_ITEM
scripts/issue-update.js
--section
issue-body.js
upsertLineInSection
parseChecklistItem
parseTick
[ ]
[x]
[X]
Code review 抓出五個缺陷,全是「會靜靜改壞議題」那一類,都已修掉並各自補上回歸測試:
1. tickLine 繞過了圍欄判斷。 issue-body.js 全檔的前提是「圍欄裡的東西不是內容」, 而工作包模板的架構圖就是一塊 fenced mermaid——裡面出現減號開頭的行是常態。 實測:圍欄裡一行 - [ ] 甲 會被真的勾下去,改壞的是一張圖。
- [ ] 甲
2. 同一個疏漏造成假的「分不出是哪一行」。 待辦與整體驗收常有一模一樣的一句話, 不限定段落就會回報 RAW_AMBIGUOUS,而使用者其實講得很清楚。新增 --section。
RAW_AMBIGUOUS
3. 大寫 [X] 重跑會硬失敗。 只認小寫的話,中斷後重跑得到 RAW_NOT_FOUND, 錯誤訊息還會誣指「議題被改過」——但議題沒被改過。這直接打破「中斷後自動接續」。
RAW_NOT_FOUND
4. 抽取端與勾選端的文法鬆緊不一致。 - [ ]甲(方框後沒有空白)抽得出來卻勾不動, 正本那句「一律用 wp-extract 給的 raw」就成了做不到的指示。
- [ ]甲
wp-extract
5. --dry-run 會預告一個實跑根本不會發的請求。 「沒東西可改就不送 PATCH」的判斷 原本放在試跑分支之後。試跑印出漂亮的計畫、實跑什麼都不送,是最難查的那種落差。
--dry-run
issue-update
--estimate-days
--overview-url
updated_at
test/helpers/stub-gitea.js
patchOf
#13
在最新 master(1e93b77a)的完整樹上套用本分支後實際執行 npm test:
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 驗過。
--tick --dry-run
🤖 Generated with Claude Code
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>
No dependencies set.
The note is not visible to the blocked user.
摘要
/sdlc-feat的第二段:一項一項把待辦做完並即時勾選,讓議題頁的進度條隨時反映真實狀態。勾選以抽取契約給的
raw做精確字串替換,只動目標那一行。需求議題
#1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組
工作包議題
#12 — 以 sdlc-feat 逐項實作並即時勾選待辦
變更內容
feat(議題解析)feat(issue-update)--tick勾待辦,並在沒東西可改時不送空的 PATCHfeat(規則正本)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」這句指路。解決的問題
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: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