feat/claim-and-branch-prep/main
master
/sdlc-feat 的第一段:把一顆工作包安全地認領下來、起錶、備妥開工的分支。 這一段不改任何一行程式碼,它只負責讓後面的實作有個乾淨的起點。
/sdlc-feat
#1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組
#11 — 以 sdlc-feat 領取工作包、起錶並備妥分支
fix(lib)
feat(claim)
feat(branch-prep)
feat(流程正本)
sdlc-feat
test(helpers)
test(sdlc-feat)
新增 scripts/claim.js、scripts/branch-prep.js、prompts/sdlc-feat.md。
scripts/claim.js
scripts/branch-prep.js
prompts/sdlc-feat.md
--dry-run
--slug
Code review 在落地過程中抓出三個實際缺陷,都已修掉並各自補上回歸測試:
1. ls-remote 的樣式比對吃的是 ref 尾段。 git ls-remote --heads origin main 會匹配到 refs/heads/feat/x/main——而本 repo 的命名慣例讓每一支分支都以 /main 結尾,任何拿 main 當開發分支的專案,都會把別人的功能分支誤認成自己的來源分支。 改用全名 refs/heads/<ref> 比對。
ls-remote
git ls-remote --heads origin main
refs/heads/feat/x/main
/main
main
refs/heads/<ref>
2. 工作區不乾淨時沒擋。 未提交的改動與未追蹤的檔案會跟著 checkout 走進這顆工作包的 分支、混進 commit;而目標分支已在遠端時,git 會拖到 checkout 那一步才拒絕,屆時 fetch 與 merge 都已經跑掉了,而 --dry-run 才剛印出一份漂亮的五步計畫。改成開工前 就擋,並把 git 回報的檔案原樣交給使用者決定。
fetch
merge
3. git 的進度訊息漏到 stderr(既有缺口)。 execFileSync 預設讓 stderr 繼承給父行程, 而 git 把 checkout/fetch 的訊息全寫在那裡。腳本的輸出契約是「stdout 一行 JSON、 stderr 乾淨」,漏出去的話呼叫端還得自己分辨哪幾行是雜訊。
execFileSync
checkout
lib.js
preflight
{repo, user}
runGit
branch-prep
#12
#13
本分支與 master 的 lib.js 各自改了不同區域(master 上新增了 RawText、 packageManifest、promptsDir),已做三方合併,無衝突,兩邊的改動都在。
RawText
packageManifest
promptsDir
在合併 master 之後的完整樹上實際執行 npm test(master 既有 386 + 本分支新增 60):
npm test
ℹ tests 446 ℹ suites 0 ℹ pass 446 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
領取鎖的四種狀態各一例,且每一種擋的情況都驗「一個字都沒寫進 Gitea」。分支命名是純字串 規則,表格驅動涵蓋開發分支三種寫法與功能分支兩層,加上中文、超長、大寫、底線、連續連 字號的輸入驗證。git 的部分在臨時 repo(bare origin + 工作用 clone)上跑真的 git。
另以實機演練確認:ls-remote 誤判已修正、工作區不乾淨會在動手前擋下且不留半途狀態、 branch-prep 跑完 stderr 為空、目標專案工作區乾淨無殘留狀態檔。
未能實機貫通的一段:claim 對本 repo 跑不到底——repo 尚未開啟時間追蹤 (TIME_TRACKER_OFF),且上面只有 ready-for-agent 一個標籤、沒有「進行中」 (LABEL_NOT_FOUND)。兩者都是本次設計中「明確錯誤碼指出該去哪裡改」的預期行為, 但領取流程的實機貫通要等這兩項設定就緒後才驗得了。
claim
TIME_TRACKER_OFF
ready-for-agent
LABEL_NOT_FOUND
🤖 Generated with Claude Code
兩件都是 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>
鎖用 assignee 加標籤,不用碼錶——Gitea 只讓人讀自己的錶,看不到別人的,拿它當鎖會漏判。 碼錶在這裡只有一個用途:發現自己忘了停掉上一顆。 四種狀態的處置:他人已認領擋;自己的錶跑在本議題擋;跑在別的議題擋;沒有鎖放行。 後者包含「自己已認領但沒起錶」,那正是中斷後重跑的情形,重跑不會產生第二把鎖。 兩種碼錶的錯誤碼分開,因為使用者的下一步不同——一個是「你已經在做了」, 另一個是「你忘了停掉那一顆」。 會擋的判斷全部做在任何寫入之前,包含「repo 上有沒有『進行中』標籤」:本 plugin 不自動 建標籤,缺了就整件事不做,不要只設一半的鎖。錶則留到最後才起,前面任一步失敗時不該 留下一顆還在跑的碼錶。 --dry-run 走同一條路,只停在寫入之前。它印出的是這一顆此刻真正缺的那幾步, 不是一份手寫的固定清單——後者會跟實作走鐘,也說不出「這顆已經是你的了」。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
命名規則照議題 #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>
第一段把工作包安全地認領下來、起錶、備妥分支,不改任何一行程式碼——它只負責讓後面的 實作有個乾淨的起點。 正本負責三件腳本做不到的事:讀完工作包後,未處理留言不是 0 就先停下來建議整併; 新分支從哪裡長出來要問過使用者,一次一題、附理由、永遠留手動輸入;議題標題翻成英文 kebab 也是 agent 的事,腳本只驗格式。 領取鎖的四種狀態連同放行那一種都列在表上,缺標籤則另外交代——它是 repo 的前置條件, 不是鎖的第五種狀態,混在一起會讓決策表說不清楚。 工作包跨多個 repo 時逐一確認要在哪幾個開分支,分支名在每個 repo 都相同。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
branch-prep 的重點行為都繞著遠端打轉——來源分支在遠端已存在時要 pull 而不是重建、 目標分支已存在時不能覆蓋他人進度。這些事沒有遠端就驗不出來,所以補一個 bare origin 加工作用 clone,並附 pushFromElsewhere 模擬「別人推了東西上去」。 順手把 makeTempRepo 與新 helper 各自重寫一次的 git 執行器與 seed 收成共用的兩支。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
領取鎖的四種狀態各一例,而且每一種擋的情況都驗「一個字都沒寫進 Gitea」——擋下來卻已經 改了一半,比直接放行更難收拾。 分支命名是純字串規則,表格驅動:開發分支三種寫法、功能分支兩層,加上中文、超長、大寫、 底線與連續連字號的輸入驗證。 git 的部分在臨時 repo 上跑真的 git,釘住三件事後來由 code review 抓出來的實際缺陷: 遠端分支的比對必須用全名(否則 feat/x/main 會冒名頂替 main)、工作區不乾淨要在動手前 就擋、來源分支與遠端分歧要回可區分的錯誤碼而不是 git 的原始訊息。 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的第一段:把一顆工作包安全地認領下來、起錶、備妥開工的分支。這一段不改任何一行程式碼,它只負責讓後面的實作有個乾淨的起點。
需求議題
#1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組
工作包議題
#11 — 以 sdlc-feat 領取工作包、起錶並備妥分支
變更內容
fix(lib)feat(claim)feat(branch-prep)feat(流程正本)sdlc-feat與它的第一段test(helpers)test(sdlc-feat)新增
scripts/claim.js、scripts/branch-prep.js、prompts/sdlc-feat.md。設計重點
拿它當鎖會漏判。碼錶在這裡只有一個用途:發現自己忘了停掉上一顆。
重跑不會產生第二把鎖。兩種碼錶的錯誤碼分開,因為使用者的下一步不同。
錶留到最後才起:前面任一步失敗時,不該留下一顆還在跑的碼錶。
--dry-run走同一條路,只停在寫入之前。 它印出的是這一顆此刻真正缺的那幾步,不是一份手寫的固定清單——後者會跟實作走鐘,也說不出「這顆已經是你的了」。
--slug並驗格式(英文 kebab、≤40 字元)。中文分支名會讓 CI 與 URL 出問題,擋在建立之前。
解決的問題
Code review 在落地過程中抓出三個實際缺陷,都已修掉並各自補上回歸測試:
1.
ls-remote的樣式比對吃的是 ref 尾段。git ls-remote --heads origin main會匹配到
refs/heads/feat/x/main——而本 repo 的命名慣例讓每一支分支都以/main結尾,任何拿
main當開發分支的專案,都會把別人的功能分支誤認成自己的來源分支。改用全名
refs/heads/<ref>比對。2. 工作區不乾淨時沒擋。 未提交的改動與未追蹤的檔案會跟著 checkout 走進這顆工作包的
分支、混進 commit;而目標分支已在遠端時,git 會拖到 checkout 那一步才拒絕,屆時
fetch與merge都已經跑掉了,而--dry-run才剛印出一份漂亮的五步計畫。改成開工前就擋,並把 git 回報的檔案原樣交給使用者決定。
3. git 的進度訊息漏到 stderr(既有缺口)。
execFileSync預設讓 stderr 繼承給父行程,而 git 把
checkout/fetch的訊息全寫在那裡。腳本的輸出契約是「stdout 一行 JSON、stderr 乾淨」,漏出去的話呼叫端還得自己分辨哪幾行是雜訊。
影響的功能
lib.js的preflight回傳形狀由 repo 資訊改為{repo, user}:第二層本來就問過「我是誰」卻把答案丟掉,害呼叫端要再問一次。原本沒有任何呼叫端在用它的回傳值。
runGit的 stderr 改為收進來,影響所有未來走 git 的腳本(目前只有branch-prep)。#12/#13會接在這一段之後:逐項實作並勾選待辦、分批提交並開 PR 停錶。本分支與 master 的
lib.js各自改了不同區域(master 上新增了RawText、packageManifest、promptsDir),已做三方合併,無衝突,兩邊的改動都在。測試結果
在合併 master 之後的完整樹上實際執行
npm test(master 既有 386 + 本分支新增 60):領取鎖的四種狀態各一例,且每一種擋的情況都驗「一個字都沒寫進 Gitea」。分支命名是純字串
規則,表格驅動涵蓋開發分支三種寫法與功能分支兩層,加上中文、超長、大寫、底線、連續連
字號的輸入驗證。git 的部分在臨時 repo(bare origin + 工作用 clone)上跑真的 git。
另以實機演練確認:
ls-remote誤判已修正、工作區不乾淨會在動手前擋下且不留半途狀態、branch-prep跑完 stderr 為空、目標專案工作區乾淨無殘留狀態檔。未能實機貫通的一段:
claim對本 repo 跑不到底——repo 尚未開啟時間追蹤(
TIME_TRACKER_OFF),且上面只有ready-for-agent一個標籤、沒有「進行中」(
LABEL_NOT_FOUND)。兩者都是本次設計中「明確錯誤碼指出該去哪裡改」的預期行為,但領取流程的實機貫通要等這兩項設定就緒後才驗得了。
🤖 Generated with Claude Code
命名規則照議題 #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>