Merge pull request '新增 WP-01 十項定案規格與 TODO.md 校正清單文件' (#79) from docs/wp01-baseline-decisions/delivery-spec into docs/wp01-baseline-decisions/main

Reviewed-on: #79
This commit was merged in pull request #79.
This commit is contained in:
2026-09-08 01:24:13 +00:00
2 changed files with 231 additions and 0 deletions
+188
View File
@@ -0,0 +1,188 @@
# 十項定案規格
這份文件收錄分析頁裡十項技術裁定的定案內容,每項附出處與具體例子,供後續工作包直接引用,不必回頭翻找分析頁全文。
## N-01:雜湊輸入分隔符
**裁決**:多個欄位(例如計畫名稱與存取庫路徑)要接成一個雜湊輸入字串時,固定用直線號 `|` 當分隔符。組法收在 `hash-id` 的 `key` 子命令這個單一入口,各技能不再自己接字串。
**出處**:「工作分解結構(WBS)」層1 共用腳本表格,工作包名稱「hash-id 加 key 子命令:分隔符 `|`、四道正規化、組法收單一入口」;測試計畫「雜湊組法收單一入口」小節第一個 TDD 循環,斷言 `hash-id key "我的計畫" "plugins/sdlc"` 與 `hash-id "我的計畫|plugins/sdlc"` 輸出同一個 40 碼雜湊。
**例外**:本份分析頁自己的雜湊輸入不吃 `{owner}/{repo}`,只用計畫名稱,理由是這一輪盤點橫跨 11 個存取庫,綁任一個存取庫都是錯的。這是單一頁面的特例,不是分隔符定案本身跟著變。
**例子**:
```
hash-id key "我的計畫" "plugins/sdlc"
# 與下面這行輸出同一個 40 碼大寫 SHA-1
hash-id "我的計畫|plugins/sdlc"
```
## N-02:計畫名稱正規化規則
**裁決**:計畫名稱進雜湊前,固定套四道正規化,依序是:
1. Unicode NFC 正規化
2. 去除頭尾空白
3. 內部連續空白壓成一個半形空白
4. 英數字元全形轉半形
大小寫不在正規化範圍內,維持原樣、視為不同名稱。
**出處**:測試計畫「雜湊組法收單一入口」小節第二個 TDD 循環,斷言「我的 計畫」「我的 計畫」「我的計畫 」三種輸入正規化後相同,而「ABC 計畫」與「abc 計畫」不同;最小實作寫明四道正規化內容。
**例子**:
- `我的 計畫`、`我的 計畫`(全形空白)、`我的 計畫`(兩個半形空白)→ 正規化後同一個結果,雜湊相同,第二次建立同名計畫會被擋下
- `ABC 計畫` 與 `abc 計畫` → 正規化後仍不同,雜湊不同,兩者當成不同計畫
可直接貼進測試檔的指令:
```
hash-id key "我的 計畫" "plugins/sdlc"
hash-id key "我的 計畫" "plugins/sdlc"
hash-id key "我的 計畫" "plugins/sdlc"
# 三行輸出同一個 40 碼雜湊
hash-id key "ABC 計畫" "plugins/sdlc"
hash-id key "abc 計畫" "plugins/sdlc"
# 兩行輸出不同雜湊,這是反例,證明大小寫不會被正規化抹掉
```
## N-05:跨存取庫工作包編號起算
**裁決**:每一份分析頁的工作包編號各自從 `WP-01` 起算,不跨頁連號。因此鎖定工作包不能只看編號,要在前面加上該分析頁自己的雜湊當複合鍵,兩份不同分析頁裡同編號的工作包才不會互搶同一把鎖。
**出處**:「工作分解結構(WBS)」層2 技能行為表格,處理 analyze 頁名與跨庫的工作包名稱寫明「各頁 WP-01 起算」;對應 TDD 小節斷言兩份不同分析頁各自的「雜湊組法收單一入口」下游工作包不互相搶鎖,最小實作是把鎖鍵改成「`{分析頁雜湊}#WP-NN`」複合鍵。
**例子**:分析頁 A 與分析頁 B 各有自己的第二個工作包。鎖鍵分別是 `{分析頁A雜湊}#WP-02` 與 `{分析頁B雜湊}#WP-02`,領取其中一個不影響另一個,兩邊各自從 1 起算。
## N-07:`PLAN_CONTENTS` 存取庫欄格式
**裁決**:`PLAN_CONTENTS` 目錄頁的存取庫欄改成清單,同一行、多個值用頓號分隔,不拆成多行子條列。
**出處**:「工作分解結構(WBS)」層2 技能行為表格,工作包名稱「`PLAN_CONTENTS` 存取庫欄改清單,同行頓號分隔」;對應 TDD 小節斷言那一行 upsert 後讀得回多個值,最小實作是改範本並在寫入時以頓號串接。
**例子**:
```
- 存取庫:plugins/sdlc、plugins/log
```
## L-03:年月週次進雜湊輸入
**裁決**:工作日誌頁名的雜湊輸入改吃「年-月-週次」字串(例如 `2026-09-W1`),取代原本的 `{owner}/{repo}`。週次字串進的是雜湊輸入本身,不是先照舊算出雜湊再在頁名後面加後綴。
**出處**:測試計畫「一週一頁工作日誌」小節第一個 TDD 循環,斷言三個不同存取庫、同一週的三筆日誌落在同一頁,且雜湊輸入不含 `{owner}/{repo}`,最小實作是「頁名改吃週次字串」。
**例子**:`plugins/sdlc`、`plugins/log`、`plugins/meta` 三個存取庫在同一週(週五落在 2026-09-04)各寫一筆日誌。三筆都算出同一個雜湊、落在同一頁 `LOG_{hash(2026-09-W1)}`,各自在頁面內容裡帶自己的存取庫欄位。
可直接貼進測試檔的指令:
```
worklog-target.sh week 2026-09-04
# 輸出:2026-09-W1
```
邊界情況(反例,跨月份):`2026-08-28` 是 8 月最後一個週五,算出 `2026-08-W4`;隔一週的 `2026-09-04` 只差 7 天,卻因為跨了月份算出 `2026-09-W1`。兩者雜湊不同、落在不同頁,不能因為「只差一週」就假設落在同一頁。
```
worklog-target.sh week 2026-08-28
# 輸出:2026-08-W4
```
## L-05:舊日誌拆頁
**裁決**:舊制一庫一頁的工作日誌,依每筆條目自己的日期拆進對應的週頁,不整頁原樣搬過去。拆頁動作可重跑不重複(用條目內容雜湊去重),拆不出日期的條目列進待處理清單,不猜日期也不丟棄。
**出處**:「工作分解結構(WBS)」層3 搬遷與清理表格,工作包名稱「舊一庫一頁日誌依條目日期拆進各週頁,可重跑」,標明「不可逆」;對應 TDD 小節斷言含日期的條目落到正確週頁、沒日期的條目列進待處理清單且不丟掉,同一份輸入跑兩次不產生重複條目。
**例子**:舊頁裡四筆條目:
| 條目 | 日期 | 落頁 |
| --- | --- | --- |
| 條目一 | 2026-08-14 | `LOG_{hash(2026-08-W2)}` |
| 條目二 | 2026-08-28 | `LOG_{hash(2026-08-W4)}` |
| 條目三 | 2026-09-04 | `LOG_{hash(2026-09-W1)}` |
| 條目四 | 無日期欄位 | 列進待處理清單,不猜週次 |
三筆有日期的條目各自落進對應週頁;第四筆沒有日期,列進一份待處理清單交人工確認,不強行歸入任何一週。同一份舊頁重跑一次拆頁,用條目內容雜湊去重,不會讓已經拆過的四筆再多出一份——重跑後 `LOG_{hash(2026-08-W2)}` 頁裡條目一依然只有一份,不是兩份。
## O-09:六條輸出原則裡哪幾條進得了 lint
**裁決**:六條輸出原則裡,只有「避免書面語」與「問句要放句尾」這兩條寫成 `ste100-lint.sh` 裡的程式化判定;其餘四條要靠語意判斷,不硬塞進 lint。
**出處**:「工作分解結構(WBS)」層2 技能行為表格,工作包名稱「`ste100-lint.sh` 補書面語詞彙與問句位置,加名詞展開寫法檢查」,註記「O-09 定案」;對應 TDD 小節有兩個判定,一個餵「請您進行身分驗證確認之動作」斷言抓得到書面語並建議改寫,另一個餵「請告訴我目的地,以便為您查詢班機」斷言抓得到問句不在句尾。
**例子**:
- 輸入「請您進行身分驗證確認之動作」→ 判定為書面語,建議改寫成「請幫我確認您的身分」
- 輸入「請告訴我目的地,以便為您查詢班機」→ 判定為問句不在句尾,應改成先問句、後補充理由
## A-12:關鍵路徑圖涵蓋所有工作包
**裁決**:「涵蓋所有工作包」是指關鍵路徑圖上要畫出全部工作包,不是把 WBS 拆成每一包都串在同一條鏈上。圖裡只有真正的最長鏈標成關鍵路徑,其餘工作包照自己實際的相依邊掛上去,不為了「全部在一條鏈上」而編造假的先後順序。
**出處**:分析頁「關鍵路徑(CPM)」節開頭:「本圖收進全部 55 個工作包(2026-09-07 裁示:關鍵路徑圖必須涵蓋所有工作包)」,並註明「`crit` 只標最長那一條鏈,其餘照自己的相依邊掛,不串成假的先後順序」。
**例子**:55 個工作包全部畫進甘特圖;只有一條鏈(定案交付包 → 雜湊組法收單一入口 → 一週一頁工作日誌 → 舊日誌拆頁)標成關鍵路徑,其餘工作包各自照自己的相依關係接線,沒有相依的直接從錨點日期起排,不硬接到關鍵路徑上。
可直接比對的斷言:
- 甘特圖節點總數:55(等於分析頁工作包總數,一個都不能少)
- 標 `crit` 的節點數:4(就是上面那條鏈),其餘 51 個工作包不掛 `crit`
- 反例:沒有相依的工作包(例如一個獨立的小型修正包)不會被接在關鍵路徑任何一個節點後面,而是直接從錨點日期起排;如果檢查發現它被接進了那條 4 節點的鏈,就是誤把「涵蓋」做成了「全部串成一條鏈」
## I-07:不監看時的相依判定
**裁決**:implement 階段選擇不監看 PR 時,判斷某個工作包是否「已完成」要同時滿足兩個條件:狀態欄本身寫著「已完成」,而且那個工作包對應的 commit 真的在目前分支的歷史裡(用 `git merge-base --is-ancestor` 判定,狀態欄要多存一個 commit 欄位)。兩個條件都成立才放行,只滿足其中一條不算。
這個判法跟「PR 已合併」不衝突:監看模式下 PR 合併之後,commit 自然會進到分支歷史裡,兩個條件同時成立;不監看模式下沒有實際等 PR 合併,改靠這兩個條件直接對真實的 git 歷史查驗,效果等同,但不必守著輪詢。
**出處**:測試計畫「implement PR 監看二選一」小節第二個 TDD 循環,斷言相依包狀態欄寫「已完成」但其 commit 不在目前分支歷史裡時不放行,兩條都成立才放行;使用者故事驗收計畫「PR 沒人審把階段掛住」失敗流程一列寫明「相依判定改吃『狀態欄加 git 祖先』」。
**例子**:某個工作包的狀態欄寫「已完成」、commit 欄記著一個 40 碼 SHA-1。查驗時執行 `git merge-base --is-ancestor {該commit} HEAD`;結束碼 0 才判定它真的完成,可以讓依賴它的下一包開工;結束碼非 0(commit 不在目前分支歷史)即使狀態欄寫完成也不放行。
反例(另一半條件不成立):狀態欄寫「進行中」,commit 欄記的 commit 其實已經是 HEAD 的祖先(`git merge-base --is-ancestor` 結束碼 0)。這種情況一樣不放行——兩個條件要同時成立,狀態欄沒寫「已完成」,光是 commit 在歷史裡也不夠。
## I-09:同一張 PR 疊多個工作包要不要收斂
**裁決**:不設上限,也不強制收斂。一張 PR 可以疊上任意數量的工作包;每次收尾時要印出目前這張 PR 疊了幾個工作包、累計改了幾行(用 `git diff --shortstat` 取得),讓疊加狀況看得見,但不會因為疊太多就被擋下。
**出處**:「定案規格交付包」工作包的測試計畫小節,列出十項定案的簡表,其中一項寫明「I-09 不設上限」;「implement PR 監看二選一」小節第四個 TDD 循環,斷言每次收尾都印出目前這張 PR 疊了幾包、累計幾行,最小實作是取 `git diff --shortstat` 與領取紀錄。
**例子**:同一張 PR 已經疊了 3 個工作包、累計改了 214 行。收尾時印出「本 PR 目前疊 3 包,累計 +180/-34 行」,然後照常繼續,不會因為已經疊了 3 包就強制先關閉這張 PR。
## 無繼承例子的工作包:`analyze-check.sh` 三合一靜態檢核
**說明**:這份文件收錄的十項技術定案加 F-01 決議,沒有一項對應到「三合一靜態檢核」這個工作包。逐一核對過 N-01、N-02、N-05、N-07、L-03、L-05、O-09、A-12、I-07、I-09、F-01,都不是這個工作包的裁決依據,硬套任何一項的例子都是誤導。
**如實記錄**:這個工作包沒有從十項技術定案加 F-01 決議裡繼承到的例子,動工時要自己另外準備測試資料——具體要涵蓋哪三種靜態檢核、各自的正常輸入與異常輸入長什麼樣子,留給工作包自己在分析頁或動工當下決定,不在這份文件裡代寫。
## F-01:五個未註冊存取庫的去向
盤點 jsc 技能組時,發現五個存取庫檔案完整、能動,但沒登錄進 `plugins/meta` marketplace 正本的 `.claude-plugin/marketplace.json`。這一節記下五個存取庫各自的決議,供 E 表重寫直接引用。
**裁決**:五個存取庫全部不納入正本,各自維持獨立系統。逐一列用途與決議:
| 存取庫 | 一句話用途 | 決議 |
| --- | --- | --- |
| `plugins/code`(jsc-code) | .NET/NuGet 升版、Gitea AI review findings 修復、存取庫批次同步、`TARGET.md` 每日待辦 | 不納入正本,維持獨立系統 |
| `plugins/doc`(jsc-doc) | Gitea 通知分組處理、docker 註解整理、議題分析與同步、工時日誌 | 不納入正本,維持獨立系統 |
| `plugins/persona`(jsc-persona) | AI 人格化記憶聊天,跟 SDLC 技能組完全不相干的獨立系統 | 不納入正本,維持獨立系統 |
| `plugins/shared`(jsc-shared) | 三十多支跨助理共用規格類技能(`spec-*`) | 不納入正本,維持獨立系統 |
| `plugins/code-review`(呼叫前綴 `jsc:`,不是 `jsc-code-review:`) | 以 GitHub Actions 為基礎的 RPG 攻防式 `git diff` review,跟正本裡互動式的 `jsc-review` 是兩套不同東西 | 不納入正本,維持獨立系統 |
**出處**:這一輪盤點(2026-09-07)裡使用者針對「五個未註冊存取庫逐一定去向」這一項待辦的明確答覆——五個全部不納入,不再逐一討論註冊、歸檔或刪除三選一。
**對 E 表的具體影響**:`meta/tools/delegate-spec.tsv` 本身已經是對的——現有 35 列,不含這五個存取庫的任何技能,不必再修。真正還記著這幾支技能、需要訂正的是 `/root/plugins/TODO.md` 第 652~655 行那份 E 表(設計討論用的表格,跟 `delegate-spec.tsv` 是兩份不同的東西)。決議之後,TODO.md 那份 E 表要照下面的方式修正,實際改檔案交給 WP-36(或 TODO.md 自己校正清單裡已經開著的 F-02 項):
- **E-13**(TODO.md 第 652 行,`jsc-doc:notifications`,定期讀 Gitea 通知分組提醒):整條移除。這支技能不會進正本,助理的技能清單裡永遠找不到它。
- **E-14**(TODO.md 第 653 行,`jsc-code:review-resolve`,巡檢 findings 有沒有新的未處理項目):整條移除,理由同上。
- **E-15**(TODO.md 第 654 行,原列 `jsc-pkg:pkg-update`、`jsc-code:nuget`):只留 `jsc-pkg:pkg-update` 那一半,`jsc-code:nuget` 那一半移除。
- **E-16**(TODO.md 第 655 行,原列 `jsc-code:sync`、`jsc-gitea:repo-sync`):只留 `jsc-gitea:repo-sync` 那一半,`jsc-code:sync` 那一半移除。
- **M-20**(TODO.md 第 934 行,`jsc-code:target` 跟助理待辦簿的關係要收攏成一套,還是只巡檢它的系統排程):這個問題本身不成立了。`jsc-code:target` 不在正本裡,助理的技能清單與委派判定清單都碰不到它,不會被觸發,也就沒有「兩份待辦互不知道」的風險。這一項直接關閉,不必再往下決議要收攏還是只巡檢。
`plugins/persona`、`plugins/shared` 沒有被 TODO.md 那份 E 表任何一列引用,純粹是盤點時發現的閒置存取庫,記下「維持獨立、不納入」即可,不需要再對 E 表或委派判定清單做任何修正。
**例子**:`meta/tools/delegate-spec.tsv` 現有 35 列,範圍剛好卡在 `ask` 到 `sdlc`,不含 `code`、`code-review`、`doc`、`persona`、`shared` 五個 domain 的任何一支技能——這份檔案本來就是決議之後該有的樣子,不必動它。要改的是 TODO.md 裡那份 E 表:核對 E-13 到 E-16、M-20 這五列,照上面的方式移除或裁半,不必再往回加東西,也不必幫已刪的那一半補回來。
**不是價值判斷**:五個存取庫都是完整、能動的系統,不納入正本不代表它們沒用或做得不好。`persona` 是另一條產品線,人格化聊天跟 SDLC 開發流程沒有交集;`shared` 是跨助理共用規格技能,服務對象是所有助理而不是單一 SDLC 流程;`code`、`doc`、`code-review` 三個雖然功能上跟 jsc 技能組相近(都碰 Gitea、都碰程式碼),但各自的呼叫方式、維運節奏、目標使用情境都不同,例如 `code-review` 連呼叫前綴都還是舊的 `jsc:`,跟正本裡 `jsc-review` 的互動式流程本來就是兩套設計。維持獨立系統,讓 jsc 技能組正本只收它管得到、巡檢得到的技能,才是對的做法。
## 跟 `wp01-todo-corrections.md` 的分工
這份文件收十項技術定案跟 F-01 決議,都是這一輪盤點裡定下來、可以直接引用的規格內容。
`TODO.md` 的狀態校正另外放在 [`wp01-todo-corrections.md`](wp01-todo-corrections.md),不併進這份文件;不能開 PR 的完整理由見該文件開頭。
+43
View File
@@ -0,0 +1,43 @@
# TODO.md 狀態校正清單
## 為什麼這份不走 PR
`/root/plugins/TODO.md` 不在任何 git 存取庫底下。`/root/plugins` 本身不是 git 存取庫,`.git` 底下只有空的 `info/`。沒有存取庫,就沒有地方可以開分支、送 commit、開 PR。
因此這份校正只能整理成清單,交給使用者參考。實際的檔案修改要靠使用者手動打開 `TODO.md`,對照下面的編號逐行更新。
這份清單分兩節:第一節是十五項狀態校正,第二節是五項數字更新。兩節的來源都是同一輪盤點(2026-09-07,分析頁「核對結果:TODO.md 有 15 項狀態過期」與後面那段五項數字敘述),11 個存取庫各自以 `origin/develop` 為準逐一核對得出。
## 第一節:十五項狀態校正
15 項待辦裡,TODO.md 記的狀態跟實際狀態對不上。其中六項(F-06、W-04、R-04、G-02、G-03、G-07)是「早就做完卻還記著未動工」——照舊表動工會做白工,這六項要優先改。其餘九項是「部分完成」,TODO.md 記著未動工,實際已經做了一部分,剩下的落差寫在證據欄裡。
| 編號 | TODO.md 原記 | 實際狀態 | 證據 |
| --- | --- | --- | --- |
| F-06 | `[ ]` 未動工 | 已完成 | `hooks/comment-scope.sh:91` 已含三種頁型 |
| W-04 | `[ ]` 未動工 | 已完成 | `hooks/templates/error-contents.md:13` 起已是條列 |
| R-04 | `[ ]` 未動工 | 已完成 | `wire-cli.sh:1394-2270`,十類 140 條自我斷言,五支 CLI 各有路徑 |
| G-02 | `[ ]` 未動工 | 已完成 | `issue.sh:81-88` 只列既有標籤,`90-103` 對不到就回 4 |
| G-03 | `[ ]` 未動工 | 已完成 | `issue.sh:202-204` 空集合就不寫進 payload |
| G-07 | `[ ]` 未動工 | 已完成 | `wiki-to-issue/SKILL.md:25` 完成條件已要求回報實際標籤 |
| W-02 | `[ ]` 未動工 | 部分完成 | `wiki-contents.sh:268-293` 的 `format` 子命令已是共用轉檔唯一實作 |
| W-05 | `[ ]` 未動工 | 部分完成 | `wiki-contents.sh:168-174` 取不出鍵就中止(不猜已在),差頁型對照表 |
| W-06 | `[ ]` 未動工 | 部分完成 | `check-contents-format.sh` 已在,但驗的是暫存檔,不是真實頁面 |
| F-04 | `[ ]` 記六種缺庫 | 部分完成 | 站台已有 10 個 `knowledges/` 庫,只缺 LEARN、ERROR、REPORT、TOOLING、MAINTAIN 五種 |
| F-05 | `[ ]` 未動工 | 部分完成 | `gitea.sh:70` 已指名要設哪個變數並回 3。新缺失:那句訊息是英文,還沒改成中文 |
| N-08 | `[ ]` 未動工 | 部分完成 | `migrate-wiki.sh` 已在,且認兩代舊演算法,差第 150 行 `WANT` 沒有「計畫名稱」候選鍵 |
| A-11 | `[ ]` 未動工 | 部分完成 | `analyze/SKILL.md:43` 內文已要求每則待辦寫出驗收依據,缺的只有程式化擋關 |
| R-01 | `[ ]` 未動工 | 部分完成 | 三段抽出一段(`deploy-verify.md`),剩兩段仍逐字重複,其中一段 23 行四份相同(`skill-new/SKILL.md:68-90` 的「結束碼」路由表) |
| F-03 | `[ ]` 記帶過期清單 | 部分完成 | `plugins/jsc` 兩份 marketplace 與正本 `diff` 為空,已於 2026-09-01 手動對齊。「過期」這個說法不成立,但去向仍未定 |
## 第二節:五項數字更新
以下五項是 TODO.md 裡記的數字跟現況對不上,不牽涉狀態欄,只是數字本身要改。
| 項目 | TODO.md 原記 | 實際數字 |
| --- | --- | --- |
| `wire-cli.sh` 總行數 | 2629 行 | 2860 行 |
| `implement/SKILL.md` 總行數 | 113 行 | 162 行 |
| `skill-check` 的 `description` 字元數 | 819 字元 | 1318 字元 |
| `delegate-spec.tsv` 裡 `probe` 欄未接線(`pending`)支數 | 7 支 | 8 支 |
| `jsc-assist` 的 `jsc.requires` 項數 | 4 項 | 5 項 |