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
- 本存取庫四支階段技能,以及讀這幾份說明檔決定共識判定與階段回報寫法的流程。
- 稽核與驗證流程改拿新的行為清單比對。
86 lines
21 KiB
Markdown
86 lines
21 KiB
Markdown
# jsc-sdlc — 開發生命週期
|
||
|
||
jsc 技能組的 sdlc domain:規劃 → 分析 → 實作 → 維護四個階段,全程以 wiki 頁追蹤(`PLAN_CONTENTS`、`PLAN_{HASH}`、`ANALYZE_CONTENTS`、`ANALYZE_{HASH}`、`REPO_CONTENTS`、`REPO_{HASH}`、`DELIVER_CONTENTS`、`DELIVER_{HASH}`、`MAINTAIN_CONTENTS`)。**五個 `*_CONTENTS` 目錄頁住在 `JSC_WIKI_REPO_CONTENTS` 解出的專用存取庫,內容頁各走自己的頁型變數,兩者不同存取庫**(詳見「環境變數」)。工作包完成即交付:實作階段會詢問交付文件要產生成 `DELIVER_{HASH}` wiki 頁或 Gitea 議題留言。hook 或流程失敗記在異常頁(`ERROR_CONTENTS`、`ERROR_{HASH}`),那組頁面與範本由 `jsc-hooks` 擁有,本 domain 不放副本。每次切換階段先過模型閘門,判定全在程式層,由 `jsc-hooks/hooks/sdlc-gate.sh lock {stage}` 執行;各階段必要標籤、阻擋與回報的鐵則見 `references/model-gate.md`。分析前先與使用者確認來源分支;實作沿用同一條來源分支作為 worktree 基準與 PR 目標。**所有參考與來源分支一律取遠端的 `origin/{branch}`,動作前先 `git fetch --prune origin`;本地分支不可作為基準,本地與遠端不一致就停下回報。**
|
||
|
||
## 安裝、更新、移除
|
||
|
||
Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安裝 token 為 `jsc-sdlc@jsc`。每個指令一行:
|
||
|
||
| CLI | 安裝 | 更新 | 移除 |
|
||
| --- | --- | --- | --- |
|
||
| claude | `claude plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && claude plugin install jsc-sdlc@jsc` | `claude plugin marketplace update jsc && claude plugin update jsc-sdlc@jsc` | `claude plugin uninstall jsc-sdlc@jsc` |
|
||
| codex | `codex plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && codex plugin add jsc-sdlc@jsc` | `codex plugin marketplace upgrade jsc` | `codex plugin remove jsc-sdlc@jsc` |
|
||
| copilot | `copilot plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && copilot plugin install jsc-sdlc@jsc` | `copilot plugin marketplace update jsc && copilot plugin update jsc-sdlc@jsc` | `copilot plugin uninstall jsc-sdlc@jsc` |
|
||
| antigravity | `git clone https://gitea.jsc.idv.tw/plugins/sdlc.git ~/plugins/sdlc && agy plugin install ~/plugins/sdlc` | `git -C ~/plugins/sdlc pull && agy plugin uninstall jsc-sdlc && agy plugin install ~/plugins/sdlc` | `agy plugin uninstall jsc-sdlc` |
|
||
| kiro | `kiro-cli plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && kiro-cli plugin install jsc-sdlc@jsc` | `kiro-cli plugin marketplace update jsc && kiro-cli plugin update jsc-sdlc@jsc` | `kiro-cli plugin uninstall jsc-sdlc@jsc` |
|
||
|
||
> antigravity 不支援 gitea URL 安裝,改用本地 clone 路徑。批次操作五個 CLI:使用 `/jsc-cli:deploy`。
|
||
|
||
> 舊入口 `plugins/jsc` 已移除,marketplace 正本移到 `plugins/meta`。marketplace 名稱仍是 `jsc`(取自 marketplace.json 的 `name` 欄位,與存取庫名無關),安裝 token 不變;已從舊入口安裝過的人先執行 `claude plugin marketplace remove jsc`,再依上表重新 add。
|
||
|
||
## 工具
|
||
|
||
| 腳本 | 用途 |
|
||
| --- | --- |
|
||
| `tools/wp-gate.sh` | 工作包 PR 閘門,把「一個工作包的 PR 沒合併,擋的是相依於它的工作包,不是整份分析」從內文敘述變成程式判定,共五個用法。`check {owner}/{repo} {index} [--since {ISO 時間}]` 查一支 PR:已合併就呼叫 `jsc-hooks` 的 `sdlc-gate.sh wp-unlock` 解鎖並印 `status=merged`;沒合併就印 `status=open` 或 `status=closed-unmerged`(被關掉但沒合併不算完成),接著把 issue 留言、審查評語、行內留言全部逐行印出(`--since` 只印更新的,值取上一輪的 `latest=`),最後一行印 `latest={最新一筆留言的時間戳}` 供寫回分析頁。`check-deps {owner}/{repo} {wp-number} --analyze {分析頁頁名}` 查某個候選工作包能不能挑:活抓呼叫端指定分析頁的 WBS 表相依欄,逐一核對每個相依工作包的狀態與 PR 是否已合併,只認同一張分析頁上的 `WP-NN` 編號,指到別份計畫的文字項目查不了就列出來要求人工確認,不當成擋人的理由。`claim {owner}/{repo} {wp-number} [--analyze {分析頁頁名}]` 在領包當下轉呼叫 `sdlc-gate.sh wp-claim` 登錄歸屬。`lock {owner}/{repo} {index} [--wp {wp-number}]` 在 PR 開好後轉呼叫 `sdlc-gate.sh wp-lock` 記下未結清,`--wp` 把 PR 掛到該工作包名下。`owns {owner}/{repo} {index} [--wp {wp-number}]` 比對這支 PR 是不是自己這一包的:`owned` 放行、`foreign` 擋住並指出它掛在哪一包名下、查無歸屬(沒有領取紀錄、工作包還沒掛上 PR)一律 `unowned` 放行只提醒。第一行固定 `status=...` 供程式判讀,其後為繁中說明;結束碼 `0`=已合併或無阻擋(含 `check-deps` 的 `ready`、`claim` 的 `claimed`、`owns` 的 `owned` 與 `unowned`)、`1`=未合併、`check-deps` 判定 `blocked` 或 `owns` 判定 `foreign`、`2`=用法錯誤、`3`=相依工具或 PR/分析頁查不到(**查不到就擋,不放行**),或歸屬登錄不了。狀態檔由 `jsc-hooks` 產生(領取檔 `$JSC_HOME/wp/{owner}-{repo}.claim`、鎖檔 `$JSC_HOME/wp/{owner}-{repo}-{index}.pr`,純文字 key=value 一行一欄),不綁 session,開新對話照樣擋;本檔只讀不寫,寫入一律走 `sdlc-gate.sh` 的子命令 |
|
||
| `tools/stage-report.sh` | 階段收尾回報,四個階段共用。`stage-report.sh {plan\|analyze\|implement\|maintain}` 加 `--page TYPE:PAGE`(本階段寫過的每一頁,可重複)產出繁中回報:模型閘門判定(轉述 `sdlc-gate.sh report`,不自評)、工作日誌連結(`--worklog`、`--worklog-heading` 組出導向條目標題的錨點)、所有寫入的 wiki 絕對網址。實作階段再加 `--worktree`、`--source-branch`、`--work-branch`、`--target-branch`、`--pr`,來源分支在不在遠端、工作分支幾個 commit、推送了沒,都由腳本現查。沒有工作日誌時警告使用者檢查,並用 `--pending-file`、`--log-hash` 把內容交給 `jsc-log/tools/worklog-pending.sh` 暫存,下次寫日誌一併寫入。結束碼 `0`=完整、`1`=有警告(**警告不是阻擋**)、`2`=用法錯誤、`3`=相依工具找不到 |
|
||
|
||
## Skills 目錄
|
||
|
||
呼叫方式:Claude / Antigravity `/jsc-sdlc:{name}`;Codex `${name}`;Copilot / Kiro 描述需求自動觸發。
|
||
|
||
<!-- JSC-SKILLS:START -->
|
||
|
||
### `plan`
|
||
|
||
規劃:讀計畫目錄 `PLAN_CONTENTS`(CONTENTS 存取庫)→ 補充或新建計畫 → 決策樹持續提問,補全目標、範圍、可行性到達成共識(判定規則見 `references/consensus.md`,一輪不算問完)→ 產生使用者故事 → 寫回 `PLAN_{HASH}`(PLAN 存取庫)→ 用 `jsc-gitea/tools/wiki-contents.sh` 把計畫目錄那個 `PLAN_{HASH}` 區塊 upsert,計畫頁連結用 `wiki-url` 的絕對網址 → 階段回報(`tools/stage-report.sh`)。純邏輯,禁止程式碼與修改檔案;claude 另有 `jsc-hooks/hooks/write-guard.sh` 的階段寫入閘門把關,其餘四支 CLI 沒有 `PreToolUse`,只靠內文約束。工作包閘門對 `plan` 只提醒不擋(`analyze` 與 `maintain` 仍擋),放棄的是「手上工作包沒結清就別開新計畫」這道在製品上限。
|
||
|
||
### `analyze`
|
||
|
||
分析:先併行讀 `PLAN_CONTENTS` 與 `ANALYZE_CONTENTS`(兩頁都在 CONTENTS 存取庫),沒有計畫可選就立刻停(不先問分支,因為分支隨計畫而變)→ 選定要擴充的分析或要分析的計畫 → 確認來源分支並檢查工作目錄與 `origin/{來源分支}` 一致 → 持續提問到達成共識(`references/consensus.md`)→ 搭配現況(工作目錄與 `REPO_{HASH}` 盤點複用)分析使用者故事 → WBS 產生編號工作包,`WP-01` 固定是獨立的交付、交接工作包,實作工作包相依於它 → CPM 估工時與天數 → 先產生**使用者故事驗收計畫**(每個情境標明 `真實資料` 或 `邏輯推論`,並寫出輸入、預期結果、資料來源與對應工作包)→ 再拆 TDD 待辦 → 寫回 `ANALYZE_{HASH}`(ANALYZE 存取庫),再用 `jsc-gitea/tools/wiki-contents.sh` 把 `ANALYZE_CONTENTS` 與 `PLAN_CONTENTS` 各自那一個 H2 區塊 upsert,分析頁連結用 `wiki-url` 的絕對網址;重新盤點時 `REPO_{HASH}` 寫進 REPO 存取庫、`REPO_CONTENTS` 走同一支腳本 → 階段回報(`tools/stage-report.sh`)。純邏輯,禁止程式碼與修改檔案;claude 另有 `jsc-hooks/hooks/write-guard.sh` 的階段寫入閘門把關,其餘四支 CLI 沒有 `PreToolUse`,只靠內文約束。
|
||
|
||
### `implement`
|
||
|
||
實作:**閘門先跑,白工才不會發生**——先讀分析頁,把每個已開 PR 但沒合併的工作包批次跑 `tools/wp-gate.sh check`(各支 PR 互不相依,併發預取後才開始逐則問),動手前先跑 `tools/wp-gate.sh owns` 確認那支 PR 是自己這一包的,再依 `jsc-ask:ask` 決策樹與使用者對每一則留言達成共識才修(以 sub agent 回原 worktree、推同一條工作分支,不開第二個 PR),**這一步只結清舊 PR 的留言,不擋別的工作包**——每則處理過的留言都要用 `jsc-gitea/tools/gitea.sh comment-reply` 回覆,純討論或讚美才可忽略並在回報中列出理由,處理過的時間戳寫回分析頁**既有**的 PR 欄位當下一輪的 `--since` → 列出「未完成、無工作證」的候選工作包,沒有可挑的就停 → **提選項前先對每個候選各跑一次 `tools/wp-gate.sh check-deps --analyze ANALYZE_{HASH}`(候選之間可併行),只有 `ready` 排進選項**:活查它在分析頁上的相依工作包是否都已合併,只有相依於它的包才會被一支未合併的 PR 擋住,跟它無關的工作包可以平行進行(交付工作包排在選項最前)→ 領到包立刻跑 `tools/wp-gate.sh claim` 記下歸屬,**沒登錄成功就不得開工** → 確認來源分支(同時是 PR 目標):分析頁已記的值直接顯示並單鍵確認,只有「分析頁沒記錄」與「`origin/{來源分支}` 遠端不存在」兩種情況才走完整決策樹 → 產生工作證並寫回該工作包的「工作證」欄 → 交付工作包開工前先確認交付內容(API 文件、由使用者輸入,見 `references/deliver-formats.md`)→ **動程式碼前先從 `origin/{source-branch}` 建立 worktree**(`.worktree/{analysis-HASH}/{wp-number}/{repo}`,一個工作包一個 worktree,分支處理依決策樹詢問;多個存取庫的 worktree 併行建立)→ 在 worktree 內逐項 TDD 實作、每完成一項立即更新 wiki → **收尾稽核兩關同時啟動、並列進行,兩關都過才算工作包完成**:一關是 `jsc-review:code-review` 程式碼審查,另一關是 API 文件稽核——先跑 `jsc-review/tools/swagger-detect.sh` 判定專案支不支援 Swagger(退出碼 `0` 支援、`1` 不支援、`2` 參數或路徑有錯),支援才呼叫 `jsc-review:api-doc` 把控制器文件補到過關(沒過就以 sub agent 修完再稽核一次),不支援就**明確跳過並回報**,跳過算通過 → **每完成一個工作包就 commit、push、PR 回來源分支**(一包一 PR),接著 `tools/wp-gate.sh lock --wp` 上鎖並登記 PR 歸屬 → **用 `jsc-gitea/tools/pr-watch.sh` 盯到合併**(預設 60 秒輪詢、不自動退場;退出碼 `0` 已合併或關閉、`10` 有新留言就回頭跑同一套留言修正、`3` 查不到該 PR、`2` 參數或環境有問題),合併後解鎖並移除 worktree → 詢問交付文件格式(`DELIVER_{HASH}` wiki 頁寫進 DELIVER 存取庫,或 Gitea 議題留言)並產出 → 詢問是否加入維護目錄;`DELIVER_CONTENTS` 與 `MAINTAIN_CONTENTS` 都在 CONTENTS 存取庫,一律用 `jsc-gitea/tools/wiki-contents.sh` 單一 H2 區塊 upsert,交付頁連結用 `wiki-url` 的絕對網址 → 階段回報(`tools/stage-report.sh`,多報工作目錄與來源、工作、目標三條分支),PR 回報使用 `jsc-meta/references/pr-report.md` 的表格。**每完成一個任務就寫一筆工作日誌**(`jsc-log:worklog`):一個工作包、一輪 PR 留言修正、一個獨立的修正提交各算一個任務,不等到階段結束才補一次;`stage-report.sh --pending-file` 暫存的內容併進同一次寫入,寫入成功才清除。寫程式碼時註解只寫「為什麼這樣寫」,工作包編號、分析頁編號、待辦編號、分支名、PR 編號一律不寫進註解,完整清單與白名單見 `jsc-review` 的 `references/comment-scope.md`。
|
||
|
||
### `maintain`
|
||
|
||
維護:從 `MAINTAIN_CONTENTS`(CONTENTS 存取庫;`MAINTAIN` 只有目錄頁)讀取維護期內的專案,**先整批併行 `git fetch` 並把每個專案切到 develop、master 並對齊 `origin/{branch}`**(專案之間互不相依),接著逐專案循序、每個專案一個 sub agent:提出至少五種維護方法,依決策樹讓使用者挑要做哪些 → commit / push / PR → 用 `jsc-meta/references/pr-report.md` 的表格回報 PR → **PR 開好立刻寫一筆工作日誌**(`jsc-log:worklog`,一個專案一筆,下一個專案開工前要先寫完)→ 用 `jsc-gitea/tools/wiki-contents.sh` 單一 H2 區塊 upsert 更新前次維護時間 → 階段回報(`tools/stage-report.sh`)。sub agent 改程式碼時註解只寫「為什麼這樣寫」,議題編號、commit hash、分支名、人名與 `@` 提及一律不寫進註解,完整清單與白名單見 `jsc-review` 的 `references/comment-scope.md`;把關交給 `comment-scope.sh` 與提交前的 commit sweep,不再多做一輪人工全 diff 自查。**只有 claude 在寫檔當下就收到警告**;codex、copilot、antigravity 的 hook 要到回合或工作階段結束才掃,提交前的 commit sweep 是那三支唯一來得及的一道。僅適用於維護期內已交付的專案;尚在實作中或未登記於 `MAINTAIN_CONTENTS` 的專案不適用。
|
||
|
||
<!-- JSC-SKILLS:END -->
|
||
|
||
## 範本與參考
|
||
|
||
| 檔案 | 用途 |
|
||
| --- | --- |
|
||
| `templates/plan-page.md`、`templates/plan-contents.md` | 計畫頁與計畫目錄 |
|
||
| `templates/analyze-page.md`、`templates/analyze-contents.md` | 分析頁(WBS、CPM、TDD 待辦)與分析目錄 |
|
||
| `templates/repo-page.md`、`templates/repo-contents.md` | 存取庫盤點頁(功能與端點,附 commit sha)與盤點目錄 |
|
||
| `templates/deliver-page.md`、`templates/deliver-contents.md` | 交付頁(API 文件、新舊參數標示、驗證方式)與交付目錄 |
|
||
| `templates/maintain-contents.md` | 維護目錄(截止日 NULL = 永久維護) |
|
||
| `references/stage-report.md` | 階段回報:四階段都要交的三項(模型能力標籤、工作日誌連結、所有寫入的 wiki 連結)、實作階段多交的四項、沒寫日誌時的暫存規則、提前停止也要回報 |
|
||
| `references/model-gate.md` | 模型閘門:執行順序、各階段必要標籤、阻擋與回報的鐵則 |
|
||
| `references/tdd.md` | 接縫、紅綠循環規則、反模式 |
|
||
| `references/branch.md` | 分支規則:**一律以遠端 `origin/{branch}` 為準、動作前先 fetch**、分析前確認來源分支、實作沿用同一條來源分支作為 PR 目標(一包一 PR,一個工作包的 PR 沒合併只擋相依於它的工作包,不擋整份分析,閘門分工與工作包隔離的狀態檔格式見該檔)、分支階梯(表本身在 `jsc-meta` 的 `references/guidelines.md`「PR 分支階梯」,該檔只寫 sdlc 拿到 `jsc-git/tools/base-branch.sh --derive` 的回應之後要做什麼、推不出就中止問使用者)、實作一律在 `.worktree/{HASH}/{wp-number}/{repo}` 內進行——一個工作包一個 worktree,讓互不相依的工作包能平行進行不互相搶路徑(建立前問分支、PR 合併後才移除)、判定遠端預設分支、不破壞未提交變更 |
|
||
| `references/consensus.md` | 規劃與分析的提問規則:一輪不算問完、共識的兩個判定條件、未決項處理 |
|
||
| `references/deliver-formats.md` | 交付內容型別:API 文件必備欄位、範例資料優先序、既有端點的新舊參數標示 |
|
||
|
||
## 環境變數
|
||
|
||
Wiki 位置:**目錄頁與內容頁分屬不同存取庫**。五個目錄頁 `PLAN_CONTENTS`、`ANALYZE_CONTENTS`、`REPO_CONTENTS`、`DELIVER_CONTENTS`、`MAINTAIN_CONTENTS` 一律由 `gitea.sh wiki-repo CONTENTS` 解析:只讀 `JSC_WIKI_REPO_CONTENTS`,再退回 `JSC_WIKI_REPO`,兩者都沒設定就 exit 3,**不退回各自的頁型變數**。內容頁各走自己的頁型:`PLAN_{HASH}` 只讀 `JSC_WIKI_REPO_PLAN`、`ANALYZE_{HASH}` 只讀 `JSC_WIKI_REPO_ANALYZE`、`REPO_{HASH}` 只讀 `JSC_WIKI_REPO_REPO`、`DELIVER_{HASH}` 只讀 `JSC_WIKI_REPO_DELIVER`,各自再退回 `JSC_WIKI_REPO`。`MAINTAIN` 是唯一只有目錄頁、沒有內容頁的型別,整個型別都在 CONTENTS 存取庫。不同類型不可互相代用;兩者都未設定才詢問(見 `jsc-gitea`)。
|
||
|
||
目錄頁版面:五個目錄頁都是條列式,不放 markdown 表格。一頁固定三段——H1 頁名、`>` 引言、然後每一筆一個 H2 區塊。H2 標題就是那一筆的鍵,寫成對應內容頁的實際頁名——PLAN、ANALYZE、REPO、DELIVER 四型都取技能自己剛寫的那一頁的頁名(線上實際長成 `ANALYZE_20260821_100552_104F0709` 這樣,不是 `{TYPE}_` 加 40 碼的公式);`MAINTAIN` 沒有內容頁,標題改用該存取庫的 `{owner}/{repo}`,存取庫名不會漂移、當鍵一樣穩,硬造一個 `MAINTAIN_{HASH}` 會指向一個不存在的頁。標題不放連結、不加前後綴。欄位是標題底下的一層條列,一欄一條,格式 `- {欄位名}:{值}`,全形冒號,順序照該頁範本。
|
||
|
||
目錄頁寫入與連結:一律用 `jsc-gitea/tools/wiki-contents.sh upsert {TYPE} {鍵欄} {鍵} {區塊檔} {範本}` 單一區塊 upsert,禁止手工整頁覆蓋。參數語意:`{鍵欄}` 是舊表格裡持有內容頁連結那一欄的序號,只供自動轉檔用——該頁還是舊表格時,腳本從那一欄的連結網址取最後一段路徑當 H2 標題;該頁已經是條列版面就完全忽略它。它不是死參數,也不能隨便填:填錯會讓轉出來的標題跟鍵對不上,既有那一筆被當成新的附加上去,同一筆變成兩個區塊,舊區塊從此再也更新不到。五個頁型的正確值是 `PLAN 2`(計畫頁欄)、`ANALYZE 2`(分析頁欄)、`DELIVER 5`(交付頁欄)、`REPO 2`(盤點頁欄)、`MAINTAIN 1`(存取庫欄,`MAINTAIN` 沒有連結欄)。`{鍵}` 是 H2 標題,填這一筆對應內容頁的實際頁名,也就是技能自己剛寫的那一頁的頁名,不套 `{TYPE}_{HASH}` 的公式;`MAINTAIN` 沒有內容頁,鍵改用該存取庫的 `{owner}/{repo}`,硬造一個 `MAINTAIN_{HASH}` 會指向一個不存在的頁。`{區塊檔}` 是整個 H2 區塊的 markdown,不是列檔(結束碼 `0`=已更新或已新增、`1`=組不出頁面內容或寫入失敗、`2`=用法錯誤、`3`=CONTENTS 存取庫未設定、`4`=頁不存在且沒給範本、`7`=金鑰失效、`8`=其他 API 失敗)。連結一律寫成 `[{文字}]({連結})`,連結取自 `gitea.sh wiki-url` 的絕對網址,不自行組路徑,也不用 `[[頁名]]` 或 `[[顯示文字|頁名]]`:後者只在同一個 wiki 內解析,寫錯不會報錯,巡不到也修不了。寫進任何頁面前,每個連結先過 `jsc-gitea/tools/link-check.sh`,結束碼 0 才寫入;有 DEAD 就不寫並回報(`1`=有連不到、`2`=沒給網址、`3`=`GITEA_HOST` 未設定、`7`=金鑰失效要停下回報,不得當成連不到)。階段回報 `tools/stage-report.sh --page TYPE:PAGE` 的目錄頁一律填 `CONTENTS:` 這個型別,填舊型別會解到錯的存取庫、印不出網址。
|
||
|
||
HASH 規則:`{owner}/{repo}` 的共用 wiki hash 一律由 `jsc-gitea/tools/hash-id` 計算(見 `jsc-gitea:wiki`),此 domain 不重複實作演算法。長度與大小寫的正本也在那裡(現行為完整 40 碼大寫十六進位),本檔不複述規格,只要求一件事:`hash-id` 印出什麼就原樣用,不得自行截短。工作證 `TICKET_{yyyyMMdd}_{HHmmss}_{HASH}` 不是 wiki 頁,但用的是同一支 `hash-id`,同樣原樣帶著走。
|
||
|
||
## 相關 domain
|
||
|
||
- [`jsc-cli`](https://gitea.jsc.idv.tw/plugins/cli):模型能力標籤與階段閘門判定(`tools/model-tags.sh`、`references/model-tags.md`、`jsc-cli:models`)、偏好模型鏈(`tools/model-config.sh`)
|
||
- [`jsc-hooks`](https://gitea.jsc.idv.tw/plugins/hooks):sdlc-gate 階段模型鎖定
|
||
- [`jsc-gitea`](https://gitea.jsc.idv.tw/plugins/gitea):wiki 讀寫、實作階段等 PR 合併的輪詢(`tools/pr-watch.sh`)
|
||
- [`jsc-review`](https://gitea.jsc.idv.tw/plugins/review):實作完成後並列的兩關收尾稽核——程式碼審查(`jsc-review:code-review`)、API 文件稽核(`jsc-review:api-doc`,專案支不支援 Swagger 由 `tools/swagger-detect.sh` 判定,稽核項目也只寫在該技能)
|
||
- [`jsc-git`](https://gitea.jsc.idv.tw/plugins/git) / [`jsc-pkg`](https://gitea.jsc.idv.tw/plugins/pkg):維護階段的 commit / PR 與套件更新
|
||
- [`jsc-log`](https://gitea.jsc.idv.tw/plugins/log):工作日誌,每完成一個任務就寫一筆
|