feat/wp-extract-contract/main
master
建立工作包議題的抽取契約 wp-extract:給一個工作包議題編號,回傳實作階段需要的一切, 而不必吞下整份議題全文。順帶修好一個既有的解析缺陷(見「解決的問題」)。
wp-extract
#1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組
#9 — 建立工作包的抽取契約
fix(議題解析)
refactor(抽取)
lib.js
feat(議題解析)
feat(wp-extract)
test(wp-extract)
新增 scripts/wp-extract.js;scripts/issue-body.js 增加 checklistInSection、tableRows、 referencedIndex;scripts/lib.js 增加 fetchIssue、countUnmergedComments; scripts/issue-extract.js 改為呼叫後兩者,行為不變。
scripts/wp-extract.js
scripts/issue-body.js
checklistInSection
tableRows
referencedIndex
scripts/lib.js
fetchIssue
countUnmergedComments
scripts/issue-extract.js
輸出與議題 #1 的契約逐欄一致:
{index, url, title, 需求議題, 描述, 架構圖, 範圍邊界[], 介面契約[], 待辦[{text,done,raw,驗收[{text,done,raw}]}], 整體驗收[], repos[], 相依:{blocks[],depends[]}, assignee, 碼錶中, 未處理留言數}
raw
\r
tableSection
CRLF 的 body 會讓清單靜靜變成空的(既有缺陷,非本次新增)。 瀏覽器送出 textarea 一律用 CRLF,議題只要在 Gitea 網頁上被編輯過,body 逐行切開後行尾 就掛著 \r。JS 的 . 不吃 \r,(.*)$ 因此整行比不中:已經上線的 issue-extract 會把目標、非目標、驗收標準一律回成空陣列,而且不報錯、exit code 是 0——下游拿到的是 「這一段沒寫」而不是「解析失敗」。改用 [\s\S] 比對行尾,並補上測試。
.
(.*)$
issue-extract
[\s\S]
issue-body.js
sdlc-feat
已知限制:碼錶中 受限於 Gitea 只開放讀自己的碼錶(/user/stopwatches),實際語意是 「我的碼錶正跑在這顆議題上」,這是議題 #1 已接受的取捨;領取鎖看的仍是 assignee。
碼錶中
/user/stopwatches
assignee
於本分支的乾淨工作樹實際執行 npm test:
npm test
ℹ tests 274 ℹ suites 0 ℹ pass 274 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 5921.072673
新增 49 個測試案例,涵蓋契約欄位、模板變體(缺段落、巢狀驗收為空、checkbox 已勾、 中英混排、圍欄裡的假待辦、只寫一格的表格列)、CRLF、相依與留言的分頁、--dry-run 預告的請求順序與實跑一致且完全不碰 Gitea。
--dry-run
另以實機驗證:dependencies/blocks//user/stopwatches 三個端點的回應形狀, 以及 StopWatch 的欄位名稱,皆對照本站 Gitea 1.27.0 的 swagger 確認無誤。
dependencies
blocks
StopWatch
🤖 Generated with Claude Code
瀏覽器送出 textarea 一律用 CRLF,議題只要在 Gitea 網頁上被編輯過,body 逐行切開後 每一行行尾就掛著 \r。JS 的 . 不吃 \r,`(.*)$` 因此整行比不中——listSection 會把 目標、非目標、驗收標準這些段落一律回成空陣列,而且不報錯,下游拿到的是「這一段沒寫」 而不是「解析失敗」。 改用 [\s\S] 比對行尾,text 本來就有 trim 會把 \r 修掉。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
工作包的抽取契約(#9)要做的事與需求議題那一支有三件完全重疊:讀議題、把「不存在」 與「沒有讀取權」分成兩種錯誤碼、以 +1 reaction 數出未整併的留言則數。這三件事的規則 只該有一份,複製一份到新腳本等於日後改規則要記得改兩個地方。 fetchIssue、countUnmergedComments 與試跑時那句附註一起搬到 lib,issue-extract 改為 呼叫它們,行為不變。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
工作包議題比需求議題多三種結構,抽取契約(#9)要靠它們: - checklistInSection 收 body 而不收切好的段落。它要交出的 `raw` 是下游勾選 checkbox 時做精確字串替換的依據,那一行必須逐字等於 body 裡的原樣,連縮排與行尾的 \r 都不能 動;段落切分會修掉前後空白,給不出這種保證。兩種畸形寫法都不丟內容:巢狀超過一層攤 進所在待辦的驗收,還沒有上層待辦就先出現的縮排項目升格成待辦。 - tableRows 保留全部欄位,tableSection 改寫成它的兩欄版。介面契約是四欄,先前那一支 只留兩欄。短的資料列補空字串——正本明講「不產出對外介面就寫一列『無』」,那一列不該 與「沒有這一段」混為一談。 - referencedIndex 從關聯段落讀出 `需求議題:#N`。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
實作階段的指令給一個議題編號就拿得到它需要的一切,不必吞下整份議題全文。 輸出與議題 #1 的契約一致:待辦與它自己的驗收是巢狀的,每一項都帶未經修改的 `raw`, 下游靠它只改那一行、不重寫整份 body。 body 說不出的三個活狀態另外現查:相依走 dependencies/blocks 兩個端點並逐頁讀完 (半份清單會讓下游把實作順序排錯,那比直接報錯更難發現)、領取人看 assignee、碼錶 走 /user/stopwatches。碼錶那一項受限於 Gitea 只讓人讀自己的錶,真正的語意是「我的錶 正跑在這顆議題上」,這是議題 #1 已接受的取捨;領取鎖看的仍是 assignee。 同樣只讀 body 不讀留言,但回報未處理留言數。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
解析是整條鏈的上游,解析錯則下游全錯,所以模板變體餵得雜一些:缺段落、巢狀驗收為空、 checkbox 已勾、中英混排、圍欄裡的假待辦、只寫一格的表格列。 另外釘住三件容易在日後鬆掉的事: - `raw` 逐行出現在原始 body 裡,包括 CRLF 的 body 連行尾的 \r 都留著,否則下游替換 時對不上原文。 - 相依與留言都逐頁讀完,不是只讀第一頁。 - --dry-run 預告的請求順序與實跑一致,且完全不碰 Gitea。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
No dependencies set.
The note is not visible to the blocked user.
摘要
建立工作包議題的抽取契約
wp-extract:給一個工作包議題編號,回傳實作階段需要的一切,而不必吞下整份議題全文。順帶修好一個既有的解析缺陷(見「解決的問題」)。
需求議題
#1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組
工作包議題
#9 — 建立工作包的抽取契約
變更內容
fix(議題解析)refactor(抽取)lib.js,兩支抽取腳本共用feat(議題解析)feat(wp-extract)test(wp-extract)新增
scripts/wp-extract.js;scripts/issue-body.js增加checklistInSection、tableRows、referencedIndex;scripts/lib.js增加fetchIssue、countUnmergedComments;scripts/issue-extract.js改為呼叫後兩者,行為不變。輸出與議題 #1 的契約逐欄一致:
設計重點
raw逐字等於 body 裡的那一行。 下游勾選 checkbox 時要靠它做精確字串替換,只改那一行、不重寫整份 body。因此
checklistInSection收整份 body 而不收切好的段落——段落切分會修掉前後空白,給不出這種保證。連行尾的
\r都原樣留著。縮排項目升格成待辦。沿用本 repo 既有的「寧可多帶一項,也不要無聲吃掉內容」。
tableSection改寫成tableRows的兩欄版,解析規則只留一份。短的資料列補空字串——正本明講「不產出對外介面就寫一列『無』」,那一列不該與「沒有這一段」混為一談。
解決的問題
CRLF 的 body 會讓清單靜靜變成空的(既有缺陷,非本次新增)。
瀏覽器送出 textarea 一律用 CRLF,議題只要在 Gitea 網頁上被編輯過,body 逐行切開後行尾
就掛著
\r。JS 的.不吃\r,(.*)$因此整行比不中:已經上線的issue-extract會把目標、非目標、驗收標準一律回成空陣列,而且不報錯、exit code 是 0——下游拿到的是
「這一段沒寫」而不是「解析失敗」。改用
[\s\S]比對行尾,並補上測試。影響的功能
issue-extract:受惠於 CRLF 修正;內部改用lib.js的共用函式,輸出不變(既有測試全數通過)。issue-body.js的tableSection:單格資料列從「丟掉」改為「補空字串」,不再無聲消失。sdlc-feat(#11–#13)將以本契約為唯一的工作包讀取管道。已知限制:
碼錶中受限於 Gitea 只開放讀自己的碼錶(/user/stopwatches),實際語意是「我的碼錶正跑在這顆議題上」,這是議題 #1 已接受的取捨;領取鎖看的仍是
assignee。測試結果
於本分支的乾淨工作樹實際執行
npm test:新增 49 個測試案例,涵蓋契約欄位、模板變體(缺段落、巢狀驗收為空、checkbox 已勾、
中英混排、圍欄裡的假待辦、只寫一格的表格列)、CRLF、相依與留言的分頁、
--dry-run預告的請求順序與實跑一致且完全不碰 Gitea。
另以實機驗證:
dependencies/blocks//user/stopwatches三個端點的回應形狀,以及
StopWatch的欄位名稱,皆對照本站 Gitea 1.27.0 的 swagger 確認無誤。🤖 Generated with Claude Code