Files
sdlc/references/behaviors.md
T
jiantw83 b7b1d8bb01 docs(skills): 四支階段技能的目錄頁讀取與寫入敘述同步條列版面
What
- `skills/plan`、`skills/analyze`、`skills/implement`、`skills/maintain`:目錄頁的讀取敘述改成從 H2 區塊取值,寫入敘述從「單列 upsert」改成單一 H2 區塊 upsert,鍵補上內容頁頁名這個引數,並註明第四個引數是區塊檔。
- `skills/maintain`:讀寫的鍵改成該存取庫的 `{owner}/{repo}`,因為這個型別沒有內容頁。
- `references/behaviors.md`:四支技能的關鍵步驟、外部呼叫與可驗證跡象同步,跡象從「留下那一列」改成留下那一個 H2 區塊。
- `references/consensus.md`:查已答問題那一條補上問答目錄頁也是條列式版面、要從區塊取值而不是表格列。
- `references/stage-report.md`:目錄頁也算寫入那一段補上「改動一個區塊也算寫過那一頁」,並統一用 `CONTENTS` 這個型別餵進去。
- `README.md`:四支技能的流程敘述與 wiki 規則段同步,並補上五個目錄頁的版面規則、鍵的落點與各頁鍵欄的正確序號。

Why
- 範本已經改成條列版面,技能內文還寫著「那一列」,執行時就會照舊敘述組出表格列,跟工具的單一區塊 upsert 對不上。
- 讀取端的敘述沒跟著改,技能會拿表格的解析方式去讀一頁條列,既有紀錄一筆都認不出來。
- 呼叫少帶鍵這個引數,工具無從判斷要換掉哪一個區塊,同一筆會被當成新的附加上去。
- 行為清單是稽核與驗證的比對基準,敘述沒跟上,稽核會拿舊描述判合規。

How
- 四支技能的呼叫一律寫成 `wiki-contents.sh upsert {TYPE} {鍵欄} "{鍵}" {區塊檔} [{範本}]`,各頁的鍵欄序號照線上那一頁實際的欄位排法寫定。
- 完成條件與可驗證跡象改用區塊的說法,連結範例改成 `- {欄位名}:[{頁名}]({連結})` 的形態。
- 只改敘述與說明,不動任何腳本;轉檔與 upsert 的實作在別的存取庫。

Who
- 本存取庫四支階段技能,以及讀這幾份說明檔決定共識判定與階段回報寫法的流程。
- 稽核與驗證流程改拿新的行為清單比對。
2026-09-02 17:21:10 +08:00

44 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# jsc-sdlc 技能行為清單
本頁記錄 jsc-sdlc 每支技能的行為基準,供技能驗證比對。技能異動時,在同一個 PR 內一起更新這一頁。
## analyze
| 項目 | 內容 |
| --- | --- |
| 觸發時機 | 計畫已經寫進 `PLAN_CONTENTS`(CONTENTS 存取庫)、該計畫 `## PLAN_{HASH}` 區塊的「狀態」是「未分析」,要把它拆成工作包時用。也用於延伸既有的 `ANALYZE_{HASH}` 分析頁。要寫程式碼時不用,那是 `implement`。`PLAN_CONTENTS` 還沒有計畫時不用,先跑 `plan`。 |
| 關鍵步驟 | 跑 `model-tags.sh sync` 與 `sdlc-gate.sh lock analyze` 過模型閘門,本階段要 `reasoning-max` 標籤、用 `gitea.sh wiki-repo CONTENTS` 解出目錄頁存取庫,並行讀 `PLAN_CONTENTS` 與 `ANALYZE_CONTENTS`,兩頁都是條列式版面:一個 H2 區塊一筆,標題就是對應的內容頁頁名,欄位是標題底下的一層條列,狀態看 `- 狀態:` 那一條,不是讀表格的列、讓使用者選延伸既有分析或分析新計畫,選項一個 H2 區塊組一個,標題給頁名與 HASH、說明文字取自該區塊的欄位條列、跑 `git fetch --prune origin` 後確認來源分支,並核對 HEAD 與 `origin/{source-branch}` 指到同一個 commit,有落差就停下回報、逐則使用者故事問到共識、先查 `REPO_{HASH}` 盤點頁(雜湊取自該存取庫自己的 `{owner}/{repo}`)決定複用,資料過期就開 sub agent 重新盤點,把 `REPO_{HASH}` 寫回 REPO 存取庫、`REPO_CONTENTS` 用 `wiki-contents.sh upsert REPO 2 {盤點頁實際頁名}` 寫回那一個 H2 區塊、做 WBS 拆工作包並標相依,交付工作包固定編為 `WP-01` 且獨立不併入實作包、用 CPM 估工時與天數,標出要徑並依 `references/cpm-chart.md` 畫 mermaid 甘特圖、寫使用者故事驗收計畫,再逐包寫 TDD 待辦、一次寫入 `ANALYZE_{HASH}`(ANALYZE 存取庫),再用 `wiki-contents.sh upsert ANALYZE 2 {分析頁實際頁名}` 與 `wiki-contents.sh upsert PLAN 2 {計畫頁實際頁名}` 各自單一 H2 區塊 upsert,第三個參數是 H2 標題,填這一筆對應內容頁的實際頁名,也就是技能自己剛寫的那一頁的頁名(線上長成 `ANALYZE_20260821_100552_104F0709` 這樣),不套 `{TYPE}_{HASH}` 的公式,`2` 與 `2` 分別是舊表格「分析頁」欄與「計畫頁」欄的序號,也就是持有內容頁連結那一欄,只供自動轉檔用(該頁還是表格時從那一欄的連結網址取最後一段路徑當標題,已是條列就忽略),填錯會讓標題跟鍵對不上、同一筆變兩個區塊、舊區塊再也更新不到,第四個參數是整個區塊的檔案不是列檔、目錄區塊的分析頁與盤點頁連結一律取自 `gitea.sh wiki-url` 的絕對網址,並依退出碼分流(`0` 用它印出的網址,`4` 回頭補寫那頁再回來,`5`、`7`、`8` 停下回報,一律不自行組網址、也不留空白連結)、每個要放進頁面或目錄區塊的連結一律寫成 `[{文字}]({連結})`,不用 `[[頁名]]` 或 `[[顯示文字|頁名]]`,而且寫入前先整批交給 `jsc-gitea/tools/link-check.sh`,結束碼 0 才寫,有 DEAD 就整筆不寫並回報連不到的清單(`2` 補參數重跑、`3` 先設好 `GITEA_HOST`、`7` 金鑰失效停下回報,不得當成連不到)、目錄區塊檔與待寫日誌檔一律用 Bash 的 heredoc 或 `mktemp` 產在暫存目錄,不走 Write 或 Edit 工具,因為 `write-guard.sh` 的 stage 模式只看階段鎖不看路徑,走工具會被自己的閘門擋下、跑 `tools/stage-report.sh analyze` 收尾回報,目錄頁一律用 `--page CONTENTS:{頁名}`、階段回報之後緊接著跑 `jsc-hooks/tools/report-status.sh skill-end jsc-sdlc:analyze {status} {結束碼} [detail]` 寫一筆結束事件,模型閘門擋下或 HEAD 與 `origin/{source-branch}` 有落差填 `blocked`,分析頁寫成功但目錄區塊沒跟上填 `degraded`,找不到腳本就安靜跳過,這一步失敗不改變本次階段的結論。 |
| 外部呼叫 | `jsc-cli/tools/model-tags.sh sync`、`jsc-hooks/hooks/sdlc-gate.sh lock`、`jsc-hooks/hooks/write-guard.sh`(claude 的 `PreToolUse` 擋寫入)、`jsc-gitea:wiki`、`jsc-gitea/tools/hash-id`、`jsc-gitea/tools/gitea.sh` 的 `wiki-repo` 與 `wiki-url`、`jsc-gitea/tools/wiki-contents.sh upsert`、`jsc-gitea/tools/link-check.sh`、`jsc-ask:ask`、`tools/stage-report.sh`、`jsc-hooks/tools/report-status.sh skill-end`、`git fetch --prune origin`、`git branch -r`、`git rev-list --left-right --count`。 |
| 完成條件 | 模型閘門退出 0 並回報實際模型 id、來源分支經使用者確認且與遠端一致、每則使用者故事達成共識、每個複用決策連理由記進「複用決策」欄、每則故事對應至少一個編號工作包、每包有工時與天數、要徑與甘特圖齊備、每個實作包至少一則測試先行的 `[ ]` 待辦、`ANALYZE_{HASH}` 存進 wiki 且未決項欄有值(沒有就寫「無」)、每個目錄區塊的頁面連結都來自退出 0 的 `wiki-url`,非 0 依 `4`、`5`、`7`、`8` 分流並講出退出碼、每一頁與每一個區塊寫出去之前都經 `link-check.sh` 退出 0 驗過,連結格式一律是 `[{文字}]({連結})`、每次目錄頁寫入都講出 `wiki-contents.sh` 的退出碼並依碼分流(`0` 續行,`1`、`3`、`7`、`8` 停下回報,`2` 修參數重跑,`4` 在本技能一律帶範本的呼叫方式下不會出現,真的出現就確認 plugin 安裝完整後重跑)、`stage-report.sh` 的輸出原樣貼給使用者、已寫一筆 `skill-end` 事件,狀態照 SKILL.md 收尾步驟那張對應表選定。提前停下也要跑收尾回報,結束事件一樣要寫;只有找不到 `report-status.sh` 才准沒有這一筆。 |
| 可驗證跡象 | ANALYZE 存取庫多一頁或更新一頁 `ANALYZE_{HASH}`;CONTENTS 存取庫的 `ANALYZE_CONTENTS` 多一個 `## ANALYZE_{HASH}` 區塊,欄位逐條列出、連結是絕對網址;`PLAN_CONTENTS` 該計畫 `## PLAN_{HASH}` 區塊的「狀態」那一條變成「已分析」;重新盤點時 REPO 存取庫多一頁 `REPO_{HASH}`,`REPO_CONTENTS` 多一個 `## REPO_{HASH}` 區塊;`$JSC_HOME/sessions/{工作階段 id}.stage` 是 `sdlc-gate.sh lock` 寫的階段鎖狀態檔;還沒有工作日誌時,`$JSC_HOME/worklog-pending/{HASH}/` 下有暫存的日誌內容檔;`stage-report.sh` 的「寫入的 wiki 頁」表格多一欄連結驗證,逐列標「通過、無可查端點、連不到、未驗證」,頁面上找不到 `[[...]]` 寫法的連結;`$JSC_HOME/usage/events.jsonl` 多一筆 `{kind:skill,phase:end}` 的事件,`name` 是 `jsc-sdlc:analyze`,`status` 是五個值之一。工作目錄的檔案一律不動,程式碼沒有任何改動。 |
## implement
| 項目 | 內容 |
| --- | --- |
| 觸發時機 | 分析頁已經有工作包與 TDD 待辦,要動手寫程式碼時用。也用於回頭處理既有工作包 PR 的留言。規劃或分析階段不用。`ANALYZE_CONTENTS` 上沒有任何狀態是「未完成」的 `## ANALYZE_{HASH}` 區塊時不用。 |
| 關鍵步驟 | 跑 `model-tags.sh sync` 與 `sdlc-gate.sh lock implement` 過模型閘門,本階段要 `coding` 標籤、從 CONTENTS 存取庫讀 `ANALYZE_CONTENTS`,它是條列式版面:一個 H2 區塊一份分析,標題就是該筆分析頁的實際頁名(線上長成 `ANALYZE_20260821_100552_104F0709` 這樣,不是 `{TYPE}_{HASH}` 的公式),狀態看 `- 狀態:` 那一條,不是讀表格的列、再從 ANALYZE 存取庫讀每一頁未完成分析頁,WBS 表、PR 欄與待辦都在那張內容頁上、這份資料後續步驟重用不再讀第二次、對每支未合併 PR 並行跑 `wp-gate.sh check` 取狀態與留言、動任何 PR 之前先跑 `wp-gate.sh owns` 確認歸屬,`foreign` 就放手、每則留言先經 `jsc-ask:ask` 取得共識,再由 sub agent 在同一個 worktree 內修、推同一條工作分支、逐則留言用 `gitea.sh comment-reply` 回覆處置結果,把 `latest=` 時間寫回分析頁 PR 欄、一輪留言修正算一個任務,當下寫一筆 `jsc-log:worklog`、列出可挑的工作包,每個候選並行跑 `wp-gate.sh check-deps` 過相依閘門,只有 `ready` 進選項、使用者挑定後跑 `wp-gate.sh claim` 登錄歸屬、確認來源分支,它同時是 worktree 基準與 PR 目標,遠端找不到就停下回報、產生 `TICKET_{yyyyMMdd}_{HHmmss}_{HASH}` 工作證並寫回分析頁「工作證」欄,同時改工作階段名稱、交付包先問交付內容型別並寫回「交付型別」欄、`git fetch --prune origin` 後從 `origin/{source-branch}` 建 worktree,多存取庫並行建、逐項待辦各開一個 sub agent 跑 TDD,主代理每完成一項就把 `[ ]` 翻成 `[x]` 並存回 wiki、收尾並行跑 `jsc-review:code-review` 與 `jsc-review:api-doc`,後者先用 `swagger-detect.sh` 判定,退出碼 1 就明確略過並回報、跑 `jsc-git:pr` 開 PR 回來源分支,把 PR 連結寫回分析頁,再跑 `wp-gate.sh lock` 上鎖、寫一筆工作日誌,接著用 `pr-watch.sh` 輪詢等合併,退出碼 10 就回頭跑同一套留言處理、合併後移除 worktree 並把工作包標為完成、問交付格式並產出 `DELIVER_{HASH}` wiki 頁(寫進 DELIVER 存取庫,雜湊取自 `{owner}/{repo}` 加工作包編號,一包一頁不互相覆蓋)或 Gitea issue 留言,交付頁再用 `wiki-contents.sh upsert DELIVER 5 {交付頁實際頁名}` 把 `DELIVER_CONTENTS` 那一個 H2 區塊寫回,第三個參數是 H2 標題,填這一筆對應內容頁的實際頁名,也就是技能自己剛寫的那一頁的頁名,不套 `{TYPE}_{HASH}` 的公式,`5` 是舊表格「交付頁」欄的序號,也就是持有內容頁連結那一欄,只供自動轉檔用(該頁還是表格時從那一欄的連結網址取最後一段路徑當標題,已是條列就忽略),填錯會讓標題跟鍵對不上、同一筆變兩個區塊、舊區塊再也更新不到,第四個參數是整個區塊的檔案不是列檔,連結取自 `gitea.sh wiki-url` 的絕對網址並依退出碼分流(`0` 用它印出的網址,`4` 回頭補寫交付頁再回來,`5`、`7`、`8` 停下回報,一律不自行組網址、也不留空白連結)、每個要放進頁面、目錄區塊、PR 欄或 issue 留言的連結一律寫成 `[{文字}]({連結})`,不用 `[[頁名]]` 或 `[[顯示文字|頁名]]`,而且寫入前先整批交給 `jsc-gitea/tools/link-check.sh`,結束碼 0 才寫,有 DEAD 就整筆不寫並回報連不到的清單(`2` 補參數重跑、`3` 先設好 `GITEA_HOST`、`7` 金鑰失效停下回報,不得當成連不到)、問要不要登錄維護並用 `wiki-contents.sh upsert MAINTAIN 1 {owner}/{repo}` 寫回 `MAINTAIN_CONTENTS` 那一個 H2 區塊,`MAINTAIN` 沒有內容頁,所以標題就是該存取庫的 `{owner}/{repo}`,不得硬造 `MAINTAIN_{HASH}` 指向一個不存在的頁,`1` 是舊表格「存取庫」欄的序號,也就是持有這一筆身分那一欄(該欄沒有連結,轉檔取純文字),只供自動轉檔用,填錯會讓標題跟鍵對不上、同一筆變兩個區塊、舊區塊再也更新不到、跑 `tools/stage-report.sh implement` 收尾回報,目錄頁一律用 `--page CONTENTS:{頁名}`、階段回報之後緊接著跑 `jsc-hooks/tools/report-status.sh skill-end jsc-sdlc:implement {status} {結束碼} [detail]` 寫一筆結束事件,模型閘門擋下、候選全被 `check-deps` 判 `blocked`、`owns` 判 `foreign` 或來源分支在遠端找不到都填 `blocked`,工作包已合併但交付目錄區塊或維護登錄沒寫成填 `degraded`,找不到腳本就安靜跳過,這一步失敗不改變本次階段的結論。 |
| 外部呼叫 | `jsc-cli/tools/model-tags.sh sync`、`jsc-hooks/hooks/sdlc-gate.sh lock`、`tools/wp-gate.sh` 的 `check`、`check-deps`、`claim`、`lock`、`owns`、`tools/stage-report.sh`、`jsc-gitea:wiki`、`jsc-gitea/tools/hash-id`、`jsc-gitea/tools/gitea.sh`(`wiki-repo`、`wiki-url`、`comment-reply` 與 issue 留言 API)、`jsc-gitea/tools/wiki-contents.sh upsert`、`jsc-gitea/tools/link-check.sh`、`jsc-gitea/tools/pr-watch.sh`、`jsc-ask:ask`、`jsc-review:code-review`、`jsc-review:api-doc`、`jsc-review/tools/swagger-detect.sh`、`jsc-hooks/hooks/comment-scope.sh`、`jsc-git:commit`、`jsc-git:pr`、`jsc-log:worklog`、`jsc-hooks/tools/report-status.sh skill-end`、`git fetch`、`git worktree`。 |
| 完成條件 | 模型閘門退出 0、每支未合併 PR 的留言都有處置與回覆、挑中的工作包經 `check-deps` 判為 `ready` 並 `claim` 成功、來源分支經確認並記進分析頁、工作證寫上 wiki、該包每一項待辦在 wiki 上都是 `[x]`、兩個收尾稽核都放行(`api-doc` 回報略過也算放行)、PR 開好且 `wp-gate.sh lock` 回 `status=locked`、工作日誌已寫、`pr-watch.sh` 退出 0 且 `wp-gate.sh check` 回 `status=merged`、交付文件已產出、交付頁那一條的連結來自退出 0 的 `wiki-url`,非 0 依 `4`、`5`、`7`、`8` 分流並講出退出碼、每一頁、每一個目錄區塊與每一則 issue 留言寫出去之前都經 `link-check.sh` 退出 0 驗過,連結格式一律是 `[{文字}]({連結})`、維護登錄問題已回答、每次目錄頁寫入都講出 `wiki-contents.sh` 的退出碼並依碼分流(`0` 續行,`1`、`3`、`7`、`8` 停下回報,`2` 修參數重跑,`4` 在本技能一律帶範本的呼叫方式下不會出現,真的出現就確認 plugin 安裝完整後重跑)、`stage-report.sh` 的輸出原樣貼出並列出 worktree 與三條分支、已寫一筆 `skill-end` 事件,狀態照 SKILL.md 收尾步驟那張對應表選定。提前停下也要跑收尾回報,結束事件一樣要寫;只有找不到 `report-status.sh` 才准沒有這一筆。 |
| 可驗證跡象 | 開出一條工作分支,並有一支回到來源分支的 PR;ANALYZE 存取庫的分析頁 `ANALYZE_{HASH}` 的「工作證」欄(值是 `TICKET_{yyyyMMdd}_{HHmmss}_{HASH}`,帶著 `hash-id` 原樣印出的雜湊)、「交付型別」欄、PR 欄、待辦勾選狀態都更新過;DELIVER 存取庫多一頁 `DELIVER_{HASH}`,或該 issue 下多一則留言;CONTENTS 存取庫的 `DELIVER_CONTENTS` 多一個 `## DELIVER_{HASH}` 區塊,欄位逐條列出、連結是絕對網址;使用者同意登錄時 `MAINTAIN_CONTENTS` 多一個 `## {owner}/{repo}` 區塊;`LOG_{HASH}` 每完成一個任務多一筆條目;`$JSC_HOME/wp/{owner}-{repo}.claim` 與 `$JSC_HOME/wp/{owner}-{repo}-{index}.pr` 兩個狀態檔;`{cwd}/.worktree/{分析-HASH}/{工作包編號}/{repo}` 目錄,PR 合併後被移除;該存取庫 `.git/info/exclude` 多一筆 `.worktree/`;PR 每則留言底下有回覆;`stage-report.sh` 的「寫入的 wiki 頁」表格多一欄連結驗證,逐列標「通過、無可查端點、連不到、未驗證」,寫出去的頁面與留言都找不到 `[[...]]` 寫法的連結;`$JSC_HOME/usage/events.jsonl` 多一筆 `{kind:skill,phase:end}` 的事件,`name` 是 `jsc-sdlc:implement`,`status` 是五個值之一。 |
## maintain
| 項目 | 內容 |
| --- | --- |
| 觸發時機 | 已交付、且在 `MAINTAIN_CONTENTS`(CONTENTS 存取庫)已有一個 `## {owner}/{repo}` 區塊的專案要做定期保養時用。還在實作中的專案不用。沒有登錄進 `MAINTAIN_CONTENTS` 的專案不用。 |
| 關鍵步驟 | 跑 `model-tags.sh sync` 與 `sdlc-gate.sh lock maintain` 過模型閘門,本階段不要求特定標籤,只要判定得出實際模型 id、用 `gitea.sh wiki-repo CONTENTS` 解出存取庫後讀 `MAINTAIN_CONTENTS`(`MAINTAIN` 只有目錄頁、沒有內容頁),它是條列式版面:一個 `## {owner}/{repo}` 區塊一個專案,`MAINTAIN` 沒有內容頁,標題就是該存取庫的 `{owner}/{repo}`,存取庫與起始日、截止日都讀標題底下的欄位條列,不是讀表格的列、篩出還在維護期內的專案(起始日不晚於今天,結束日為空或不早於今天)、主代理先並行對每個專案跑 `git fetch --prune origin`,切到維護分支並與 `origin/{branch}` 對齊,有落差就回報並略過該專案、之後一個專案一個專案跑,每個專案的維護都開一個 sub agent、每個專案提出至少五項維護做法給使用者挑、把改動用 `jsc-git:commit` 提交到新分支,推送後用 `jsc-git:pr` 開 PR 回步驟 3.1 那條分支、PR 開好當下寫一筆 `jsc-log:worklog`、用 `wiki-contents.sh upsert MAINTAIN 1 {owner}/{repo}` 把該專案在 `MAINTAIN_CONTENTS` 那個 H2 區塊的「前次維護時間」那一條更新成今天,標題與其餘欄位條列原樣保留,第三個參數的標題就是該專案的 `{owner}/{repo}`,取自讀進來的那個區塊,不得代換成 `MAINTAIN_{HASH}`,`1` 是舊表格「存取庫」欄的序號,也就是持有這一筆身分那一欄(該欄沒有連結,轉檔取純文字),只供自動轉檔用,填錯會讓標題跟鍵對不上、同一筆變兩個區塊、舊區塊再也更新不到,第四個參數是整個區塊的檔案不是列檔、該頁指向別型別頁的連結一律取自 `gitea.sh wiki-url` 的絕對網址並依退出碼分流(`0` 用它印出的網址,`4` 填「無」或回頭補寫那頁,`5`、`7`、`8` 停下回報,`7` 絕不當成 `4` 填「無」,一律不自行組網址、也不留空白連結)、每個要放進該區塊的連結一律寫成 `[{文字}]({連結})`,不用 `[[頁名]]` 或 `[[顯示文字|頁名]]`,而且寫入前先整批交給 `jsc-gitea/tools/link-check.sh`,結束碼 0 才寫,有 DEAD 就整個區塊不寫並回報連不到的清單(`2` 補參數重跑、`3` 先設好 `GITEA_HOST`、`7` 金鑰失效停下回報,不得當成連不到)、主代理彙整每個專案的做法、PR 表格列與失敗原因、跑 `tools/stage-report.sh maintain` 收尾回報,目錄頁用 `--page CONTENTS:MAINTAIN_CONTENTS`、階段回報之後緊接著跑 `jsc-hooks/tools/report-status.sh skill-end jsc-sdlc:maintain {status} {結束碼} [detail]` 寫一筆結束事件,模型閘門擋下或在期專案全部與遠端有落差而整批略過填 `blocked`,一部分專案交出 PR、另一部分略過或「前次維護時間」沒更新成填 `degraded`,找不到腳本就安靜跳過,這一步失敗不改變本次階段的結論。 |
| 外部呼叫 | `jsc-cli/tools/model-tags.sh sync`、`jsc-hooks/hooks/sdlc-gate.sh lock`、`jsc-gitea:wiki`、`jsc-gitea/tools/gitea.sh` 的 `wiki-repo` 與 `wiki-url`、`jsc-gitea/tools/wiki-contents.sh upsert`、`jsc-gitea/tools/link-check.sh`、`jsc-ask:ask`、`jsc-git:commit`、`jsc-git:pr`、`jsc-log:worklog`、`jsc-pkg:pkg-update`(選了套件更新才用)、`jsc-hooks/hooks/comment-scope.sh`、`tools/stage-report.sh`、`jsc-hooks/tools/report-status.sh skill-end`、`git fetch --prune origin`。 |
| 完成條件 | 模型閘門退出 0、步驟 2 列出的每個在期專案都跑完自己的 sub agent,各自收在一條 PR 連結或一個記錄下來的略過原因、每個完成的專案都有一筆工作日誌,而且下一個專案開始前就存好、`wiki-contents.sh` 退出 0 且退出碼有講出來(`1`、`3`、`7`、`8` 停下回報,`2` 修參數重跑,`4` 在本技能一律帶範本的呼叫方式下不會出現,真的出現就確認 plugin 安裝完整後重跑)、每個跨型別連結都來自退出 0 的 `wiki-url`,非 0 依 `4`、`5`、`7`、`8` 分流並講出退出碼、每一個區塊寫回去之前都經 `link-check.sh` 退出 0 驗過,連結格式一律是 `[{文字}]({連結})`、`MAINTAIN_CONTENTS` 該專案的「前次維護時間」是今天,其他專案那幾個區塊一個位元組都沒變、彙整報告涵蓋每個專案、`stage-report.sh` 的輸出原樣貼給使用者、已寫一筆 `skill-end` 事件,狀態照 SKILL.md 收尾步驟那張對應表選定。沒有專案在期時,一樣要跑收尾回報並寫結束事件,狀態填 `aborted`;只有找不到 `report-status.sh` 才准沒有這一筆。 |
| 可驗證跡象 | 每個維護過的專案多一條新分支與一支回到 `develop` 或 `master` 的 PR;CONTENTS 存取庫的 `MAINTAIN_CONTENTS` 對應那個 `## {owner}/{repo}` 區塊的「前次維護時間」那一條變成今天;`LOG_{HASH}` 每個完成的專案多一筆條目;`$JSC_HOME/sessions/{工作階段 id}.stage` 是 `sdlc-gate.sh lock` 寫的階段鎖狀態檔;一個專案都沒完成時,`$JSC_HOME/worklog-pending/{HASH}/` 下有暫存的日誌內容檔;`stage-report.sh` 的「寫入的 wiki 頁」表格多一欄連結驗證,逐列標「通過、無可查端點、連不到、未驗證」,該頁找不到 `[[...]]` 寫法的連結;`$JSC_HOME/usage/events.jsonl` 多一筆 `{kind:skill,phase:end}` 的事件,`name` 是 `jsc-sdlc:maintain`,`status` 是五個值之一。 |
## plan
| 項目 | 內容 |
| --- | --- |
| 觸發時機 | 使用者要開新計畫、或要補強既有計畫時用。做分析或寫程式碼時不用。 |
| 關鍵步驟 | 跑 `model-tags.sh sync` 與 `sdlc-gate.sh lock plan` 過模型閘門,本階段要 `reasoning-max` 標籤、用 `gitea.sh wiki-repo CONTENTS` 解出存取庫後讀 `PLAN_CONTENTS`,它是條列式版面:一個 H2 區塊一份計畫,標題就是該筆計畫頁的實際頁名(不是 `{TYPE}_{HASH}` 的公式),狀態看 `- 狀態:` 那一條,不是讀表格的列,列出狀態為「未分析」的計畫與各自的 HASH、讓使用者選延伸既有計畫或建立新計畫,選項一個 H2 區塊組一個,標題給頁名與 HASH、說明文字取自該區塊的欄位條列、依 `references/consensus.md` 跑決策樹,把目標、範圍、可行性三項問到共識,每個答案都要導出下一個問題、把共識寫成「身為⋯⋯我想要⋯⋯以便⋯⋯」格式的使用者故事、套 `templates/plan-page.md` 寫入 `PLAN_{HASH}`(PLAN 存取庫)、用 `wiki-contents.sh upsert PLAN 2 {計畫頁實際頁名}` 把這份計畫在 `PLAN_CONTENTS` 的那一個 H2 區塊 upsert,狀態那一條填「未分析」,第三個參數是 H2 標題,填這一筆對應內容頁的實際頁名,也就是技能自己剛寫的那一頁的頁名,不套 `{TYPE}_{HASH}` 的公式,`2` 是舊表格「計畫頁」欄的序號,也就是持有內容頁連結那一欄,只供自動轉檔用(該頁還是表格時從那一欄的連結網址取最後一段路徑當標題,已是條列就忽略),填錯會讓標題跟鍵對不上、同一筆變兩個區塊、舊區塊再也更新不到,第四個參數是整個區塊的檔案不是列檔、計畫頁連結取自 `gitea.sh wiki-url` 的絕對網址並依退出碼分流(`0` 用它印出的網址,`4` 回頭補寫計畫頁再回來,`5`、`7`、`8` 停下回報,一律不自行組網址、也不留空白連結)、每個要放進頁面或目錄區塊的連結一律寫成 `[{文字}]({連結})`,不用 `[[頁名]]` 或 `[[顯示文字|頁名]]`,而且寫入前先整批交給 `jsc-gitea/tools/link-check.sh`,結束碼 0 才寫,有 DEAD 就整筆不寫並回報連不到的清單(`2` 補參數重跑、`3` 先設好 `GITEA_HOST`、`7` 金鑰失效停下回報,不得當成連不到)、目錄區塊檔與待寫日誌檔一律用 Bash 的 heredoc 或 `mktemp` 產在暫存目錄,不走 Write 或 Edit 工具,因為 `write-guard.sh` 的 stage 模式只看階段鎖不看路徑,走工具會被自己的閘門擋下、跑 `tools/stage-report.sh plan` 收尾回報,目錄頁用 `--page CONTENTS:PLAN_CONTENTS`、階段回報之後緊接著跑 `jsc-hooks/tools/report-status.sh skill-end jsc-sdlc:plan {status} {結束碼} [detail]` 寫一筆結束事件,模型閘門擋下填 `blocked`,計畫頁寫成功但 `PLAN_CONTENTS` 那個區塊沒跟上填 `degraded`,找不到腳本就安靜跳過,這一步失敗不改變本次階段的結論。 |
| 外部呼叫 | `jsc-cli/tools/model-tags.sh sync`、`jsc-hooks/hooks/sdlc-gate.sh lock`、`jsc-hooks/hooks/write-guard.sh`(claude 的 `PreToolUse` 擋寫入)、`jsc-gitea:wiki`、`jsc-gitea/tools/hash-id`、`jsc-gitea/tools/gitea.sh` 的 `wiki-repo` 與 `wiki-url`、`jsc-gitea/tools/wiki-contents.sh upsert`、`jsc-gitea/tools/link-check.sh`、`jsc-ask:ask`、`tools/stage-report.sh`、`jsc-hooks/tools/report-status.sh skill-end`。 |
| 完成條件 | 模型閘門退出 0 並回報實際模型 id、目標、範圍、可行性三項都達成共識,而且使用者明確確認過覆述的摘要、每個共識項目至少對應一則使用者故事、`PLAN_{HASH}` 存進 wiki 且範本要求的每個區段都有值、沒有留下未填的佔位字、`PLAN_CONTENTS` 該區塊的狀態那一條是「未分析」,計畫頁那一條的連結來自退出 0 的 `wiki-url`(非 0 依 `4`、`5`、`7`、`8` 分流並講出退出碼),並經 `link-check.sh` 退出 0 驗過,格式是 `[{文字}]({連結})`,其他區塊一個位元組都沒變,而且 `wiki-contents.sh` 的退出碼有講出來並依碼分流(`0` 續行,`1`、`3`、`7`、`8` 停下回報,`2` 修參數重跑,`4` 在本技能一律帶範本的呼叫方式下不會出現,真的出現就確認 plugin 安裝完整後重跑)、`stage-report.sh` 的輸出原樣貼給使用者、已寫一筆 `skill-end` 事件,狀態照 SKILL.md 收尾步驟那張對應表選定。提前停下也要跑收尾回報,結束事件一樣要寫;只有找不到 `report-status.sh` 才准沒有這一筆。 |
| 可驗證跡象 | PLAN 存取庫多一頁或更新一頁 `PLAN_{HASH}`;CONTENTS 存取庫的 `PLAN_CONTENTS` 多一個或更新一個 `## PLAN_{HASH}` 區塊,狀態那一條是「未分析」、計畫頁那一條是 `[{文字}]({連結})` 格式的絕對網址;`$JSC_HOME/sessions/{工作階段 id}.stage` 是 `sdlc-gate.sh lock` 寫的階段鎖狀態檔;還沒有工作日誌時,`$JSC_HOME/worklog-pending/{HASH}/` 下有暫存的日誌內容檔;`stage-report.sh` 的「寫入的 wiki 頁」表格多一欄連結驗證,逐列標「通過、無可查端點、連不到、未驗證」,頁面上找不到 `[[...]]` 寫法的連結;`$JSC_HOME/usage/events.jsonl` 多一筆 `{kind:skill,phase:end}` 的事件,`name` 是 `jsc-sdlc:plan`,`status` 是五個值之一。工作目錄的檔案一律不動。 |