jiantw83 and Claude Opus 5
3ad08be14f
test(comments-merge): 把留言裡的決策整併回議題描述並標記
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 09:19:10 +00:00
jiantw83 and Claude Opus 5
16f93f6e8b
feat(comments-merge): 把留言裡的決策整併回議題描述並標記
...
判斷「哪幾則有決策、該併進哪一段」是讀得懂內容的人的事;這一支只負責把結果安全地寫回去。
先寫描述再標記,描述寫失敗就不標記:反過來的話,那幾則已經被標成處理過,再也不會被提出來。
--merged 只收真的併進去的那幾則,略過的保持未標記。標記之前先核對那幾則確實在這顆議題上——
打錯 id 的 reaction 會落在別顆議題的留言上,而那幾乎不會有人發現。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 09:19:09 +00:00
jiantw83 and Claude Opus 5
5ef25d3ee9
test(抽取契約): 未整併的判定改成只認自己打的 +1
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 09:19:08 +00:00
jiantw83 and Claude Opus 5
c1ab712afd
feat(議題解析): 換掉一個段落的內容,標題與其餘段落一字不動
...
整併留言裡的決策時用它。不整份重寫的理由跟 upsertLineInSection 一樣,只是代價更大:
重寫會把別人在其他段落的編輯一起蓋掉,而議題的編輯紀錄沒有人會去比對。
三件事照著同檔既有的規矩做:圍欄裡的假標題不算段落;同名標題出現不只一次時交回 ambiguous
而不賭第一個(蓋掉的是一整段,猜錯的代價比 tickLine 更高);換行沿用 body 原本的那一種,
CRLF 的 body 裡混進 LF 會讓抽取契約交出的 raw 對不上原文,之後就勾不動那幾行。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 09:19:08 +00:00
jiantw83 and Claude Opus 5
3b7e3bdfc7
test(pr-comments): 議題也讀得了,不再先打 PR 端點
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 09:19:07 +00:00
jiantw83 and Claude Opus 5
051fe0ded4
fix(pr-comments): 議題也讀得了,不再先打 PR 端點
...
每個 PR 都是議題,議題不一定是 PR——原本的註解把這句話講反了,程式也照著反過來寫:
先打 /pulls/{index},對純議題回 404,於是 /sdlc-sync 在讀到第一則留言之前就斷了。
改成先讀 /issues/{index}(兩種都有),看它有沒有 pull_request 才決定要不要去翻 review。
輸出加上「類型」讓下游知道拿到的是議題還是 PR。
讀取的共用結構沿用 pr-threads(#48 為了讓 pr-watch 數同一件事而抽出來的):readGeneral
改名 readGeneralComments 並導出,純議題只叫它;pr-threads 自己那份 markedByMe 拿掉,
改用 lib 的 mergedByMe。#48 的檔頭擔心「規則寫兩份遲早會各自演化」,現在三處共用一份。
試跑改印 commonRequests:pr-comments 收得下兩種輸入,而試跑階段還沒讀過議題、不知道是
哪一種。與其假設是 PR 而列出五個(對純議題有三個根本不會發),不如只列一定會發的。
pr-watch 的輸入一定是 PR,繼續用 plannedRequests。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 09:19:06 +00:00
jiantw83 and Claude Opus 5
b263915afc
test(pr-create): 讀檔與列留言收進 lib,並讓已整併只認自己打的 +1
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 09:19:05 +00:00
jiantw83 and Claude Opus 5
ee474d0439
refactor(lib): 讀檔與列留言收進 lib,並讓已整併只認自己打的 +1
...
「讀一個 --xxx-file 或直接失敗」原本在四支腳本各寫一份,錯誤碼還有三種拼法
(BODY_FILE_NOT_FOUND/BODY_FILE_MISSING/CONTENT_FILE_NOT_FOUND)。同一種情況要有同一個
碼,呼叫端才分辨得出是哪一步壞了。留言分頁的那段咒語也是第三份,一併收成 listIssueComments。
countUnmergedComments 原本接受任何人的 +1,而讀留言那邊只認自己的——兩端對「已整併」的
定義不一致。後果是隊友對決策留言按個讚,未處理留言數就掉到 0,analyze 與 feat 再也不提示,
那則決策永遠不會被收進描述。統一成只認自己打的:別人按讚是「我同意」,不是「已經收進去了」。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 09:19:05 +00:00
jiantw83 and Claude Opus 5
617a3eef72
fix(pr-watch): 試跑的預告與實跑的守門對齊,並說出路徑被佔住這件事
...
review 抓到一處落差:試跑判「終止且工作樹乾淨」就預告 git worktree remove,
但實跑多判一件事——那條路徑上的東西是不是真的一棵工作樹。別的 clone 在同一條路徑上
留下目錄時(路徑由 owner/repo/分支名 推導,不含本機 clone 的位置),試跑會預告一行
實跑必然拒絕的指令,而回報裡完全看不出原因。
判斷收進 lib 的 inspectWorktree,由它直接給出 reason(missing/foreign/dirty/
removable):試跑與實跑、自動與手動四條路徑從此擋在同一個判斷上,worktree-remove 裡
那份重算的副本也跟著刪掉。回報多一個「是工作樹」欄位,手動出口的 NOT_A_WORKTREE
不再是使用者第一次聽到這件事。
順帶兩件同源的修正:
- 「是不是工作樹」改認 .git 為**檔案**。獨立 clone 的 .git 是目錄,先前會被當成工作樹,
然後在 git worktree remove 那一步炸出一句原始錯誤。
- 兩支腳本的 --dry-run 請求預告收進 pr-threads 的 plannedRequests,並補上 pr-watch
先前漏掉的那句說明(逐則 reaction 與逐個 review 的行內留言事前列不完)。預告與實際
發出的請求分開寫,加一個端點就會有一邊忘了改。
- PR 讀不到 head 分支時給出 PULL_HEAD_MISSING,而不是拿空字串去推導一條路徑。
議題 #41
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 17:06:07 +08:00
jiantw83 and Claude Opus 5
32edd65962
docs(sdlc-feat): 第三段收尾指向 pr-watch 與手動清理
...
PR 開出去之後流程就斷在那裡,使用者不會知道有東西可以查現況、也不會知道工作樹會被
自動清掉。收尾補一步,把兩支腳本講給使用者聽,並明講「多久跑一次由他自己排」。
邊界同時擋住兩件事:agent 不自己反覆跑 pr-watch,也不因為它建議了 run-sdlc-fix 就
自己去跑 /sdlc-fix——流程只由使用者明確叫用。
議題 #41
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 16:59:30 +08:00
jiantw83 and Claude Opus 5
d331bef1ed
feat(pr-watch): 回報 PR 現況,並在它結束時清掉工作樹
...
開發者要能隨時問一句「這個 PR 現在怎麼樣、我還有什麼要做」。回報 PR 狀態、還有幾則
留言沒處理、工作樹在哪、裡面有沒有沒提交的東西,以及固定列舉值的 suggestedAction
——用列舉值而不是一段文字,呼叫端才能程式化判斷。
一次性、無狀態:不做變化偵測。已處理的判定基準是 Gitea 上的 +1 與 resolve,那個狀態
不在本機記憶裡,所以一份現況快照就足以回答「還有沒有事要做」,不必跟上次比較,也就
不必留任何游標或狀態檔。不做常駐程序也不做 daemon,排程交給呼叫端。
只通知,不動手:偵測到未處理留言只給建議,不自動執行 /sdlc-fix——流程不該被模型自動
觸發,而 /sdlc-fix 要求「不確定時詢問使用者」,非互動模式下那個詢問無處可去。
四種狀態的處置不一致,所以表格驅動測:merged 與 closed 終止並清理;open 繼續監看;
draft 繼續監看且**不清理**——被退回草稿代表還要繼續改,這時候那棵工作樹更需要留著。
議題 #41
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 16:59:30 +08:00
jiantw83 and Claude Opus 5
9e049580bb
feat(worktree-remove): 手動清掉一棵工作樹,絕不 --force
...
pr-watch 會在 PR 合併或關閉時自動清理,但永遠不會被合併也不會被關閉的 PR 沒有出口
——沒有這一支,那些工作樹只能靠使用者自己記得去刪。兩條路共用 lib 的 removeWorktree,
不互相開子行程:守門的規則只有一份,自動的那條與手動的這條不該長出兩種行為。
**絕不 --force。** 清理會被自動執行,而自動執行的東西只能做可逆的事:工作樹重建得回來,
被刪掉的未提交變更救不回來。所以有東西沒提交就中止並報出路徑與檔名。只移除工作樹,
本機分支與遠端分支都留著。
輸入是 owner/repo 與分支名而不是一條路徑:要刪哪一棵由「哪顆工作包」決定,
使用者不必自己去記 12 碼的雜湊目錄名。
順手修掉一個測試抓出來的解析錯誤:git status --porcelain 的第一行前導空白會被 runGit
的 trim 修掉,固定切前三個字元會讓已修改檔案的檔名少一個字(README.md 變成 EADME.md),
人照著訊息去找會找不到。改成認「狀態欄一到兩個字元 + 空白」。
議題 #41
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 16:59:30 +08:00
jiantw83 and Claude Opus 5
43764f457e
refactor(pr-comments): 三類留言的讀取收進 pr-threads
...
pr-watch 要數「還有幾則沒處理」,數的是與 pr-comments 完全同一件事:三類留言分散在
三個端點,一般留言與總評看自己打的 +1、行內留言看有沒有被 resolve,而總評的 reaction
掛在它的 issue comment id 上。這套規則寫兩份,遲早會一邊認自己的 +1、另一邊認任何人的
——而那個差異要等到有留言被靜靜跳過才會被發現。
pr-comments 只留輸入輸出,行為不變。
議題 #41
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 16:59:30 +08:00
jiantw83
a1bbd78cb4
test(sdlc-fix-assets): 新增 sdlc-fix 流程正本
...
分類必改/建議、不確定時停下來問、最後那則摘要——這三件腳本擋不住,只有正本做得到。
標不了的那幾則要在摘要裡單獨點出來,否則 reviewer 掃 reaction 與 resolve 時會以為它們
被跳過了。留言指向的程式碼已被改掉時不要硬試,列進「無法處理」讓使用者自己回。
2026-09-17 08:46:35 +00:00
jiantw83
6453c78fd1
feat(sdlc-fix): 新增 sdlc-fix 流程正本
...
分類必改/建議、不確定時停下來問、最後那則摘要——這三件腳本擋不住,只有正本做得到。
標不了的那幾則要在摘要裡單獨點出來,否則 reviewer 掃 reaction 與 resolve 時會以為它們
被跳過了。留言指向的程式碼已被改掉時不要硬試,列進「無法處理」讓使用者自己回。
2026-09-17 08:46:35 +00:00
jiantw83
8d9bcd65e3
test(pr-reply): 回覆一則 PR 留言並標記已處理
...
「回在原本那一串底下」對三類是三件不同的事。行內留言沒有「回覆某一則」的端點,
把新留言指向同一個檔案與同一行,Gitea 才會把它排在原留言底下——位置是串的識別。位置不由
呼叫端給而是拿 id 查出來:手抄行號是這一段最容易錯的地方。回覆還帶上原留言的 commit_id,
否則 PR 之後又推了新 commit 時,同一個行號指的是別的程式碼。
標記排在回覆之後,回覆沒成功就不標記:沒回就標記等於謊稱處理過。
輸出三類同形:用不到的欄位填 null 而不是讓它消失,下游不必為了少一欄多寫一種分支。
2026-09-17 08:46:34 +00:00
jiantw83
759b53adeb
feat(pr-reply): 回覆一則 PR 留言並標記已處理
...
「回在原本那一串底下」對三類是三件不同的事。行內留言沒有「回覆某一則」的端點,
把新留言指向同一個檔案與同一行,Gitea 才會把它排在原留言底下——位置是串的識別。位置不由
呼叫端給而是拿 id 查出來:手抄行號是這一段最容易錯的地方。回覆還帶上原留言的 commit_id,
否則 PR 之後又推了新 commit 時,同一個行號指的是別的程式碼。
標記排在回覆之後,回覆沒成功就不標記:沒回就標記等於謊稱處理過。
輸出三類同形:用不到的欄位填 null 而不是讓它消失,下游不必為了少一欄多寫一種分支。
2026-09-17 08:46:34 +00:00
jiantw83
de1fd08efa
test(pr-comments): 讀 PR 上的三類留言
...
一般留言、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 之後整批消失。
2026-09-17 08:46:33 +00:00
jiantw83
cc29b5bc21
feat(pr-comments): 讀 PR 上的三類留言
...
一般留言、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 之後整批消失。
2026-09-17 08:46:33 +00:00
jiantw83 and Claude Opus 5
d3ce364727
docs(sdlc-feat): description 跟著改成「備妥工作樹、起錶」
...
轉接檔的一行說明是從這裡取的,順序寫錯會讓人以為錶還是在領取那一步起。
議題 #40
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 16:30:00 +08:00
jiantw83 and Claude Opus 5
0154cf59d4
fix(claim): 被碼錶擋下時明說停錶不會動到既有的工作樹
...
議題 #38 的使用者故事第 30 條:使用者常以為停錶等於放棄那顆工作包,於是寧可
不停——工時就記到別顆議題去了。碼錶只管時間、工作樹只管檔案,兩者互不相干,
這件事要在擋下來的當下就講,不能指望使用者自己推論。
領取與起錶會撞到同一個擋路理由,訊息收進 lib 只寫一份。順手收掉 review 指出的
三處:planWorktree 沒用到的 repo 參數、與 path.resolve 同名而誤導的區域函式、
以及只有 lib 自己用得到卻對外 export 的兩支路徑函式。
回滾補上最後一道:git 清不掉時把目錄本身也刪掉。那條路徑在這次執行之前不存在
(不存在正是建立的前提),裡面不可能有使用者的東西,而留著它下一次重跑會直接
撞上 WORKTREE_PATH_TAKEN——一次失敗的建立不該讓人從此開不了工。
議題 #40
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 16:29:12 +08:00
jiantw83 and Claude Opus 5
4583a5f210
docs(sdlc-feat): 第一段改成領取、備妥工作樹、最後起錶
...
正本跟著實作走:分支那一步改成工作樹,新增起錶那一步排在它後面,
並把三處「不要自己決定」寫明——來源分支不存在時不自己換一支、路徑被佔住時
不自己刪、工作樹建不起來時不退回原地切分支。工作區不乾淨的處置整段拿掉:
工作樹本來就是為了讓未提交的變更不再擋路。
AGENTS.md 補上兩條邊界。git worktree add 一定會在目標 repo 的 .git/worktrees/
底下寫中繼資料,這是 git 的機制,無法避免——「不改目標專案」指的是專案的內容檔,
把這件事明說,免得下一個人以為實作違規。
議題 #40
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 16:29:12 +08:00
jiantw83 and Claude Opus 5
74b4ca130e
feat(timer): 碼錶移出領取,等工作樹建成之後才起
...
原本的順序是「放行 → 設 assignee 與標籤 → 起錶 → 處理分支」,而工作樹建立
失敗會中止整個領取——錶已經起了才失敗,使用者會被計一段什麼都沒做的時間,
而工時要準正是工時報表的立足點。
claim 只留領取鎖的兩件事(assignee 與標籤),起錶交給新的 timer.js,由流程
正本排在 branch-prep 之後。timer 已經跑在這顆議題上時什麼都不做:中斷後重跑
是它最常見的處境,重新起錶會把已經累積的時間切成兩段;跑在別顆上則照舊擋下,
不代勞停錶。
三支腳本讀碼錶的那段各留一份,趁這次收進 lib。
議題 #40
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 16:27:43 +08:00
jiantw83 and Claude Opus 5
5b740c236b
feat(branch-prep): 一律在獨立的工作樹上開工,不在原地切換分支
...
同一份 clone 上同時持有多顆工作包時,原地切分支有三種損耗,一種比一種難查:
未提交的變更擋路、建置產物跨分支混淆,以及 agent 讀到不屬於它那顆工作包的
程式碼——agent 是非同步的,它可能在分支已經被切走之後才去讀檔,而且不會察覺,
產出看起來完全合理,只是接錯了上下文。前兩種人會當場發現,第三種不會,
所以工作樹一律建立,不是「有衝突才用」。
建不起來就中止,不退回原地切分支:靜默降級會讓使用者以為自己在隔離環境裡,
其實在原地改。
分支與工作樹合併為一個原子動作(fetch 後一次 worktree add),並補上回滾——
git 在 worktree add 失敗時仍會把分支留下來,那是最難查的半成品:下一次重跑
會走到「目標分支已存在」那條路,起點從此不再是遠端的來源分支。
起點一律取自 origin/{來源分支},遠端沒有就中止,不退回本機同名分支;
本機分支可能落後好幾天,而這件事從輸出上完全看不出來。原「來源分支在遠端
已存在時 pull 而非重建」那條,用更強的方式達成同一個目的:根本不碰本機分支,
就沒有覆蓋他人進度的可能。
不設 upstream:此刻遠端還沒有這個新分支,--track 會把 upstream 指到來源分支,
之後 git pull 會把來源分支的提交拉進來。留給第一次 push -u 自然建立。
路徑由 owner/repo/分支名 正規化後取雜湊推導(lib 的 worktreePath),不查表、
不寫狀態檔,換機器算出來一樣。取雜湊而不是把斜線攤平成 -,是因為攤平會讓
feat/a-b/main 與 feat/a/b/main 撞成同一個目錄,而現行的分支命名規則恰好讓
這種形狀有機會出現。
議題 #40
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 16:27:43 +08:00
jiantw83
997d4ec280
docs(sdlc-feat): 第三段補上兩個 repo 的區別與重跑的行為
...
說明 --repo 與 --issue-repo 的差別、--base 要明講不讓腳本猜、重跑不會開出第二顆 PR,
以及提交中途失敗時不要自己回捲歷史。
2026-09-17 08:23:28 +00:00
jiantw83
013947630f
test(sdlc-feat-assets): 第三段補上兩個 repo 的區別與重跑的行為
...
說明 --repo 與 --issue-repo 的差別、--base 要明講不讓腳本猜、重跑不會開出第二顆 PR,
以及提交中途失敗時不要自己回捲歷史。
2026-09-17 08:23:28 +00:00
jiantw83
da5b670f29
test(script-contract): 讓 --key=value 的值可以本身以 -- 開頭
...
commit 訊息與 PR 描述裡出現 --flag 是常態,而原本的檢查對兩種寫法一視同仁:值只要以
-- 開頭就報「需要一個值」。空格分隔的寫法確實分不出「值」與「打錯的 flag」,但等號寫法
沒有這個歧義,不該一起擋掉。
這是實際撞到的:拿 commit-split 提交它自己時,--body 的內容第一行就是「--repo 與
--issue-repo 的差別」,整個 commit 因此做不出來。空格寫法的錯誤訊息現在會指路到等號寫法。
2026-09-17 08:23:27 +00:00
jiantw83
1c6e7f85bb
fix(lib): 讓 --key=value 的值可以本身以 -- 開頭
...
commit 訊息與 PR 描述裡出現 --flag 是常態,而原本的檢查對兩種寫法一視同仁:值只要以
-- 開頭就報「需要一個值」。空格分隔的寫法確實分不出「值」與「打錯的 flag」,但等號寫法
沒有這個歧義,不該一起擋掉。
這是實際撞到的:拿 commit-split 提交它自己時,--body 的內容第一行就是「--repo 與
--issue-repo 的差別」,整個 commit 因此做不出來。空格寫法的錯誤訊息現在會指路到等號寫法。
2026-09-17 08:23:27 +00:00
jiantw83
95e6026950
refactor(lib): 開啟目標專案 git repo 的那幾行收進 lib
...
「路徑不是 repo 就報 NOT_A_GIT_REPO」加上「把 cwd 綁進 runGit」原本在 branch-prep 與
commit-split 各寫一份。錯誤碼要一致,而這件事寫第三遍就該收起來了。
2026-09-17 08:23:26 +00:00
jiantw83
fbc80f286f
test(pr-create): 錶停在議題的 repo,並讓重跑不會開出第二顆 PR
...
claim 在工作包議題上起錶,而 PR 開在目標專案上——議題在需求的 repo,程式碼在 repos 列的
那幾個,兩者常常不是同一個。先前用同一個 --repo 同時指 PR 與停錶,停到的會是別人的議題
(或 404 而在 PR 已建立之後才拋錯),而自己的錶還在跑。新增 --issue-repo,預設與 --repo 相同。
--index 與 --base 改為必填:停錶是這一步的一部分,忘了給會讓工時算不準;而目標專案的開發
分支可能叫 master、main 或 develop,猜錯會開到不存在的 base。
重跑先查同一個 head 有沒有開著的 PR,有就回傳它並把 created 設為 false,然後照樣停錶——
那一步可能正是上次中斷的地方。先前重跑會撞上 Gitea 的 422,而那個錯誤看不出 PR 其實已經開好。
停錶的 500 改為只在訊息確實提到 stopwatch 時才視為「本來就沒在跑」,免得把真的伺服器錯誤
吞掉;未經證實的 409 那一支拿掉。測試結果的空話檢查改成整段每一行都是空話才擋,段落也改用
行首標題切,描述裡引用到「## 測試結果」這幾個字不會再讓檢查看錯地方。
2026-09-17 08:23:25 +00:00
jiantw83
30297cc49a
fix(pr-create): 錶停在議題的 repo,並讓重跑不會開出第二顆 PR
...
claim 在工作包議題上起錶,而 PR 開在目標專案上——議題在需求的 repo,程式碼在 repos 列的
那幾個,兩者常常不是同一個。先前用同一個 --repo 同時指 PR 與停錶,停到的會是別人的議題
(或 404 而在 PR 已建立之後才拋錯),而自己的錶還在跑。新增 --issue-repo,預設與 --repo 相同。
--index 與 --base 改為必填:停錶是這一步的一部分,忘了給會讓工時算不準;而目標專案的開發
分支可能叫 master、main 或 develop,猜錯會開到不存在的 base。
重跑先查同一個 head 有沒有開著的 PR,有就回傳它並把 created 設為 false,然後照樣停錶——
那一步可能正是上次中斷的地方。先前重跑會撞上 Gitea 的 422,而那個錯誤看不出 PR 其實已經開好。
停錶的 500 改為只在訊息確實提到 stopwatch 時才視為「本來就沒在跑」,免得把真的伺服器錯誤
吞掉;未經證實的 409 那一支拿掉。測試結果的空話檢查改成整段每一行都是空話才擋,段落也改用
行首標題切,描述裡引用到「## 測試結果」這幾個字不會再讓檢查看錯地方。
2026-09-17 08:23:25 +00:00
jiantw83
8a6145ea14
test(commit-split): 改名時別漏掉舊檔的刪除,失敗時說出做到哪裡
...
git diff --name-only 預設偵測改名,只印出目的地那一個路徑。來源的刪除因此被漏掉——
留在 index 裡沒被提交,而腳本還回報成功,要等下一次跑才會發現工作區不乾淨。加 --no-renames。
某一批提交失敗時,錯誤現在會列出前面已經建立的那幾顆 commit。不回捲它們:那會動到使用者的
歷史,而那幾顆本身是好的;但一定要說出做到哪裡,否則重跑前得自己去翻 git log。
類型對照表補上目標專案常見的測試擺法:tests/、spec/、__tests__/,以及放在被測檔案旁邊的
user.test.js。先前只認 test/,目標專案的測試會被併進 feat 那一批。
2026-09-17 08:23:24 +00:00
jiantw83
f99adab245
fix(commit-split): 改名時別漏掉舊檔的刪除,失敗時說出做到哪裡
...
git diff --name-only 預設偵測改名,只印出目的地那一個路徑。來源的刪除因此被漏掉——
留在 index 裡沒被提交,而腳本還回報成功,要等下一次跑才會發現工作區不乾淨。加 --no-renames。
某一批提交失敗時,錯誤現在會列出前面已經建立的那幾顆 commit。不回捲它們:那會動到使用者的
歷史,而那幾顆本身是好的;但一定要說出做到哪裡,否則重跑前得自己去翻 git log。
類型對照表補上目標專案常見的測試擺法:tests/、spec/、__tests__/,以及放在被測檔案旁邊的
user.test.js。先前只認 test/,目標專案的測試會被併進 feat 那一批。
2026-09-17 08:23:23 +00:00
jiantw83
513dad7f6a
test(sdlc-feat-assets): 加入第三段「提交與開立 PR」
...
PR 描述的八個段落與順序寫在正本裡,由 pr-create 擋;正本負責的是腳本擋不住的事:
測試結果要貼實際輸出而不是改寫成一句話、被擋下來時補真的內容而不是為了通過而拼湊、
以及跨兩個功能時用 --files 分兩次跑。
先開 PR 再停錶的理由也寫進去了:工時要記在真的有做事的那段時間上。
2026-09-17 08:23:23 +00:00
jiantw83
0b728ca270
feat(sdlc-feat): 加入第三段「提交與開立 PR」
...
PR 描述的八個段落與順序寫在正本裡,由 pr-create 擋;正本負責的是腳本擋不住的事:
測試結果要貼實際輸出而不是改寫成一句話、被擋下來時補真的內容而不是為了通過而拼湊、
以及跨兩個功能時用 --files 分兩次跑。
先開 PR 再停錶的理由也寫進去了:工時要記在真的有做事的那段時間上。
2026-09-17 08:23:22 +00:00
jiantw83
958b1f85e8
test(pr-create): 開立 PR 並停錶
...
標題等同分支名:reviewer 在列表上看到的就是分支,兩者對不上會找錯 PR。
描述的段落固定且順序固定,缺一段或順序不對就擋下,不自動補——補出來的段落是編的,
而 reviewer 會把它當成真的。
「測試結果」另外驗一次它不是空話。那一段是 reviewer 唯一能判斷「這東西真的跑過嗎」的
依據,寫「已測試通過」等於沒寫。判斷刻意很窄,只擋「整段只有一行,而那一行是已知的
偷懶寫法」——這一關要擋的是明顯沒跑過就交差,不是去評價別人的測試寫得夠不夠好。
沒有自動化測試時,寫得出可重現的手動驗證步驟就放行。
停錶排在 PR 開出去之後,而且只在 PR 真的建立了才停:工時要記在真的有做事的那段時間上。
錶本來就沒在跑不算失敗(Gitea 對此回 500)——PR 已經開出去了,把整件事報成失敗只會讓人
以為 PR 沒開成而重跑一次。
2026-09-17 08:23:22 +00:00
jiantw83
b5214ed0f1
feat(pr-create): 開立 PR 並停錶
...
標題等同分支名:reviewer 在列表上看到的就是分支,兩者對不上會找錯 PR。
描述的段落固定且順序固定,缺一段或順序不對就擋下,不自動補——補出來的段落是編的,
而 reviewer 會把它當成真的。
「測試結果」另外驗一次它不是空話。那一段是 reviewer 唯一能判斷「這東西真的跑過嗎」的
依據,寫「已測試通過」等於沒寫。判斷刻意很窄,只擋「整段只有一行,而那一行是已知的
偷懶寫法」——這一關要擋的是明顯沒跑過就交差,不是去評價別人的測試寫得夠不夠好。
沒有自動化測試時,寫得出可重現的手動驗證步驟就放行。
停錶排在 PR 開出去之後,而且只在 PR 真的建立了才停:工時要記在真的有做事的那段時間上。
錶本來就沒在跑不算失敗(Gitea 對此回 500)——PR 已經開出去了,把整件事報成失敗只會讓人
以為 PR 沒開成而重跑一次。
2026-09-17 08:23:21 +00:00
jiantw83
d6b44e0ba8
test(分批提交): 把變更依類型分批 commit
...
一個 commit 只裝一種類型:程式碼、測試、文件、雜項各自成批,reviewer 一次只看一件事,
日後 git log 也讀得懂。全部混成一顆「完成工作包」的巨大 commit,等於沒有歷史。
類型多半看得出來——測試檔就是 test、README 就是 docs——但 scripts/ 底下的改動是新功能
還是修 bug,只有做的人知道,所以那一批由 --type 指定。這張對照表是純字串規則,表格驅動。
scope 單檔用檔名(claim.test.js 的 scope 是 claim,不是 claim.test),多檔用 --scope 的
功能名。描述要有中文:日後回顧時看得懂的是中文,而夾雜英文的專有名詞本來就該保留原文。
--files 讓一次變更橫跨兩個功能時能分兩次跑;--body 讓工具產出的歷史與本 repo 既有的
commit 一樣說明得出「為什麼」。
列變更檔案刻意不用 git status --porcelain:它的前兩欄是狀態碼,而 runGit 會 trim 掉
輸出的前導空白,未 staged 的修改會少掉檔名的第一個字元。
2026-09-17 08:23:21 +00:00
jiantw83
bb886457fd
feat(commit-split): 把變更依類型分批 commit
...
一個 commit 只裝一種類型:程式碼、測試、文件、雜項各自成批,reviewer 一次只看一件事,
日後 git log 也讀得懂。全部混成一顆「完成工作包」的巨大 commit,等於沒有歷史。
類型多半看得出來——測試檔就是 test、README 就是 docs——但 scripts/ 底下的改動是新功能
還是修 bug,只有做的人知道,所以那一批由 --type 指定。這張對照表是純字串規則,表格驅動。
scope 單檔用檔名(claim.test.js 的 scope 是 claim,不是 claim.test),多檔用 --scope 的
功能名。描述要有中文:日後回顧時看得懂的是中文,而夾雜英文的專有名詞本來就該保留原文。
--files 讓一次變更橫跨兩個功能時能分兩次跑;--body 讓工具產出的歷史與本 repo 既有的
commit 一樣說明得出「為什麼」。
列變更檔案刻意不用 git status --porcelain:它的前兩欄是狀態碼,而 runGit 會 trim 掉
輸出的前導空白,未 staged 的修改會少掉檔名的第一個字元。
2026-09-17 08:23:20 +00:00
jiantw83 and Claude Opus 5
8ea6a2a8b3
test(逐項實作): 覆蓋勾選的五種危險、兩份規則正本與正本第二段
...
勾選的測試全部繞著「會不會改錯行」打轉,五種都是 code review 抓出來的實際缺陷:
圍欄裡長得像 checkbox 的那一行不會被改到、不同段落的同一句話靠 --section 分得開、
大寫 [X] 重跑是 no-op、方框後沒有空白照樣勾得到、沒有方框的項目給的是指路的錯誤
而不是謊報已勾過。
另外釘住抽取端與勾選端的一致性:wp-extract 交得出來的每一種 raw,--tick 都要收得下。
patchOf 收進 helpers——它先前在三個測試檔裡各有一份一模一樣的定義。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:39:54 +00:00
jiantw83 and Claude Opus 5
a45e981c95
feat(流程正本): sdlc-feat 加入第二段「逐項實作」
...
一項一項做完並即時勾選,讓議題頁的進度條隨時反映真實狀態。
過程不打斷:二十項待辦不按二十次同意,只印進度;也不為了勾選留留言——勾選改的是 body,
進度條自己會動,逐項留言會把議題洗版,reviewer 得從一堆「已完成第 N 項」裡找真正的討論。
真正該停下來問的只有三種,列出來了。
規則正本指名讀取,不在這裡複述——抄過來就會有兩份各自演化的規則。
中斷後重跑從 Gitea 的勾選狀態接續,不看任何本機檔案;重複勾選是安靜的 no-op,
所以不確定某一項有沒有勾到時直接再勾一次即可,不必先查。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:39:48 +00:00
jiantw83 and Claude Opus 5
6e0fa92e73
feat(規則正本): 新增實作規範與註解格式對照表
...
兩份規則只存在於本 plugin 裡,由流程正本指名讀取,不寫進目標專案的任何檔案。
coding-standards.md 管規則:六種專案檔對應語言、認不出就停下來問;分層看職責不看目錄,
三層各寫功能/邏輯/資料源註解,服務層要標註呼叫的方法讓 reviewer 追得到呼叫鏈;
屬性的用途註解遞迴到每一層,並附真實資料範例,優先取自 MCP,推理來的要明講未經驗證
——不註明的話,會有人照著沒對過的格式寫解析。
comment-styles.md 只管格式:六種語言各一節,都附可照抄的方法註解與屬性註解範例。
Go 的「以識別字開頭」與 Python 的「docstring 在定義的下一行」各自點名,那是最常被
照抄成別的語言寫法的兩處。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:39:48 +00:00
jiantw83 and Claude Opus 5
586b746b55
feat(issue-update): 以 --tick 勾待辦,並在沒東西可改時不送空的 PATCH
...
--tick 收抽取契約交出的那一整行 raw,--section 指出它在哪一個段落。四種擋下來的情況
各有錯誤碼,因為使用者的下一步不同:找不到(抽取結果過期,重抽)、同段落出現多次
(請改寫議題上重複的說法)、那一項沒有方框(去議題上補)、段落不存在(對照輸出確認)。
一律報錯不盲改——改壞了議題的進度條會說謊,而沒有人會去比對 body 的編輯紀錄。
--tick 的輸入只驗「是不是清單項」,不要求方框。抽取端會把忘了寫 checkbox 的項目也收成
一項待辦,那種 raw 要走到 tickLine 才拿得到「去議題上補成 checkbox」這句話;
在入口就擋掉,使用者只會得到一個看不出該怎麼辦的格式錯誤。
沒有任何欄位要改時整個 PATCH 都不送:空的 PATCH 會把議題的 updated_at 推新,在列表上
浮起來像是有人動過。這個判斷做在試跑分支之前——放在後面的話,試跑會預告一個實跑根本
不會發的請求,而那是最難查的那種落差。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:39:44 +00:00
jiantw83 and Claude Opus 5
9582553c41
feat(議題解析): 勾選 checkbox 的精確替換,並統一清單項的文法
...
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 >
2026-09-17 07:39:43 +00:00
jiantw83 and Claude Opus 5
67528dde5f
fix(README): 安裝指令補上 git+ 前綴,否則 npm 會把它當壓縮檔
...
npm 只有看到 git/git+ssh/git+http/git+https/git+file 才會當成 git repo。
寫成 https://….git 會被歸類成遠端 tarball,下載回來解壓失敗,錯誤是
TAR_BAD_ARCHIVE: Unrecognized archive format——看起來完全不像「網址寫法錯了」,
使用者只會以為套件壞了。
先前那條「README 指令逐字執行得動」的測試沒抓到,因為它只跑 tea-sdlc 開頭的
行,npm 那行從來沒被執行過。補一條規則把 .git 網址必須帶 git+ 前綴釘住:
真的去跑一次 npm 全域安裝要開網路、要三秒,不適合放進這套向來密封的測試裡,
但「前綴在不在」這條規則本身就足以擋掉這個錯。
議題 #25
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 15:30:27 +08:00
jiantw83 and Claude Opus 5
cbf4c3df36
docs(README): 前置需求分開講安裝與跑流程,並把指令是否真的跑得動釘住
...
前置需求表原本一句「缺少時腳本印出指引並中止」套在所有需求上,但 install 只
警告不中止——文件描述的是一個不存在的行為。改成逐項寫「缺了會怎樣」,並把
「安裝只需要 Node」提到表前面:使用者不該為了裝 plugin 先去裝 tea。
另外補上三條把 #30 驗收標準真的驗起來的測試。其中一條把 README bash 區塊裡的
tea-sdlc 指令逐行拿去真的執行(家目錄指向空的暫存,所以一個檔都不會寫),
失敗理由若是「這個指令/參數我不認得」就算 README 寫錯——這比用眼睛核對可靠。
議題 #30
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:11:18 +00:00
jiantw83 and Claude Opus 5
002511ce45
test(sdlc-feat): 覆蓋領取鎖決策表、分支命名規則與三處不覆蓋他人進度
...
領取鎖的四種狀態各一例,而且每一種擋的情況都驗「一個字都沒寫進 Gitea」——擋下來卻已經
改了一半,比直接放行更難收拾。
分支命名是純字串規則,表格驅動:開發分支三種寫法、功能分支兩層,加上中文、超長、大寫、
底線與連續連字號的輸入驗證。
git 的部分在臨時 repo 上跑真的 git,釘住三件事後來由 code review 抓出來的實際缺陷:
遠端分支的比對必須用全名(否則 feat/x/main 會冒名頂替 main)、工作區不乾淨要在動手前
就擋、來源分支與遠端分歧要回可區分的錯誤碼而不是 git 的原始訊息。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:07:02 +00:00
jiantw83 and Claude Opus 5
e1897f2d33
test(helpers): 加上「有遠端」的臨時 repo,並收掉三份重複的 git 執行器
...
branch-prep 的重點行為都繞著遠端打轉——來源分支在遠端已存在時要 pull 而不是重建、
目標分支已存在時不能覆蓋他人進度。這些事沒有遠端就驗不出來,所以補一個 bare origin
加工作用 clone,並附 pushFromElsewhere 模擬「別人推了東西上去」。
順手把 makeTempRepo 與新 helper 各自重寫一次的 git 執行器與 seed 收成共用的兩支。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:07:01 +00:00
jiantw83 and Claude Opus 5
d55f1682b7
feat(流程正本): 新增 sdlc-feat 與它的第一段「領取與開工準備」
...
第一段把工作包安全地認領下來、起錶、備妥分支,不改任何一行程式碼——它只負責讓後面的
實作有個乾淨的起點。
正本負責三件腳本做不到的事:讀完工作包後,未處理留言不是 0 就先停下來建議整併;
新分支從哪裡長出來要問過使用者,一次一題、附理由、永遠留手動輸入;議題標題翻成英文
kebab 也是 agent 的事,腳本只驗格式。
領取鎖的四種狀態連同放行那一種都列在表上,缺標籤則另外交代——它是 repo 的前置條件,
不是鎖的第五種狀態,混在一起會讓決策表說不清楚。
工作包跨多個 repo 時逐一確認要在哪幾個開分支,分支名在每個 repo 都相同。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:07:01 +00:00
jiantw83 and Claude Opus 5
d153a49c47
feat(branch-prep): 依命名規則備妥開工的分支
...
命名規則照議題 #1:從開發分支長出 {類型}/{需求描述}/main,從功能分支長出時前兩段沿用
來源,子分支才會留在同一棵樹下。需求描述由議題標題翻譯,那是 agent 的事,所以這裡只收
--slug 並驗格式:英文 kebab、≤40 字元,中文分支名會讓 CI 與 URL 出問題。
三處「不弄丟別人的東西」,而且全部在任何 git 寫入之前判斷完:
- 工作區不乾淨就不動手。未提交的改動與未追蹤的檔案都會跟著 checkout 走到新分支上,
混進這顆工作包的 commit;目標分支已存在時,git 還會拖到 checkout 那一步才拒絕,
屆時 fetch 與 merge 都已經跑掉了。
- 來源分支在遠端已存在時 pull 而不是重建。
- 目標分支已存在時接上去而不是從來源蓋掉。
遠端分支的比對用全名 refs/heads/<ref>:ls-remote 的樣式比對吃的是 ref 尾段,而本 repo
的命名慣例讓每一支分支都以 /main 結尾——用短名比對,拿 main 當開發分支的專案會把
feat/x/main 誤認成 main,整個判成「遠端已經有這一支」。
算與做分成兩段,--dry-run 印出的就是真正將執行的那幾行 git,不另外維護一份描述。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:07:00 +00:00
jiantw83 and Claude Opus 5
7f24c9070e
feat(claim): 領取工作包,上鎖、貼標籤、起錶
...
鎖用 assignee 加標籤,不用碼錶——Gitea 只讓人讀自己的錶,看不到別人的,拿它當鎖會漏判。
碼錶在這裡只有一個用途:發現自己忘了停掉上一顆。
四種狀態的處置:他人已認領擋;自己的錶跑在本議題擋;跑在別的議題擋;沒有鎖放行。
後者包含「自己已認領但沒起錶」,那正是中斷後重跑的情形,重跑不會產生第二把鎖。
兩種碼錶的錯誤碼分開,因為使用者的下一步不同——一個是「你已經在做了」,
另一個是「你忘了停掉那一顆」。
會擋的判斷全部做在任何寫入之前,包含「repo 上有沒有『進行中』標籤」:本 plugin 不自動
建標籤,缺了就整件事不做,不要只設一半的鎖。錶則留到最後才起,前面任一步失敗時不該
留下一顆還在跑的碼錶。
--dry-run 走同一條路,只停在寫入之前。它印出的是這一顆此刻真正缺的那幾步,
不是一份手寫的固定清單——後者會跟實作走鐘,也說不出「這顆已經是你的了」。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:07:00 +00:00
jiantw83 and Claude Opus 5
f524f17375
fix(lib): git 的進度訊息不再漏到 stderr,並讓前置檢查交回帳號
...
兩件都是 branch-prep 與 claim 落地時才浮現的既有缺口:
git 把 checkout/fetch 的進度訊息全寫在 stderr,而 execFileSync 預設讓 stderr 直接
繼承給父行程。腳本的輸出契約是「stdout 一行 JSON、stderr 乾淨」,不收的話呼叫端還得
自己分辨哪幾行是雜訊。改成收進來;失敗時這些內容仍讀得到,錯誤訊息不會因此變模糊。
preflight 的第二層本來就打過 /user 問「我是誰」,卻只把答案丟掉,害呼叫端要再問一次。
改為連同 repo 資訊一起交回去。原本沒有任何呼叫端在用它的回傳值,形狀改變是安全的。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 07:06:59 +00:00
jiantw83 and Claude Opus 5
17178f0c4d
feat(佈署): 以 npm 裝出 tea-sdlc 指令並產生各平台轉接檔
...
單一入口 bin/tea-sdlc.js 認四個子指令。第一個位置參數是子指令,其餘 argv 原樣
交出去——既有的 flag 解析拒絕位置參數,所以子指令必須在那之前就被取走。
轉接檔裡沒有路徑,只有一句 tea-sdlc prompt --name <指令名>。正本在哪由 PATH 上
的 tea-sdlc 自己回推:fnm 把 Node 版號寫進全域安裝路徑,寫死路徑的話升一次
Node,七個平台的轉接檔會同時指向不存在的檔案,而且不會有任何錯誤訊息。
prompt 是全專案唯一輸出非 JSON 的路徑,理由只有一個:它的輸出要餵給模型讀。
失敗仍走 envelope——成功是內容,失敗才需要結構。
status 的 ok 不兼差表達環境好壞,健康與否放在 data.healthy:呼叫端要分得出
「status 掛了」與「status 成功查到你環境有問題」。
install 只寫進偵測得到的平台;缺 git/tea 只警告不中止,因為那兩個完全不影響
轉接檔產生,硬擋等於逼使用者為了裝 plugin 先去裝 tea。uninstall 只刪帶產生標記
的檔案,使用者自己寫的同名檔案一律留著並在輸出裡交代。裝哪些指令以 prompts/ 裡
實際存在的正本為準,不是寫死的六個名字——裝出指向不存在正本的轉接檔,使用者只會
看到 PROMPT_NOT_FOUND。
流程正本的 description 前綴在抄進轉接檔之前就檢查:有三個平台關不掉自動觸發,
全靠那句話把 description 窄到不會被誤判,不能等使用者發現誤觸才知道漏了。
議題 #26 #27 #28 #29 #17
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:59:37 +00:00
jiantw83 and Claude Opus 5
b56216e0f0
test(工時報表): 釘住週次歸屬的跨月、跨年與五個週五
...
時區在測試裡固定為 Asia/Taipei:週界是以人在的時區切的,不釘住時區就等於沒釘住答案。
--today 讓「本週」在 CLI 接縫上釘得住,否則預設期間會跟著系統時鐘漂走。
寫入請求那則斷言誠實列出唯一的非 GET——四層前置檢查的寫入權探針,
而不是先把它濾掉再宣稱整趟沒有寫入。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:50:35 +00:00
jiantw83 and Claude Opus 5
57e45dd63e
feat(流程正本): 新增 sdlc-report 與工時報表模板
...
正本釘住三件事:期間怎麼切、落差怎麼讀、印到哪裡為止。報表只印在終端,
不張貼到議題、PR 或任何管道——要給誰看是使用者的決定,不是這個流程的。
時分格式由腳本算好,正本明令直接取用:報表上的數字自己算錯,比沒有報表更糟。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:50:34 +00:00
jiantw83 and Claude Opus 5
fc30df15f2
feat(工時報表): 以 report.js 產出週/月/年工時報表
...
期間固定以週五當錨點:一週為週一至週日,跨月那一週依該週週五所屬月份歸屬,
一筆工時因此只會落在一個月裡,不會被前後兩個月各算一次。
工時取自 /user/times——它永遠只回傳自己的工時,不必有 issue manager 權限,
repo 的篩選因此在本地做。估算讀的是議題「關聯」段落裡的那一行,不是 Gitea 的
time_estimate 欄位:該欄位的 API 寫不進去,議題上唯一可信的估算就是那一行;
內嵌的議題沒帶 body 時補查一次議題,否則估算會整欄靜靜變成 null。
總計的落差只拿有估算的議題的實際去比。拿全部實際去比只有部分議題的估算,
會讓沒估算的工時全部變成「超出估算」,落差就永遠是灌水的正數。
labelledNumber 放進 issue-body:body 的解析正本在那裡,格式改一次不該動兩個模組。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:50:34 +00:00
jiantw83 and Claude Opus 5
74930b0571
test(wp-extract): 覆蓋契約欄位、模板變體、活狀態與 CRLF
...
解析是整條鏈的上游,解析錯則下游全錯,所以模板變體餵得雜一些:缺段落、巢狀驗收為空、
checkbox 已勾、中英混排、圍欄裡的假待辦、只寫一格的表格列。
另外釘住三件容易在日後鬆掉的事:
- `raw` 逐行出現在原始 body 裡,包括 CRLF 的 body 連行尾的 \r 都留著,否則下游替換
時對不上原文。
- 相依與留言都逐頁讀完,不是只讀第一頁。
- --dry-run 預告的請求順序與實跑一致,且完全不碰 Gitea。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:30:24 +00:00
jiantw83 and Claude Opus 5
4655a30f47
feat(wp-extract): 建立工作包的抽取契約
...
實作階段的指令給一個議題編號就拿得到它需要的一切,不必吞下整份議題全文。
輸出與議題 #1 的契約一致:待辦與它自己的驗收是巢狀的,每一項都帶未經修改的 `raw`,
下游靠它只改那一行、不重寫整份 body。
body 說不出的三個活狀態另外現查:相依走 dependencies/blocks 兩個端點並逐頁讀完
(半份清單會讓下游把實作順序排錯,那比直接報錯更難發現)、領取人看 assignee、碼錶
走 /user/stopwatches。碼錶那一項受限於 Gitea 只讓人讀自己的錶,真正的語意是「我的錶
正跑在這顆議題上」,這是議題 #1 已接受的取捨;領取鎖看的仍是 assignee。
同樣只讀 body 不讀留言,但回報未處理留言數。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:30:23 +00:00
jiantw83 and Claude Opus 5
98861cecbd
feat(議題解析): 解析巢狀待辦、多欄表格與關聯裡的議題編號
...
工作包議題比需求議題多三種結構,抽取契約(#9)要靠它們:
- checklistInSection 收 body 而不收切好的段落。它要交出的 `raw` 是下游勾選 checkbox
時做精確字串替換的依據,那一行必須逐字等於 body 裡的原樣,連縮排與行尾的 \r 都不能
動;段落切分會修掉前後空白,給不出這種保證。兩種畸形寫法都不丟內容:巢狀超過一層攤
進所在待辦的驗收,還沒有上層待辦就先出現的縮排項目升格成待辦。
- tableRows 保留全部欄位,tableSection 改寫成它的兩欄版。介面契約是四欄,先前那一支
只留兩欄。短的資料列補空字串——正本明講「不產出對外介面就寫一列『無』」,那一列不該
與「沒有這一段」混為一談。
- referencedIndex 從關聯段落讀出 `需求議題:#N`。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:30:23 +00:00
jiantw83 and Claude Opus 5
bbfa842e2a
refactor(抽取): 議題讀取與留言計數收進 lib,兩支抽取腳本共用
...
工作包的抽取契約(#9)要做的事與需求議題那一支有三件完全重疊:讀議題、把「不存在」
與「沒有讀取權」分成兩種錯誤碼、以 +1 reaction 數出未整併的留言則數。這三件事的規則
只該有一份,複製一份到新腳本等於日後改規則要記得改兩個地方。
fetchIssue、countUnmergedComments 與試跑時那句附註一起搬到 lib,issue-extract 改為
呼叫它們,行為不變。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:30:22 +00:00
jiantw83 and Claude Opus 5
3977523eb3
fix(議題解析): CRLF 的 body 不再讓清單靜靜變成空的
...
瀏覽器送出 textarea 一律用 CRLF,議題只要在 Gitea 網頁上被編輯過,body 逐行切開後
每一行行尾就掛著 \r。JS 的 . 不吃 \r,`(.*)$` 因此整行比不中——listSection 會把
目標、非目標、驗收標準這些段落一律回成空陣列,而且不報錯,下游拿到的是「這一段沒寫」
而不是「解析失敗」。
改用 [\s\S] 比對行尾,text 本來就有 trim 會把 \r 修掉。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:30:21 +00:00
jiantw83 and Claude Opus 5
a460d7e661
test(總覽網頁): 把三條驗不出東西的斷言改成驗得出來的
...
- mermaid 那條原本只比對「有出現 mermaid 字樣」,而 CDN 網址裡就有這個字,
整段渲染腳本刪掉也照樣通過。改成驗 mermaid.initialize 真的被呼叫。
- 新增一條守住例外的範圍:模板裡只能有那一段腳本,且不得夾帶網路或儲存操作。
- sdlc-plan 的七條斷言原本拿整份正本比對,任何一處撞到就算過。改成只看第 6 步,
與 sdlc-analyze 那邊的做法一致。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:22:31 +00:00
jiantw83 and Claude Opus 5
197de62570
fix(issue-update): 網址夾帶私有提醒時擋下,並修正 TDZ 錯誤
...
把上一次寫回的整行一起複製貼上是很常見的手誤,放行的話那句提醒會在議題上出現
兩次。
順帶修掉一個自己造出來的錯:PRIVACY_NOTE 原本宣告在 main() 之後,而新的檢查在
main() 的同步段就要用到它,於是每次執行都以「Cannot access 'PRIVACY_NOTE' before
initialization」收場。常數移到 main() 之前。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:22:30 +00:00
jiantw83 and Claude Opus 5
57c059b5f9
docs(慣例): 寫明總覽模板是「模板不含邏輯」的唯一例外
...
overview-artifact.html 是一份要在瀏覽器裡開的網頁,需要一段把 mermaid 畫出來的
腳本。與其默默違反自己寫的規則,不如把例外與理由寫進慣例表——下一個人才知道
這是想過的決定,而不是漏網的。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:22:30 +00:00
jiantw83 and Claude Opus 5
0aa0439061
test(總覽網頁): 釘住模板結構與兩份正本的規則
...
模板的檢查重點是「樣式與內容分離」與「全景段落能整段消失」,兩者壞掉時規劃版會
留下空標題或行內樣式散落各處,肉眼不容易發現。
順帶把 work-package 測試的 phase2 切法收斂到第三段之前——原本切到檔尾,第三段
新增的編號清單會混進段落順序的斷言裡。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:22:29 +00:00
jiantw83 and Claude Opus 5
47529d33c2
test(issue-update): 覆蓋總覽網址的寫回與就地更新
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:22:29 +00:00
jiantw83 and Claude Opus 5
6b30552ee2
feat(流程正本): 兩份正本加入產生總覽與寫回網址的步驟
...
規劃版填總覽、目標、流程圖,工作包全景填空字串;分析版沿用同一份模板,額外把
工作包的相依與截止日畫成 graph TD 的全景圖。節點一樣以 12 個為上限,超過就只畫
相依鏈最長路徑上的那幾顆。
兩份都寫回同一顆需求議題的同一行,所以分析版會取代規劃版——同一顆需求議題只掛
一個總覽網址,這是預期行為,正本裡寫明免得被當成 bug。
另外交代填模板時流程圖不帶圍欄:圍欄是議題 markdown 用的,填進 HTML 會多出一段
沒有意義的字。
Closes #10
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:22:28 +00:00
jiantw83 and Claude Opus 5
0e05dd2066
feat(issue-update): 支援 --overview-url,把總覽網址寫回議題
...
沿用既有的 upsertLineInSection:連結以固定前綴獨佔總覽段落裡的一行,重跑時就地
更新,不會長出第二個連結;議題原本的 markdown 白話總覽一字不動——網頁是補充,
不是取代。
連結旁自動附上「此連結預設為私有,組織外無法開啟」。讀到的人多半會想轉寄給組織外
的人,這句話寫在議題上比寫在文件裡有用。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:22:28 +00:00
jiantw83 and Claude Opus 5
ed2d08de9f
feat(總覽模板): 新增圖解版總覽的 HTML 模板
...
給非技術的利害關係人在會議上直接投影用:一句話總覽、目標、流程圖,分析階段再多
一張工作包全景。
樣式全部集中在單一 style 區塊,內文只放佔位——改版面不必動內容,換內容不必碰樣式。
深色模式跟隨系統,手機寬度另有斷點,投影與傳連結兩種場合都看得清楚。
工作包全景是整段佔位、獨佔一行,規劃階段填空字串時整段會乾淨消失;若把它包在寫死
的 section 裡,規劃版就會留下一個空標題。
mermaid 由 CDN 載入並實際渲染,而不是把原始碼丟給讀者看;代價是離線開啟時圖不會出來。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:22:27 +00:00
jiantw83 and Claude Opus 5
97d0afac38
test(project-add): 把「不建立專案」改成驗得出東西的斷言
...
原本的條件是「沒有非 GET 請求打到路徑含 project 的端點」,但 Gitea 的專案根本
沒有 API 路徑,這個條件恆真,壞掉的實作也會通過。改成斷言真正的寫入只有議題本身
那一次 PATCH、而且只帶 projects 欄位。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:12 +00:00
jiantw83 and Claude Opus 5
15da38a460
test(issue-update): 封住估算那一行的三種污染
...
三條測試都先確認過會在舊版實作上失敗。第一版寫出來時有兩條其實是陪跑的——
情境裡沒有後續段落,正確與錯誤的結果剛好都落在 body 結尾,分不出來。加上一個
真正的後續段落之後才有鑑別力。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:11 +00:00
jiantw83 and Claude Opus 5
b09746a309
test(排程): 覆蓋重複 index
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:11 +00:00
jiantw83 and Claude Opus 5
7a6cf948f5
fix(流程正本): 補回標題後被吃掉的空行
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:10 +00:00
jiantw83 and Claude Opus 5
be6ceddde0
refactor(參數): parseIndex 抽到 lib,四支腳本共用
...
同一段 /^[1-9]\d*$/ 與 BAD_INDEX 已經抄了四份。lib 本來就放著同性質的 parseRepo,
這一支該待在它旁邊。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:10 +00:00
jiantw83 and Claude Opus 5
e5b247e4cf
fix(排程): 拒絕重複的工作包 index
...
同一個 index 出現兩次時,相依看的是後者、標題與人天卻取到前者,算出來的時程是
兩份定義混出來的東西,而且回傳 ok:true 完全不報錯。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:09 +00:00
jiantw83 and Claude Opus 5
e494bd534e
fix(議題解析): upsertLineInSection 限定在目標段落內
...
三個實際重現過的污染情境:
- 圍欄裡的 `## 關聯` 被當成真標題,估算插進圍欄後面。本檔的共同前提是「圍欄裡的
東西不是內容」,這支卻自己用 indexOf 找標題,繞過了那個判斷。
- `## 關聯度說明` 被 indexOf 當成 `## 關聯` 命中,改到別人的段落。
- 「這一行是否已存在」用整份 body 比對,於是別的段落剛好有 `估算人天:` 時被改掉,
真正的關聯段落反而一直拿不到值。
改成沿用同檔的 eachLine 走行、標題要完全相同、既有那一行只在段落範圍內找。
弄錯的代價是靜靜改壞別人的內容,所以三道判斷都收緊。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:09 +00:00
jiantw83 and Claude Opus 5
257642cb1c
test(sdlc-analyze): 釘住第三段的腳本順序與已知限制那一節
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:08 +00:00
jiantw83 and Claude Opus 5
c635465751
feat(sdlc-analyze): 加入第三段,把工作包排上時程與看板
...
先算後寫:schedule 算出截止日,再由 issue-link、issue-update、project-add 逐顆
補上相依、時程與看板。三支都先試跑再實跑,三支都是冪等的。
另立一節寫明人天估算的 API 限制,而不是把它藏在行文裡——estimate 只寫得進 body,
sdlc-report 之後讀的也是那一行,這件事踩到才知道就太晚了。
邊界改成三段各自列:哪一段不做什麼講清楚,兩顆工作包才不會互相踩。
Closes #8
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:08 +00:00
jiantw83 and Claude Opus 5
5327f5882e
test(project-add): 覆蓋反查、貼網址、既有看板不被覆蓋
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:07 +00:00
jiantw83 and Claude Opus 5
770bf686ce
feat(project-add): 把議題放進看板,看板 id 靠掃議題反查
...
Gitea 1.27 沒有「列出專案」的 endpoint,名稱只能反查:掃最近 50 筆議題,從它們
身上的 projects 欄位湊出 id→名稱對照。全都沒掛看板時湊不出來,這時請使用者直接
貼專案網址,結尾即 id。
projects 欄位是整份取代不是附加,所以要先讀出議題既有的看板再聯集——漏掉就等於
把這顆議題踢出原本的看板。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:06 +00:00
jiantw83 and Claude Opus 5
3f97fe0901
test(issue-update): 覆蓋 Milestone 解析、日期格式與估算的就地更新
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:06 +00:00
jiantw83 and Claude Opus 5
45bfd99d80
feat(issue-update): 掛 Milestone、寫截止日、記人天估算
...
三件事經同一個 PATCH 送出,因為排時程時它們幾乎總是一起改,分開發等於多兩次往返。
Milestone 只認既有的:指到不存在的就中止並列出可選項目,本工具不建立 Milestone。
人天估算只寫進 body 的人類可讀一行。Gitea 1.27 的 API 沒有任何請求定義接受
time_estimate——它只出現在 Issue 的回應裡——所以議題的估算欄位無法由 API 寫入。
新增的 upsertLineInSection 負責就地更新那一行:重跑改估算不會累積成兩行,值沒變
就不把 body 塞進 PATCH,免得在議題上留下一筆沒有內容的編輯紀錄。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:05 +00:00
jiantw83 and Claude Opus 5
b45437e527
test(issue-link): 覆蓋兩種相依、冪等與自我相依
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:05 +00:00
jiantw83 and Claude Opus 5
b1025168c0
feat(issue-link): 建立議題之間的阻擋與先決
...
--depends 是「這顆被誰擋住」,--blocks 是「這顆擋住誰」。先讀現況只補缺的那幾條,
重跑不會在 Gitea 上堆出重複的相依。
請求必須帶 owner 與 repo:Gitea 的相依端點少了它們會回 404,而且訊息是「repository
does not exist」,不看文件會以為是路徑寫錯。
自己依賴自己擋在發出請求之前——Gitea 會接受,但那會讓後續的拓撲排序永遠排不完。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:04 +00:00
jiantw83 and Claude Opus 5
be477a4391
test(排程): 覆蓋拓撲順序、多重先決與成環
...
除了逐例比對日期,另有一條測試直接驗「所有先決關係都滿足」這個不變式,
而不是只比對硬編的日期字串——不變式壞掉時它會指出是哪一對。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:04 +00:00
jiantw83 and Claude Opus 5
0f53567737
feat(排程): 依相依關係拓撲推算截止日
...
保證一件事:任一工作包的截止日都不早於它的先決。人工排時程最常出現的矛盾就是
前置工作比後續還晚到期,看板上看起來合理、實際上做不到。
以 Kahn 演算法排序,排不完就代表有環,而環上的成員正是排不進去的那些,直接把
它們列出來——相依成環是拆法有問題,硬排沒有意義。
日期以日曆日累加,不跳週末也不扣假日:跳過哪些日子是團隊政策,這裡不替使用者
決定。這支腳本不碰 Gitea 也不碰 git,純算數字,因此沒有前置檢查也不需要登入。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 06:06:03 +00:00
jiantw83 and Claude Opus 5
6457d68874
refactor(測試): 模板結構的三項檢查抽到共用斷言
...
段落順序、正本的編號清單、圖表段落不寫死圍欄——這三件事需求議題與工作包議題
都要驗,第二份模板出現時就該抽出來。兩份測試原本各抄一份,其中佔位數的斷言
還悄悄長成不同寫法(一邊 >=、一邊 ==);抽出來之後這種分歧會被逼著講清楚。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:43:26 +00:00
jiantw83 and Claude Opus 5
9a67c8074f
fix(流程正本): 「不畫圖」綁回上限,不是免死金牌
...
兩份正本原本都只寫「不畫:一行說明為什麼不畫」,讀起來像是隨時可以跳過。
議題 #1 的原意是「超過上限即拆圖或不畫」——退路是給畫不下的情況用的。
改成只在超過上限拆不開、或畫了不會比文字更清楚時才選,兩份正本一起改,
免得兩邊講法不同。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:43:26 +00:00
jiantw83 and Claude Opus 5
7b54d566e2
docs(議題解析): 標明 tableSection 只處理兩欄
...
工作包的介面契約是四欄(介面/產出者/消費者/形狀),直接沿用這一支會無聲
丟掉第三、四欄。把限制寫在函式註解上,讓接手 wp-extract 的人一眼看到,而不是
自己踩一次才發現。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:43:25 +00:00
jiantw83 and Claude Opus 5
f0beb1ff64
test(工作包): 釘住模板與「產生工作包」那一段的規則
...
模板的段落順序決定 wp-extract 解析得到什麼,待辦的巢狀寫法決定實作階段勾得到
哪一行——這兩件事寫死在測試裡,改動時才會被逼著一起改。
巢狀範例的斷言不比對固定縮排量,而是比對「最深的一層比最淺的深」,這樣重排
外層清單的縮排不會弄壞測試。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:43:25 +00:00
jiantw83 and Claude Opus 5
0cd25d49d4
feat(sdlc-analyze): 擴充為兩段式,第二段把共識變成工作包議題
...
第一段到共識摘要為止仍然完全不寫入;使用者點頭之後才進入第二段建立議題。
邊界條文隨之改寫成「共識摘要之前不對 Gitea 產生任何寫入」,並明列第二段
不做的事:不建相依、不掛 Milestone、不加看板、不寫人天估算——那些是後續
流程的工作,寫在這裡會讓兩顆工作包互相踩。
工作包的切法、標題規則(動詞加名詞、禁止 WP-01 這類流水編號)、待辦與驗收
的巢狀寫法(附可照抄的範例)、架構圖依性質三選一,都在這一段定下來。
邊界的斷言跟著條文一起改,因為條文換了語意;分開成兩顆 commit 的話中間那顆
會是紅的。另補一條斷言:第一段不得出現任何寫入型腳本的名字。
Closes #7
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:43:24 +00:00
jiantw83 and Claude Opus 5
35bafcc928
feat(工作包): 新增工作包議題模板
...
九個段落與順序:這個工作包在做什麼/描述/架構圖/範圍邊界/介面契約/待辦/
整體驗收/repo 列表/關聯。段落順序即下游 wp-extract 的解析依據。
介面契約是四欄表格(介面/產出者/消費者/形狀)並帶分隔列,讓解析有明確的
資料列起點。架構圖同樣不寫死 mermaid 圍欄——正本允許不畫,圍欄寫死時不畫會在
議題頁留下一塊渲染失敗的空區塊。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:43:24 +00:00
jiantw83 and Claude Opus 5
8a405de189
test(sdlc-analyze): 覆蓋時程清單的估算前提
...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:11:07 +00:00
jiantw83 and Claude Opus 5
b79c68613a
fix(可行性檢查): 補上時程估算的前提,並讓四份清單結構一致
...
時程清單的「相依鏈最長路徑」預設了一份工作拆法,但分析階段還沒有工作包可依,
照著問會問不出東西。補上說明:這個階段要先拉一份暫定拆法,它同時是下一段開
工作包的草稿;拆不出來本身就是一個要問使用者的問題。
架構清單原本在開頭多了一段中間文字,內容與自己的「問題怎麼問」重複,也讓它
成為四份裡唯一結構不同的一份,移除。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:11:07 +00:00
jiantw83 and Claude Opus 5
2b06dfd663
test(sdlc-analyze): 釘住四份清單與正本的結構
...
這一顆沒有腳本,交付的就是文件本身,所以驗的是文件的結構:四份清單各有足夠
的檢查項與提問指引、正本逐一指名它們且順序為架構→邏輯→資料→時程、一次一題、
兩個固定選項、共識摘要只印不寫,以及「不對 Gitea 寫入」有被寫成明確邊界。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:11:06 +00:00
jiantw83 and Claude Opus 5
930270f545
refactor(測試): 正本的共用檢查抽到 helpers
...
description 前綴、沒有 frontmatter、不出現平台專屬字樣——這三件事每一份流程
正本都要驗,第二份正本出現時就該抽出來,而不是再抄一次。順帶把讀正本、讀規則
正本、讀模板三個路徑組合也收在同一處。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:11:06 +00:00
jiantw83 and Claude Opus 5
775909bd3d
feat(sdlc-analyze): 新增可行性分析的流程正本
...
一次問一題、依架構→邏輯→資料→時程清空、每題固定給「建議(含理由)」與
「手動輸入」兩個選項、最後輸出共識摘要。摘要只印在終端,這一段完全不寫入
Gitea——把工作包開出去是下一段的事。
開頭先看 issue-extract 回傳的未處理留言數:不是 0 就代表描述可能是過期的,
先提示使用者以 sdlc-sync 整併回描述再回來,堅持要繼續就在摘要裡註明。
明令「能在程式碼裡查證的就自己去查」,把問題留給只有人能回答的事。
Closes #6
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:11:05 +00:00
jiantw83 and Claude Opus 5
549bd29313
feat(可行性檢查): 新增架構、邏輯、資料、時程四份檢查清單
...
四份規則正本,各自列出要對著需求議題回答的檢查項,回答不出來的就是一個要問
使用者的問題。每份末尾都交代「問題怎麼問」——檢查項只說要查什麼,不說怎麼把
它變成一句能收斂的提問,那才是實際卡住的地方。
四份各自點出一個最該先問的:架構問落點與循環相依,邏輯問既有功能是不是已經
做過同一件事(這條能整個取消工作),資料問 schema 與遷移(答案通常不在議題裡),
時程問未知數最大的一項(它決定整體估算的可信度)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:11:05 +00:00
jiantw83 and Claude Opus 5
06de8980ca
test(issue-extract): 封住圍欄、表格與分頁的回頭路
...
八條新案例,每一條都對應一個實際重現過的缺陷:~~~ 圍欄、圍欄內的假清單項、
混用圍欄標記、未閉合圍欄的歸屬、逸脫的直線、第二條分隔列、巢狀攤平,以及
留言分頁。
把修正還原成舊版解析器後,這批測試有五條會失敗;修正回來則全綠——確認測試
真的抓得到,不是陪跑。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:00:29 +00:00
jiantw83 and Claude Opus 5
6125c2b6e0
fix(issue-extract): 留言逐頁讀完,不再只數第一頁
...
原本只打一次留言端點就收工,留言超過一頁時未整併的則數會少算——而少算的後果
是下游以為描述是最新的,照著過期的描述做事。改用 lib.pages 走完所有頁,讀不完
就以 COMMENT_LIMIT 報錯,不無聲回傳半份。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-09-17 05:00:28 +00:00