六個指令的第一版已經走通:六份流程正本、二十支腳本、四十個測試檔都已交付,規劃到工時回報整條鏈跑得起來。實際用下去之後,暴露出四個缺口。它們彼此無關,共同點只有一個——都是「跑起來之後才看得見」的那種問題。
一、每一步都由主 agent 親自做,脈絡被過程資訊塞滿。 有些步驟的過程根本不需要被看見:把議題標題翻成英文 kebab、依相依關係算截止日、把四份可行性清單逐條比對出疑點、產生一份 HTML 總覽。這些步驟只有結果要緊,但它們的中間產物——讀進來的整份清單、試了又丟的譯名、算到一半的拓撲排序——全部留在主 agent 的脈絡裡,把後面真正需要判斷力的步驟愈擠愈窄。這正是 #1 列的三種損耗中「token 浪費」那一條,只是換了個位置出現。
二、安裝完成不等於能用。 tea-sdlc install 跑完會回報寫了哪些轉接檔,但沒有人驗過那條鏈真的通:轉接檔 → PATH 上的 tea-sdlc → 流程正本。而這條鏈最脆弱的一環恰好在中間——套件裝在某個 Node 版本底下,換個版本就找不到了,而轉接檔本身看起來完全正常。使用者要到第一次打 /sdlc-plan 才發現,那時他已經離開安裝的心智狀態很久了。
tea-sdlc install
tea-sdlc
/sdlc-plan
三、sdlc-fix 只收得了 PR。 但要求改程式碼的意見不一定發在 PR 上——常常發在工作包議題或需求議題的留言裡。使用者手上有一個議題編號、看得到有人留言說「這裡要改」,卻沒有指令收得下它,只能自己翻出對應的工作包、自己記得該跑 /sdlc-feat。
sdlc-fix
/sdlc-feat
四、規劃與分析的時間完全不計。 碼錶只在 sdlc-feat 領取工作包時起動,所以 /sdlc-report 產出的數字裡,規劃與分析是零。久了會讓人以為「規劃不花時間」,而那正是估算失準最常見的來源——實作的工時有人記,想清楚要做什麼的工時沒人記。
sdlc-feat
/sdlc-report
四個缺口各自補上,彼此獨立可驗收。
委派:流程正本在只在意結果的步驟上標記 〔可委派〕,並以能力描述而非工具名說明怎麼委派——「你的環境若能把工作交給子代理就交出去,只把結果帶回來;不能就自己做」。對支援子代理的平台,那些步驟的中間產物不再進入主脈絡;對不支援的平台,同一句話自然降級成「自己做」,同一份正本兩邊都讀得通。
〔可委派〕
安裝驗證:install 結束時自動驗一次真實的叫用鏈——實際取回正本、比對各平台轉接檔存在且含正確的叫用行,逐平台回報。任一平台不通就讓 install 回失敗。「安裝完成」從此等於「驗過能用」。
install
sdlc-fix 收議題:輸入從「一個 PR 編號」放寬為「PR 編號或議題編號」。收到議題時不自己重做一遍實作流程,而是交棒給 sdlc-feat——交棒機制 sdlc-sync 已經定好了,複用即可。
sdlc-sync
規劃計時:sdlc-plan 在議題建立後起錶、回報時停錶,議題建立之前那段以補登方式記上去;sdlc-analyze 在需求議題上起錶、回報時停錶。每一段計時的起點與終點都寫在同一份正本裡,讀的人一眼看得出這段錶涵蓋到哪。
sdlc-plan
sdlc-analyze
取代 #14 的「輸入」:
一個 PR 編號。
改為:一個 PR 編號或議題編號。議題編號的處置見本需求的對應工作包。#14 其餘內容全部仍然成立。
明確未被取代者:#4 的驗收標準「流程正本為平台中立 markdown,不含任何平台專屬語法」繼續成立。委派以能力描述表達、不指名任何平台的工具,正是為了讓它繼續成立——這點要寫清楚,否則未來會有人以為委派把中立性犧牲掉了。
其餘已關閉的議題一律不修改,它們是歷史紀錄,忠實記載當時交付了什麼。
委派的表達方式
流程正本以能力描述說明委派,不指名任何平台的工具。寫法固定為一句話,大意是「這一步只在意結果;你的環境若能把工作交給子代理,就交出去,只把結果帶回來;不能就自己做」。
選這個寫法而不是直接寫平台工具名,是因為 #4 已交付的驗收標準明訂流程正本不含平台專屬語法,而子代理是平台專屬能力——Claude Code 與 Codex 有,Copilot/Kiro/OpenCode 不一定。能力描述對不支援的平台是自然降級,同一份正本兩邊都讀得通,不需要兩套。
也不採「由 install.js 在產生轉接檔時依平台注入」:轉接檔只有一行指回正本,塞不下步驟級的指示;而「哪些步驟可委派」是流程知識,搬進 install.js 會污染它「唯一知道各平台目錄結構」的單一職責。
install.js
可委派的判準
四條全部成立才可委派:
第 2 條是硬排除:子代理問不到使用者,一旦卡在提問就只能自行決定。所有「問到共識」類步驟一律不可委派。
第 4 條的理由不是子代理做不好,而是它的失敗沒有人看著:備妥工作樹失敗會中止整個領取、實際提交失敗會留下半套 git 歷史,這兩種都需要當場有人判斷下一步,而子代理只會把一個失敗訊息帶回來,主流程拿到時現場已經過去了。把寫入留在主流程,委派就只承擔「算出要寫什麼」,失敗頂多是算錯、重算一次。
判準寫進 references/delegation.md,沿用既有規則正本的英文檔名慣例與「# 標題 + 一句用途」的開頭形狀。
references/delegation.md
# 標題
標記形式
標題後綴 〔可委派〕,全形方括號。不用 emoji 也不用 HTML 註解——它要能被人眼掃到、被 grep 抓到,也要在七個平台的 markdown 渲染下都不出事。
不採集中清單:清單和步驟本體分離,改了步驟卻忘了改清單是遲早的事。不採步驟內文開頭加句:那裡應該放這一步要做什麼。
安裝驗證
install 寫完轉接檔後自動執行驗證:實際取回一次流程正本、比對各平台轉接檔存在且內容含正確的叫用行,逐平台 pass/fail 併入輸出。任一平台失敗則 install 回 ok:false。
ok:false
不沿用 status:它查的是環境與轉接檔數量,不驗「這條鏈真的叫得動」,而整個設計最脆弱的一環恰好是「轉接檔 → PATH 上的 tea-sdlc → 正本」這條鏈。
status
不把 test/ 打包進去讓使用者跑:那四十個測試檔驗的是開發期的契約,不是安裝結果,而且需要 stub server。
test/
驗證完全不需要網路——取正本是讀套件內的檔案,比對轉接檔是讀本機目錄。因此它可以無條件執行,不受 Gitea 登入或時間追蹤狀態影響。
驗證失敗不回滾,保留已寫的轉接檔。回滾在升級情境下會造成淨損失:使用者原本有一組能用的舊轉接檔,覆蓋後驗證失敗,回滾把新的刪掉、舊的也已經沒了,他從「有點舊但能用」變成「什麼都沒有」。而且最可能的病灶是「PATH 上找不到 tea-sdlc」(裝在另一個 Node 版本底下),那不是轉接檔的問題,刪掉它一點幫助也沒有。
sdlc-fix 的輸入型別
輸入放寬為 PR 編號或議題編號。型別判定沿用既有契約:以 wp-extract 解析,解析得出「母議題」欄位的就是工作包議題,否則當需求議題。不另發明判準。
wp-extract
收到議題時交棒給 sdlc-feat,不複製它的步驟。sdlc-feat 有領取鎖、起錶、備妥工作樹、逐項實作、分批提交、開 PR 一整套,抄進 sdlc-fix 會製造第二份正本,正是「流程正本只有一份」要防的事。交棒機制 sdlc-sync 已經定好——「整併完就直接接回去,從原本那個指令被打斷的地方繼續,不要要求使用者重打一次」——複用同一個機制。
順序是:先讓 sdlc-sync 把決策類留言整併掉,剩下確實是「要改程式碼」的,才進到選工作包。需求議題上的留言絕大多數是決策討論,先過一次 sync 通常就清空了,選工作包那一步根本不會觸發。收到需求議題且確實有改碼要求時,列出它底下的工作包讓使用者選一顆——使用者手上的資訊和流程一樣多,報錯只是把他無論如何都要做的事推回給他自己在 Gitea 網頁上做。
規劃與分析的計時
sdlc-plan:議題建立之後起錶(在此之前議題不存在,沒有標的可起),步驟 7 回報時停錶。議題建立之前那段以 POST /repos/{owner}/{repo}/issues/{index}/times 補登,不設上限、照實補登。代價是中途去開會的時間會被算進去,換來 sdlc-plan 不必為此多長一題出來。
POST /repos/{owner}/{repo}/issues/{index}/times
sdlc-analyze:在需求議題上起錶,步驟 12 回報時停錶。錶已經跑在同一顆議題上時 timer.js 什麼都不做,所以 plan 接著跑 analyze 不會把時間切成兩段。
timer.js
每個階段停掉自己起的錶,不讓錶跨階段跑。不採「讓 claim 偵測到錶跑在母需求議題上時自動停錶放行」:那是在「保護你不要忘記停錶」的關卡上開後門,而 Gitea 起新錶會靜默結算舊錶,這種靜默結算正是 claim 那條規則當初要擋的。
claim
起錶與停錶在同一份正本裡成對出現,讀正本的人一眼看得出這段計時的範圍到哪。
什麼是好的測試:只測外部行為。接縫維持既有的兩個,不新增:scripts/*.js 的 CLI 邊界(以子行程執行、比對單行 JSON 與 exit code)與 bin/tea-sdlc.js 的 CLI 邊界。
scripts/*.js
bin/tea-sdlc.js
流程正本的資產測試沿用既有那一組(test/sdlc-*-assets.test.js)。委派標記要加一條新斷言:正本上被標記 〔可委派〕 的步驟集合,等於 references/delegation.md 列出的集合。這條讓標記與判準不會各走各的——沒有它,兩邊遲早會漂開,而漂開時沒有任何東西會報錯。
test/sdlc-*-assets.test.js
測試對象優先序:
ok:true
--dry-run 兼作測試工具:補登與起錶在 --dry-run 下輸出將發出的請求而不執行,讓計時路徑不需要真實 Gitea 也能被斷言。這點特別重要——目前所有 repo 的時間追蹤都是關閉的,真實路徑跑不起來。
--dry-run
docs/adr/0002-以能力描述而非工具名表達委派.md
四顆工作包全部合併,四個缺口都補上了:
master 目前在 c545f11,全測 878 / 878 過。
c545f11
No dependencies set.
The note is not visible to the blocked user.
Problem Statement
六個指令的第一版已經走通:六份流程正本、二十支腳本、四十個測試檔都已交付,規劃到工時回報整條鏈跑得起來。實際用下去之後,暴露出四個缺口。它們彼此無關,共同點只有一個——都是「跑起來之後才看得見」的那種問題。
一、每一步都由主 agent 親自做,脈絡被過程資訊塞滿。 有些步驟的過程根本不需要被看見:把議題標題翻成英文 kebab、依相依關係算截止日、把四份可行性清單逐條比對出疑點、產生一份 HTML 總覽。這些步驟只有結果要緊,但它們的中間產物——讀進來的整份清單、試了又丟的譯名、算到一半的拓撲排序——全部留在主 agent 的脈絡裡,把後面真正需要判斷力的步驟愈擠愈窄。這正是 #1 列的三種損耗中「token 浪費」那一條,只是換了個位置出現。
二、安裝完成不等於能用。
tea-sdlc install跑完會回報寫了哪些轉接檔,但沒有人驗過那條鏈真的通:轉接檔 → PATH 上的tea-sdlc→ 流程正本。而這條鏈最脆弱的一環恰好在中間——套件裝在某個 Node 版本底下,換個版本就找不到了,而轉接檔本身看起來完全正常。使用者要到第一次打/sdlc-plan才發現,那時他已經離開安裝的心智狀態很久了。三、
sdlc-fix只收得了 PR。 但要求改程式碼的意見不一定發在 PR 上——常常發在工作包議題或需求議題的留言裡。使用者手上有一個議題編號、看得到有人留言說「這裡要改」,卻沒有指令收得下它,只能自己翻出對應的工作包、自己記得該跑/sdlc-feat。四、規劃與分析的時間完全不計。 碼錶只在
sdlc-feat領取工作包時起動,所以/sdlc-report產出的數字裡,規劃與分析是零。久了會讓人以為「規劃不花時間」,而那正是估算失準最常見的來源——實作的工時有人記,想清楚要做什麼的工時沒人記。Solution
四個缺口各自補上,彼此獨立可驗收。
委派:流程正本在只在意結果的步驟上標記
〔可委派〕,並以能力描述而非工具名說明怎麼委派——「你的環境若能把工作交給子代理就交出去,只把結果帶回來;不能就自己做」。對支援子代理的平台,那些步驟的中間產物不再進入主脈絡;對不支援的平台,同一句話自然降級成「自己做」,同一份正本兩邊都讀得通。安裝驗證:
install結束時自動驗一次真實的叫用鏈——實際取回正本、比對各平台轉接檔存在且含正確的叫用行,逐平台回報。任一平台不通就讓install回失敗。「安裝完成」從此等於「驗過能用」。sdlc-fix收議題:輸入從「一個 PR 編號」放寬為「PR 編號或議題編號」。收到議題時不自己重做一遍實作流程,而是交棒給sdlc-feat——交棒機制sdlc-sync已經定好了,複用即可。規劃計時:
sdlc-plan在議題建立後起錶、回報時停錶,議題建立之前那段以補登方式記上去;sdlc-analyze在需求議題上起錶、回報時停錶。每一段計時的起點與終點都寫在同一份正本裡,讀的人一眼看得出這段錶涵蓋到哪。取代宣告
取代 #14 的「輸入」:
改為:一個 PR 編號或議題編號。議題編號的處置見本需求的對應工作包。#14 其餘內容全部仍然成立。
明確未被取代者:#4 的驗收標準「流程正本為平台中立 markdown,不含任何平台專屬語法」繼續成立。委派以能力描述表達、不指名任何平台的工具,正是為了讓它繼續成立——這點要寫清楚,否則未來會有人以為委派把中立性犧牲掉了。
其餘已關閉的議題一律不修改,它們是歷史紀錄,忠實記載當時交付了什麼。
User Stories
sdlc-fix收得下議題編號,以便發在議題上的修改要求也有指令處理得了。sdlc-fix自己分辨我給的是工作包還是需求議題,以便不必先查清楚才敢下指令。sdlc-fix把實作流程重做一遍,以便流程正本只有一份、不會兩邊走鐘。Implementation Decisions
委派的表達方式
流程正本以能力描述說明委派,不指名任何平台的工具。寫法固定為一句話,大意是「這一步只在意結果;你的環境若能把工作交給子代理,就交出去,只把結果帶回來;不能就自己做」。
選這個寫法而不是直接寫平台工具名,是因為 #4 已交付的驗收標準明訂流程正本不含平台專屬語法,而子代理是平台專屬能力——Claude Code 與 Codex 有,Copilot/Kiro/OpenCode 不一定。能力描述對不支援的平台是自然降級,同一份正本兩邊都讀得通,不需要兩套。
也不採「由
install.js在產生轉接檔時依平台注入」:轉接檔只有一行指回正本,塞不下步驟級的指示;而「哪些步驟可委派」是流程知識,搬進install.js會污染它「唯一知道各平台目錄結構」的單一職責。可委派的判準
四條全部成立才可委派:
第 2 條是硬排除:子代理問不到使用者,一旦卡在提問就只能自行決定。所有「問到共識」類步驟一律不可委派。
第 4 條的理由不是子代理做不好,而是它的失敗沒有人看著:備妥工作樹失敗會中止整個領取、實際提交失敗會留下半套 git 歷史,這兩種都需要當場有人判斷下一步,而子代理只會把一個失敗訊息帶回來,主流程拿到時現場已經過去了。把寫入留在主流程,委派就只承擔「算出要寫什麼」,失敗頂多是算錯、重算一次。
判準寫進
references/delegation.md,沿用既有規則正本的英文檔名慣例與「# 標題+ 一句用途」的開頭形狀。標記形式
標題後綴
〔可委派〕,全形方括號。不用 emoji 也不用 HTML 註解——它要能被人眼掃到、被 grep 抓到,也要在七個平台的 markdown 渲染下都不出事。不採集中清單:清單和步驟本體分離,改了步驟卻忘了改清單是遲早的事。不採步驟內文開頭加句:那裡應該放這一步要做什麼。
安裝驗證
install寫完轉接檔後自動執行驗證:實際取回一次流程正本、比對各平台轉接檔存在且內容含正確的叫用行,逐平台 pass/fail 併入輸出。任一平台失敗則install回ok:false。不沿用
status:它查的是環境與轉接檔數量,不驗「這條鏈真的叫得動」,而整個設計最脆弱的一環恰好是「轉接檔 → PATH 上的tea-sdlc→ 正本」這條鏈。不把
test/打包進去讓使用者跑:那四十個測試檔驗的是開發期的契約,不是安裝結果,而且需要 stub server。驗證完全不需要網路——取正本是讀套件內的檔案,比對轉接檔是讀本機目錄。因此它可以無條件執行,不受 Gitea 登入或時間追蹤狀態影響。
驗證失敗不回滾,保留已寫的轉接檔。回滾在升級情境下會造成淨損失:使用者原本有一組能用的舊轉接檔,覆蓋後驗證失敗,回滾把新的刪掉、舊的也已經沒了,他從「有點舊但能用」變成「什麼都沒有」。而且最可能的病灶是「PATH 上找不到
tea-sdlc」(裝在另一個 Node 版本底下),那不是轉接檔的問題,刪掉它一點幫助也沒有。sdlc-fix的輸入型別輸入放寬為 PR 編號或議題編號。型別判定沿用既有契約:以
wp-extract解析,解析得出「母議題」欄位的就是工作包議題,否則當需求議題。不另發明判準。收到議題時交棒給
sdlc-feat,不複製它的步驟。sdlc-feat有領取鎖、起錶、備妥工作樹、逐項實作、分批提交、開 PR 一整套,抄進sdlc-fix會製造第二份正本,正是「流程正本只有一份」要防的事。交棒機制sdlc-sync已經定好——「整併完就直接接回去,從原本那個指令被打斷的地方繼續,不要要求使用者重打一次」——複用同一個機制。順序是:先讓
sdlc-sync把決策類留言整併掉,剩下確實是「要改程式碼」的,才進到選工作包。需求議題上的留言絕大多數是決策討論,先過一次 sync 通常就清空了,選工作包那一步根本不會觸發。收到需求議題且確實有改碼要求時,列出它底下的工作包讓使用者選一顆——使用者手上的資訊和流程一樣多,報錯只是把他無論如何都要做的事推回給他自己在 Gitea 網頁上做。規劃與分析的計時
sdlc-plan:議題建立之後起錶(在此之前議題不存在,沒有標的可起),步驟 7 回報時停錶。議題建立之前那段以POST /repos/{owner}/{repo}/issues/{index}/times補登,不設上限、照實補登。代價是中途去開會的時間會被算進去,換來sdlc-plan不必為此多長一題出來。sdlc-analyze:在需求議題上起錶,步驟 12 回報時停錶。錶已經跑在同一顆議題上時timer.js什麼都不做,所以 plan 接著跑 analyze 不會把時間切成兩段。每個階段停掉自己起的錶,不讓錶跨階段跑。不採「讓
claim偵測到錶跑在母需求議題上時自動停錶放行」:那是在「保護你不要忘記停錶」的關卡上開後門,而 Gitea 起新錶會靜默結算舊錶,這種靜默結算正是claim那條規則當初要擋的。起錶與停錶在同一份正本裡成對出現,讀正本的人一眼看得出這段計時的範圍到哪。
Testing Decisions
什麼是好的測試:只測外部行為。接縫維持既有的兩個,不新增:
scripts/*.js的 CLI 邊界(以子行程執行、比對單行 JSON 與 exit code)與bin/tea-sdlc.js的 CLI 邊界。流程正本的資產測試沿用既有那一組(
test/sdlc-*-assets.test.js)。委派標記要加一條新斷言:正本上被標記〔可委派〕的步驟集合,等於references/delegation.md列出的集合。這條讓標記與判準不會各走各的——沒有它,兩邊遲早會漂開,而漂開時沒有任何東西會報錯。測試對象優先序:
ok:true;刻意破壞某平台的轉接檔內容時該平台 fail 且install回ok:false;失敗時已寫的轉接檔仍然存在(不回滾);驗證不發出任何網路請求。sdlc-fix的型別判定 —— 工作包議題、需求議題、PR 三種輸入各一例,斷言判定結果與後續走向;需求議題且無未整併留言時列出工作包清單。sdlc-plan與sdlc-analyze的正本裡,起錶與停錶必須成對出現;補登請求的時長等於「指令開始到議題建立」的差值。--dry-run兼作測試工具:補登與起錶在--dry-run下輸出將發出的請求而不執行,讓計時路徑不需要真實 Gitea 也能被斷言。這點特別重要——目前所有 repo 的時間追蹤都是關閉的,真實路徑跑不起來。Out of Scope
test/打包進發佈的套件。sdlc-fix複製sdlc-feat的步驟。claim上開自動停錶的後門。Further Notes
sdlc-feat步驟 4(把議題標題翻成英文)、步驟 8(認出語言,讀規則正本)、步驟 13 的分批方案計算(實際 commit 仍由主流程執行)、sdlc-analyze步驟 2(對四份清單列出疑點)、步驟 9(算出截止日)、步驟 11 與sdlc-plan步驟 6(產生圖解版總覽)。sdlc-plan與sdlc-analyze的正本,而計時是在既有步驟序列裡插入新步驟、委派是在既有步驟上加標記。先插入再標記,標記落在穩定的步驟編號上;反過來做,插入會把後面的步驟編號全部往後推,剛標記好的位置要重對一次。sdlc-fix收議題各自動不同的檔案,彼此無相依,可與其餘兩包並行。--dry-run與 stub server。這不是本需求要解的問題,但實作時會撞到。docs/adr/0002-以能力描述而非工具名表達委派.md。四顆工作包全部合併,四個缺口都補上了:
master 目前在
c545f11,全測 878 / 878 過。