Merge pull request 'feat/change-requests/sdlc-pr-flow-and-wp-gate' (#35) from feat/change-requests/sdlc-pr-flow-and-wp-gate into feat/change-requests/main

Reviewed-on: #35
This commit was merged in pull request #35.
This commit is contained in:
2026-08-28 01:46:51 +00:00
7 changed files with 32 additions and 19 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-sdlc", "name": "jsc-sdlc",
"version": "0.2.0", "version": "0.2.1",
"description": "開發生命週期:規劃、分析、實作、維護(wiki 追蹤)", "description": "開發生命週期:規劃、分析、實作、維護(wiki 追蹤)",
"skills": "./skills", "skills": "./skills",
"author": { "author": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-sdlc", "name": "jsc-sdlc",
"version": "0.2.0", "version": "0.2.1",
"description": "開發生命週期:規劃、分析、實作、維護(wiki 追蹤)", "description": "開發生命週期:規劃、分析、實作、維護(wiki 追蹤)",
"skills": "./skills" "skills": "./skills"
} }
+3 -3
View File
@@ -22,7 +22,7 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安
| 腳本 | 用途 | | 腳本 | 用途 |
| --- | --- | | --- | --- |
| `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}` 查某個候選工作包能不能挑:活抓分析頁 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/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`=相依工具找不到 | | `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 目錄 ## Skills 目錄
@@ -41,11 +41,11 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安
### `implement` ### `implement`
實作:先確認來源分支(同時是 PR 目標)→ 領包前先跑 `tools/wp-gate.sh check` 把每個已開 PR 但沒合併的工作包留言逐筆印出,動手前先跑 `tools/wp-gate.sh owns` 確認那支 PR 是自己這一包的,再依 `jsc-ask:ask` 決策樹與使用者對每一則留言達成共識才修(以 sub agent 回原 worktree、推同一條工作分支,不開第二個 PR),**這一步只結清舊 PR 的留言,不擋別的工作包**——修不動或純討論的留言忽略但要在回報裡列出,處理過的時間戳寫回分析頁**既有**的 PR 欄位當下一輪的 `--since` → 產生工作證鎖定「未完成、無工作證」的候選工作包(交付工作包優先),**每個候選都跑 `tools/wp-gate.sh check-deps` 判斷能不能挑**:活查它在分析頁上的相依工作包是否都已合併,只有相依於它的包才會被一支未合併的 PR 擋住,跟它無關的工作包可以平行進行 → 領到包立刻跑 `tools/wp-gate.sh claim` 記下歸屬 → 交付工作包開工前先確認交付內容(API 文件、由使用者輸入,見 `references/deliver-formats.md`)→ **動程式碼前先從 `origin/{source-branch}` 建立 worktree**(`.worktree/{analysis-HASH}/{wp-number}/{repo}`,一個工作包一個 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 頁或 Gitea 議題留言)並產出 → 詢問是否加入維護目錄 → 階段回報(`tools/stage-report.sh`,多報工作目錄與來源、工作、目標三條分支)。**每完成一個任務就寫一筆工作日誌**(`jsc-log:worklog`):一個工作包、一輪 PR 留言修正、一個獨立的修正提交各算一個任務,不等到階段結束才補一次;`stage-report.sh --pending-file` 暫存的內容併進同一次寫入,寫入成功才清除。寫程式碼時註解只寫「為什麼這樣寫」,工作包編號、分析頁編號、待辦編號、分支名、PR 編號一律不寫進註解,完整清單與白名單見 `jsc-review` 的 `references/comment-scope.md`。 實作:先確認來源分支(同時是 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}` 判斷能不能挑**:活查它在分析頁上的相依工作包是否都已合併,只有相依於它的包才會被一支未合併的 PR 擋住,跟它無關的工作包可以平行進行 → 領到包立刻跑 `tools/wp-gate.sh claim` 記下歸屬 → 交付工作包開工前先確認交付內容(API 文件、由使用者輸入,見 `references/deliver-formats.md`)→ **動程式碼前先從 `origin/{source-branch}` 建立 worktree**(`.worktree/{analysis-HASH}/{wp-number}/{repo}`,一個工作包一個 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 頁或 Gitea 議題留言)並產出 → 詢問是否加入維護目錄 → 階段回報(`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`
維護:讀取維護期內的專案,每個專案一個 sub agent:fetch 後切 develop、master 並對齊 `origin/{branch}` → 提出至少五種維護方法,依決策樹讓使用者挑要做哪些 → commit / push / PR → **PR 開好立刻寫一筆工作日誌**(`jsc-log:worklog`,一個專案一筆,下一個專案開工前要先寫完)→ 更新前次維護時間 → 階段回報(`tools/stage-report.sh`)。sub agent 改程式碼時註解只寫「為什麼這樣寫」,議題編號、commit hash、分支名、人名與 `@` 提及一律不寫進註解,完整清單與白名單見 `jsc-review` 的 `references/comment-scope.md`。僅適用於維護期內已交付的專案;尚在實作中或未登記於 `MAINTAIN_CONTENTS` 的專案不適用。 維護:讀取維護期內的專案,每個專案一個 sub agent:fetch 後切 develop、master 並對齊 `origin/{branch}` → 提出至少五種維護方法,依決策樹讓使用者挑要做哪些 → commit / push / PR → 用 `jsc-meta/references/pr-report.md` 的表格回報 PR → **PR 開好立刻寫一筆工作日誌**(`jsc-log:worklog`,一個專案一筆,下一個專案開工前要先寫完)→ 更新前次維護時間 → 階段回報(`tools/stage-report.sh`)。sub agent 改程式碼時註解只寫「為什麼這樣寫」,議題編號、commit hash、分支名、人名與 `@` 提及一律不寫進註解,完整清單與白名單見 `jsc-review` 的 `references/comment-scope.md`。僅適用於維護期內已交付的專案;尚在實作中或未登記於 `MAINTAIN_CONTENTS` 的專案不適用。
<!-- JSC-SKILLS:END --> <!-- JSC-SKILLS:END -->
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-sdlc", "name": "jsc-sdlc",
"version": "0.2.0", "version": "0.2.1",
"description": "開發生命週期:規劃、分析、實作、維護(wiki 追蹤)", "description": "開發生命週期:規劃、分析、實作、維護(wiki 追蹤)",
"skills": "./skills/" "skills": "./skills/"
} }
+3 -3
View File
@@ -24,14 +24,14 @@ All wiki reads and writes go through `jsc-gitea:wiki`.
4. **The PR has to be yours before you touch it.** Run `jsc-sdlc/tools/wp-gate.sh owns {owner}/{repo} {index} --wp {the work package number that PR column belongs to}`. `status=owned` → carry on. `status=foreign` (exit 1) → leave that PR alone, name the work package the script says holds it, and let that package's own session handle it. `status=unowned` (exit 0) → carry on, and report that ownership could not be determined. Completion condition: the script has run for that PR and its verdict is reported. 4. **The PR has to be yours before you touch it.** Run `jsc-sdlc/tools/wp-gate.sh owns {owner}/{repo} {index} --wp {the work package number that PR column belongs to}`. `status=owned` → carry on. `status=foreign` (exit 1) → leave that PR alone, name the work package the script says holds it, and let that package's own session handle it. `status=unowned` (exit 0) → carry on, and report that ownership could not be determined. Completion condition: the script has run for that PR and its verdict is reported.
5. **Agree on the fix before making it.** Run the `jsc-ask:ask` decision tree over the comments the script printed — issue comments, review verdicts and inline comments alike — one option set per comment, each option stating its impact scope (which files it touches, whether it changes the package's TDD todos). **Never fix a comment automatically**: a reviewer's wording often allows two different fixes, and picking one silently costs another review round. Completion condition: the user has said how each comment is handled before any file is edited. 5. **Agree on the fix before making it.** Run the `jsc-ask:ask` decision tree over the comments the script printed — issue comments, review verdicts and inline comments alike — one option set per comment, each option stating its impact scope (which files it touches, whether it changes the package's TDD todos). **Never fix a comment automatically**: a reviewer's wording often allows two different fixes, and picking one silently costs another review round. Completion condition: the user has said how each comment is handled before any file is edited.
6. **Each round of fixes MUST run as a sub agent** inside that package's own worktree, pushing to the same work branch, so the PR updates itself. Hand the sub agent the agreed decisions and let the comment text stay inside it — the main agent keeps only the decisions and the bookkeeping. Never open a second PR for the same package. 6. **Each round of fixes MUST run as a sub agent** inside that package's own worktree, pushing to the same work branch, so the PR updates itself. Hand the sub agent the agreed decisions and let the comment text stay inside it — the main agent keeps only the decisions and the bookkeeping. Never open a second PR for the same package.
7. Give every printed comment an outcome — fixed, no fix needed, or cannot fix. Ignore what you cannot fix, plus pure discussion and praise: do not reply on the PR and do not stop the flow, and list each ignored comment with its reason in your final report. 7. Give every printed comment an outcome — fixed, no fix needed, or cannot fix. Reply to every handled comment with `jsc-gitea/tools/gitea.sh comment-reply {owner}/{repo} {index} {issue|review|inline} {comment id} {reply file}`. The reply states the outcome and the commit, file, or reason. Pure discussion and praise can be ignored only when you list the reason. Rules and the completion condition: `jsc-meta/references/pr-report.md`.
8. Write the script's `latest=` value into that work package's PR column, appended after the existing PR link as `#{index} 已處理留言 {ISO time}`, and save the page back to the wiki. Next run passes it as `--since`, so handled comments stay handled. Reuse the existing PR column and add no new column; the analysis page's columns belong to `analyze`. 8. Write the script's `latest=` value into that work package's PR column, appended after the existing PR link as `#{index} 已處理留言 {ISO time}`, and save the page back to the wiki. Next run passes it as `--since`, so handled comments stay handled. Reuse the existing PR column and add no new column; the analysis page's columns belong to `analyze`.
9. **One round of comment fixes is one finished task — call `jsc-log:worklog` now**, under the Rules section's one-task-one-entry rule. Completion condition: the entry for this round is saved on `LOG_{HASH}` before the next round starts. 9. **One round of comment fixes is one finished task — call `jsc-log:worklog` now**, under the Rules section's one-task-one-entry rule. Completion condition: the entry for this round is saved on `LOG_{HASH}` before the next round starts.
10. Exit 3 means the gate could not decide (a missing dependency, or the PR could not be found). Report it and stop — an undecidable gate never counts as merged. 10. Exit 3 means the gate could not decide (a missing dependency, or the PR could not be found). Report it and stop — an undecidable gate never counts as merged.
11. Completion condition: every work package holding an unmerged PR has had this run's comments triaged (fixed, no fix needed, or cannot fix), logged and reported; a package left unmerged after this does not block step 5/6 for packages that do not depend on it. 11. Completion condition: every work package holding an unmerged PR has had this run's comments triaged (fixed, no fix needed, or cannot fix), logged and reported; a package left unmerged after this does not block step 5/6 for packages that do not depend on it.
5. Read `ANALYZE_CONTENTS` via `jsc-gitea:wiki` and list what is unfinished: plan name, HASH, work package number, count of open items. A selectable work package must satisfy all three: **unfinished, not holding a work ticket, and — verified by step 6's `wp-gate.sh check-deps`, never by eyeballing the 相依 column yourself — dependency-free or all dependencies merged**. Completion condition: you have listed every selectable work package, or reported that none is selectable and stopped. 5. Read `ANALYZE_CONTENTS` via `jsc-gitea:wiki` and list what is unfinished: plan name, HASH, work package number, count of open items. A selectable work package must satisfy all three: **unfinished, not holding a work ticket, and — verified by step 6's `wp-gate.sh check-deps`, never by eyeballing the 相依 column yourself — dependency-free or all dependencies merged**. Completion condition: you have listed every selectable work package, or reported that none is selectable and stopped.
6. **Before picking, the candidate's own dependencies decide — the gate lives in code, not in this text, and it is scoped to that one candidate, never to every open PR on the page**: 6. **Before picking, the candidate's own dependencies decide — the gate lives in code, not in this text, and it is scoped to that one candidate, never to every open PR on the page**:
1. For the candidate work package the user is about to choose, run `jsc-sdlc/tools/wp-gate.sh check-deps {owner}/{repo} {wp-number}`. It re-reads the analysis page and queries Gitea itself — it does not trust anything you already read or concluded. 1. For the candidate work package the user is about to choose, run `jsc-sdlc/tools/wp-gate.sh check-deps {owner}/{repo} {wp-number} --analyze ANALYZE_{HASH}`. It re-reads the caller-specified analysis page and queries Gitea itself — it does not trust anything you already read or concluded, and it never guesses the page from the repository hash.
2. Exit 0 (`status=ready`) → eligible; proceed to claim it. Exit 1 (`status=blocked`) → not eligible; report which dependency work package's PR is not merged yet, and offer the user the other eligible candidates instead of this one. Exit 3 (`status=missing-dep`) is an undecidable gate — report it and stop; never treat an undecidable result as either ready or blocked. 2. Exit 0 (`status=ready`) → eligible; proceed to claim it. Exit 1 (`status=blocked`) → not eligible; report which dependency work package's PR is not merged yet, and offer the user the other eligible candidates instead of this one. Exit 3 (`status=missing-dep`) is an undecidable gate — report it and stop; never treat an undecidable result as either ready or blocked.
3. A dependency phrased as text pointing outside this analysis page (another plan, another analysis) cannot be checked by the script; it comes back listed separately as needing manual confirmation. Confirm it with the user before proceeding — an unchecked cross-page dependency is not the same as a cleared one. 3. A dependency phrased as text pointing outside this analysis page (another plan, another analysis) cannot be checked by the script; it comes back listed separately as needing manual confirmation. Confirm it with the user before proceeding — an unchecked cross-page dependency is not the same as a cleared one.
4. Let the user pick per `jsc-ask:ask` rules from the eligible candidates only (options state open-item count and estimated effort). **List delivery packages (交付 `是`) first** — the analysis page makes `WP-01` the standalone delivery package, so keep that order in the options. Write the ticket into that work package's ticket column (the zh-TW field 「工作證」) on the analysis page and save it back to the wiki. 4. Let the user pick per `jsc-ask:ask` rules from the eligible candidates only (options state open-item count and estimated effort). **List delivery packages (交付 `是`) first** — the analysis page makes `WP-01` the standalone delivery package, so keep that order in the options. Write the ticket into that work package's ticket column (the zh-TW field 「工作證」) on the analysis page and save it back to the wiki.
@@ -65,7 +65,7 @@ All wiki reads and writes go through `jsc-gitea:wiki`.
- `3` — the PR could not be found. Report and stop; a PR nobody can find never counts as merged. - `3` — the PR could not be found. Report and stop; a PR nobody can find never counts as merged.
- `2` — bad arguments, or Gitea was unreachable on the very first poll. Fix the arguments or the environment and run it again; never fall back to eyeballing the PR page and calling it merged. - `2` — bad arguments, or Gitea was unreachable on the very first poll. Fix the arguments or the environment and run it again; never fall back to eyeballing the PR page and calling it merged.
6. **Do not start another work package in this session.** An unrelated package can still proceed, but in its own session with its own worktree; packages that depend on this one stay blocked until step 4 or step 11.5 sees it merged. 6. **Do not start another work package in this session.** An unrelated package can still proceed, but in its own session with its own worktree; packages that depend on this one stay blocked until step 4 or step 11.5 sees it merged.
7. Completion condition: the PR exists, its URL is saved on the analysis page and reported to the user, the lock existed (`status=locked`), the work log entry is saved, and `pr-watch.sh` has returned `0` with `wp-gate.sh check` confirming `status=merged` — or the run stopped on a reported `2`, `3` or `status=closed-unmerged`. 7. Completion condition: the PR exists, its URL is saved on the analysis page and reported to the user with the table format in `jsc-meta/references/pr-report.md`, the lock existed (`status=locked`), the work log entry is saved, and `pr-watch.sh` has returned `0` with `wp-gate.sh check` confirming `status=merged` — or the run stopped on a reported `2`, `3` or `status=closed-unmerged`.
12. **Delivery document** — a finished work package is a delivery, so **always ask before producing it; never pick a format silently and never skip this step**: 12. **Delivery document** — a finished work package is a delivery, so **always ask before producing it; never pick a format silently and never skip this step**:
1. Ask per `jsc-ask:ask` rules which format to produce. The options are fixed: **a `DELIVER_{HASH}` wiki page** or **a Gitea issue comment**. State the impact scope on each (the wiki page lives beside the plan and analysis pages; the issue comment reaches whoever follows that issue). 1. Ask per `jsc-ask:ask` rules which format to produce. The options are fixed: **a `DELIVER_{HASH}` wiki page** or **a Gitea issue comment**. State the impact scope on each (the wiki page lives beside the plan and analysis pages; the issue comment reaches whoever follows that issue).
2. Both formats use the same structure — `templates/deliver-page.md`, in Traditional Chinese. Only the destination differs. Sample values and personal-data handling: `references/deliver-formats.md`. 2. Both formats use the same structure — `templates/deliver-page.md`, in Traditional Chinese. Only the destination differs. Sample values and personal-data handling: `references/deliver-formats.md`.
+2 -2
View File
@@ -24,8 +24,8 @@ All wiki reads and writes go through `jsc-gitea:wiki`.
Completion condition: the user has picked the methods to apply, and every picked method is either applied or reported with the reason it could not be. Completion condition: the user has picked the methods to apply, and every picked method is either applied or reported with the reason it could not be.
3. **A code comment states why the code is written this way; it never states where the work is tracked.** Issue numbers, commit hashes, branch names, people's names and `@` mentions stay out of every code comment this project's maintenance touches — including the comments the cleanup method rewrites. Full list and the allowed exceptions: `jsc-review/references/comment-scope.md`. `jsc-hooks/hooks/comment-scope.sh` compares each file after it is written and prints a warning; fix the flagged line at once, then carry on. Completion condition: this project's diff holds no comment line carrying an issue number, a commit hash, a branch name, a person's name or an `@` mention, and every warning the hook printed is fixed. 3. **A code comment states why the code is written this way; it never states where the work is tracked.** Issue numbers, commit hashes, branch names, people's names and `@` mentions stay out of every code comment this project's maintenance touches — including the comments the cleanup method rewrites. Full list and the allowed exceptions: `jsc-review/references/comment-scope.md`. `jsc-hooks/hooks/comment-scope.sh` compares each file after it is written and prints a warning; fix the flagged line at once, then carry on. Completion condition: this project's diff holds no comment line carrying an issue number, a commit hash, a branch name, a person's name or an `@` mention, and every warning the hook printed is fixed.
4. Commit the changes to a new branch per `jsc-git:commit`, push, then open a PR per `jsc-git:pr` back to the branch of step 3.1, passing it explicitly as the base. Completion condition: the PR exists, and you have reported its URL and number. 4. Commit the changes to a new branch per `jsc-git:commit`, push, then open a PR per `jsc-git:pr` back to the branch of step 3.1, passing it explicitly as the base. Completion condition: the PR exists, and you have reported it with the table format in `jsc-meta/references/pr-report.md`.
5. **One project's maintenance is one finished task — call `jsc-log:worklog` right after its PR is open.** A task is one of three things: one work package, one round of PR-comment fixes, or one standalone fix commit; this stage produces the third kind, one per project. Never let the stage end and then write a single catch-up entry, and never let a second project start before the first one's entry is saved — by then the elapsed time, the token counts and the difficulties are gone. Every entry appends to the same `LOG_{HASH}` page. Content parked earlier by `tools/stage-report.sh --pending-file` is merged into that same write and cleared only once the write succeeds; parked content is not a written log. Completion condition: this project's entry is saved on `LOG_{HASH}` before the next project's sub agent starts. 5. **One project's maintenance is one finished task — call `jsc-log:worklog` right after its PR is open.** A task is one of three things: one work package, one round of PR-comment fixes, or one standalone fix commit; this stage produces the third kind, one per project. Never let the stage end and then write a single catch-up entry, and never let a second project start before the first one's entry is saved — by then the elapsed time, the token counts and the difficulties are gone. Every entry appends to the same `LOG_{HASH}` page. Content parked earlier by `tools/stage-report.sh --pending-file` is merged into that same write and cleared only once the write succeeds; parked content is not a written log. Completion condition: this project's entry is saved on `LOG_{HASH}` before the next project's sub agent starts.
6. Update the project's last-maintained field (the zh-TW column 「前次維護時間」) in `MAINTAIN_CONTENTS` to today. Completion condition: `MAINTAIN_CONTENTS` shows today's date in 「前次維護時間」 for that project, saved on the wiki. 6. Update the project's last-maintained field (the zh-TW column 「前次維護時間」) in `MAINTAIN_CONTENTS` to today. Completion condition: `MAINTAIN_CONTENTS` shows today's date in 「前次維護時間」 for that project, saved on the wiki.
4. The main agent reports the summary: maintenance methods applied per project, PR links, and failure reasons. The report and all generated wiki content, commits, and PR descriptions stay Traditional Chinese per the STE100 rule. Completion condition: the summary names every project read in step 2, each with its applied methods and either a PR link or the reason it was skipped. 4. The main agent reports the summary: maintenance methods applied per project, PR table rows, and failure reasons. The report and all generated wiki content, commits, and PR descriptions stay Traditional Chinese per the STE100 rule. Completion condition: the summary names every project read in step 2, each with its applied methods and either a PR table row or the reason it was skipped.
5. **Stage report — the last thing this stage does, including when no project was in window.** Run `tools/stage-report.sh maintain` with one `--page MAINTAIN:{page}` per wiki page this run wrote (`MAINTAIN_CONTENTS` counts), plus `--worklog` and `--worklog-heading` pointing at the entries step 3.5 wrote. `--pending-file {file} --log-hash {HASH}` is the fallback for a stage that stopped before any project finished: it holds the content for the next `jsc-log:worklog` run, and held content is not a written log. Rules and exit codes: `references/stage-report.md`. Exit 1 is a warning, never a block. Completion condition: the script's output is reported to the user verbatim, and every wiki page this run wrote appears in it. 5. **Stage report — the last thing this stage does, including when no project was in window.** Run `tools/stage-report.sh maintain` with one `--page MAINTAIN:{page}` per wiki page this run wrote (`MAINTAIN_CONTENTS` counts), plus `--worklog` and `--worklog-heading` pointing at the entries step 3.5 wrote. `--pending-file {file} --log-hash {HASH}` is the fallback for a stage that stopped before any project finished: it holds the content for the next `jsc-log:worklog` run, and held content is not a written log. Rules and exit codes: `references/stage-report.md`. Exit 1 is a warning, never a block. Completion condition: the script's output is reported to the user verbatim, and every wiki page this run wrote appears in it.
+21 -8
View File
@@ -16,9 +16,10 @@
# --since 只印比該時間更新的留言,值用上一輪印出的 latest=(UTC,形如 2026-08-25T10:19:59Z)。 # --since 只印比該時間更新的留言,值用上一輪印出的 latest=(UTC,形如 2026-08-25T10:19:59Z)。
# wp-gate.sh lock {owner}/{repo} {index} # wp-gate.sh lock {owner}/{repo} {index}
# PR 開好之後上鎖,讓閘門跨工作階段有效。轉呼叫 sdlc-gate.sh wp-lock。 # PR 開好之後上鎖,讓閘門跨工作階段有效。轉呼叫 sdlc-gate.sh wp-lock。
# wp-gate.sh check-deps {owner}/{repo} {wp-number} # wp-gate.sh check-deps {owner}/{repo} {wp-number} --analyze {分析頁頁名}
# 候選工作包能不能挑:活抓分析頁 WBS 表的相依欄,逐一核對每個相依工作包的狀態欄與 # 候選工作包能不能挑:活抓分析頁 WBS 表的相依欄,逐一核對每個相依工作包的狀態欄與
# PR 欄(PR 有給就活查 Gitea 是否已合併),不吃 implement 技能自己讀到的任何快取或判斷。 # PR 欄(PR 有給就活查 Gitea 是否已合併),不吃 implement 技能自己讀到的任何快取或判斷。
# 分析頁由呼叫端明確指定;沒帶 --analyze 直接拒絕,不用存取庫 hash 猜頁名。
# 只認同一張分析頁上的 WP-NN 編號;相依欄裡指到別份計畫或別頁分析的文字項目查不了, # 只認同一張分析頁上的 WP-NN 編號;相依欄裡指到別份計畫或別頁分析的文字項目查不了,
# 照樣放行但會在說明裡列出來,要求人工確認。 # 照樣放行但會在說明裡列出來,要求人工確認。
# wp-gate.sh claim {owner}/{repo} {wp-number} [--analyze {分析頁頁名}] # wp-gate.sh claim {owner}/{repo} {wp-number} [--analyze {分析頁頁名}]
@@ -88,7 +89,7 @@ usage() {
cat >&2 <<'EOF' cat >&2 <<'EOF'
用法: 用法:
wp-gate.sh check {owner}/{repo} {index} [--since {ISO 時間}] 查 PR:合併就解鎖放行,沒合併就印出留言並擋住 wp-gate.sh check {owner}/{repo} {index} [--since {ISO 時間}] 查 PR:合併就解鎖放行,沒合併就印出留言並擋住
wp-gate.sh check-deps {owner}/{repo} {wp-number} 候選工作包能不能挑:核對它在分析頁上的相依工作包是否都已結清 wp-gate.sh check-deps {owner}/{repo} {wp-number} --analyze {頁名} 候選工作包能不能挑:核對它在分析頁上的相依工作包是否都已結清
wp-gate.sh claim {owner}/{repo} {wp-number} [--analyze {頁名}] 領包當下登錄歸屬 wp-gate.sh claim {owner}/{repo} {wp-number} [--analyze {頁名}] 領包當下登錄歸屬
wp-gate.sh lock {owner}/{repo} {index} [--wp {wp-number}] 開完 PR 後上鎖並把 PR 掛到工作包名下,讓閘門跨工作階段有效 wp-gate.sh lock {owner}/{repo} {index} [--wp {wp-number}] 開完 PR 後上鎖並把 PR 掛到工作包名下,讓閘門跨工作階段有效
wp-gate.sh owns {owner}/{repo} {index} [--wp {wp-number}] 這支 PR 是不是自己這一包的:不是就擋,查無歸屬就放行 wp-gate.sh owns {owner}/{repo} {index} [--wp {wp-number}] 這支 PR 是不是自己這一包的:不是就擋,查無歸屬就放行
@@ -281,8 +282,8 @@ case "$sub" in
echo "$repo 第 $index 號 PR 還開著,沒有合併。這一包還沒結清。" echo "$repo 第 $index 號 PR 還開著,沒有合併。這一包還沒結清。"
fi fi
echo '這一包沒結清,只表示相依於它的工作包不能開始;其餘互不相依的工作包能不能挑,見 wp-gate.sh check-deps。' echo '這一包沒結清,只表示相依於它的工作包不能開始;其餘互不相依的工作包能不能挑,見 wp-gate.sh check-deps。'
echo '下列每一筆留言都要有結果(已修、不需修、修不動)。修不動或純討論、讚美的留言直接忽略:' echo '下列每一筆留言都要有結果(已修、不需修、修不動)。已處理的留言要用 gitea.sh comment-reply 回覆:'
echo '不在 PR 上回覆、也不因此停下流程,但要在最終回報裡逐筆列出被忽略的留言與理由。' echo '純討論或讚美可以不回覆、也不因此停下流程,但要在最終回報裡逐筆列出被忽略的留言與理由。'
if [ -n "$since" ]; then if [ -n "$since" ]; then
echo "留言(只列比 $since 更新的;更早的已經處理過):" echo "留言(只列比 $since 更新的;更早的已經處理過):"
else else
@@ -309,15 +310,27 @@ case "$sub" in
repo="${1:-}"; wp_number="${2:-}" repo="${1:-}"; wp_number="${2:-}"
valid_repo "$repo" || { echo 'status=usage'; usage; exit 2; } valid_repo "$repo" || { echo 'status=usage'; usage; exit 2; }
valid_index "$wp_number" || { echo 'status=usage'; usage; exit 2; } valid_index "$wp_number" || { echo 'status=usage'; usage; exit 2; }
[ "$#" -le 2 ] || { echo 'status=usage'; usage; exit 2; } shift 2
analyze=''
while [ "$#" -gt 0 ]; do
case "$1" in
--analyze) analyze="${2:-}"; [ -n "$analyze" ] || { echo 'status=usage'; usage; exit 2; }; shift 2 ;;
--analyze=*) analyze=${1#--analyze=}; [ -n "$analyze" ] || { echo 'status=usage'; usage; exit 2; }; shift ;;
*) echo 'status=usage'; usage; exit 2 ;;
esac
done
[ -n "$analyze" ] || {
echo 'status=usage'
echo '[jsc][工作包閘門][ERR]:缺少 --analyze ANALYZE_{HASH},check-deps 不會用存取庫 hash 猜分析頁。' >&2
usage
exit 2
}
gitea=$(gitea_sh) || missing_dep "找不到 jsc-gitea 的 tools/gitea.sh。並排版面請確認 {workspace}/gitea 存在,已安裝版面請確認 jsc-gitea plugin 已安裝,或設定 JSC_GITEA_TOOLS 指向它的 tools 目錄。" gitea=$(gitea_sh) || missing_dep "找不到 jsc-gitea 的 tools/gitea.sh。並排版面請確認 {workspace}/gitea 存在,已安裝版面請確認 jsc-gitea plugin 已安裝,或設定 JSC_GITEA_TOOLS 指向它的 tools 目錄。"
hash=$(sh "$gitea" hash-id "$repo" 2>/dev/null)
[ -n "$hash" ] || missing_dep "算不出 $repo 的 wiki HASH。"
wiki_repo=$(sh "$gitea" wiki-repo ANALYZE 2>/dev/null) wiki_repo=$(sh "$gitea" wiki-repo ANALYZE 2>/dev/null)
[ -n "$wiki_repo" ] || missing_dep "解析不出 ANALYZE 頁的 wiki 存取庫(JSC_WIKI_REPO_ANALYZE 與 JSC_WIKI_REPO 都未設定)。" [ -n "$wiki_repo" ] || missing_dep "解析不出 ANALYZE 頁的 wiki 存取庫(JSC_WIKI_REPO_ANALYZE 與 JSC_WIKI_REPO 都未設定)。"
page="ANALYZE_${hash}" page="$analyze"
content=$(sh "$gitea" wiki-get "$wiki_repo" "$page" 2>/dev/null) content=$(sh "$gitea" wiki-get "$wiki_repo" "$page" 2>/dev/null)
[ -n "$content" ] || missing_dep "讀不到分析頁 $wiki_repo 的 $page。" [ -n "$content" ] || missing_dep "讀不到分析頁 $wiki_repo 的 $page。"