Files
sdlc/skills/implement/SKILL.md
T
jiantw83 9b48d16422 feat(implement): 收尾改成程式碼審查與 API 文件稽核兩關並列
What:skills/implement/SKILL.md 第 10 步改寫。原本只呼叫 code-review,現在拆成
並列的兩關:10.1 程式碼審查維持原判準,10.2 新增 API 文件稽核——先跑
jsc-review/tools/swagger-detect.sh,退出碼 0 就呼叫 jsc-review:api-doc,1 就
明確跳過並回報,2 就修好參數或路徑重跑。技能的 description 同步改寫。

Why:支援 Swagger 的專案,控制器文件沒補全就等於工作包沒做完。兩關並列而不是
一關套一關,是因為程式碼審查過了不代表 API 文件補齊了,反過來也一樣,任何一關
沒過工作包都不算完成。跳過一定要講出來:沒回報的跳過跟忘記做分不出來。退出碼
2 是偵測不出結果,既不算通過也不算跳過,硬當跳過會讓真的支援 Swagger 的專案
漏掉稽核。

How:改寫刻意只動第 10 步內部,用 10.1、10.2 子項編號,1 到 14 的頂層編號一個
都不動——references/deliver-formats.md 指的「步驟 7」、references/branch.md 指的
「步驟 4 與步驟 11」都還指得到原來的位置。稽核項目不抄一份過來,只寫「看
jsc-review:api-doc」,判準改動時不必兩邊同步。兩關的失敗都是修,不是放行:每一
輪修正都以 sub agent 在同一個 worktree 內進行,修完再稽核一次。

Who:jsc-sdlc 的 implement 技能,工作包的收尾稽核。
2026-08-27 15:41:38 +08:00

21 KiB

name, description
name description
implement SDLC implementation stage. Gate on capability tags enforced in code by sdlc-gate (implement requires coding), then confirm the analysis page's source branch - it is both the worktree base and the PR target. Every already-open work package's PR comments get triaged via tools/wp-gate.sh check and fixed by sub agents only after jsc-ask consensus, never blocking an unrelated package; picking a candidate is gated per-candidate in code by tools/wp-gate.sh check-deps, and claiming it records the package number via tools/wp-gate.sh claim so tools/wp-gate.sh owns keeps every session on its own package's PR. Claim a ready work package from ANALYZE_CONTENTS with a work ticket, confirm a delivery package's content type, then complete its TDD todos one at a time inside a worktree built from origin/{source-branch}, updating the wiki after every item, closing with the two side-by-side audits jsc-review code-review and jsc-review api-doc (the latter gated by swagger-detect.sh and explicitly skipped where the project has no Swagger support), one PR back to the source branch, a jsc-gitea pr-watch.sh poll that holds until that PR merges, a jsc-log:worklog entry per finished task, the chosen delivery document, an optional MAINTAIN_CONTENTS entry, and a tools/stage-report.sh report covering the model tag verdict, the worklog link, every wiki link written, the worktree and the three branches. Use when analysis is done and code must be written; not for planning or analysis.

implement

Goal: complete the analysis page's todos one by one; update the wiki status immediately after every completed item. All wiki reads and writes go through jsc-gitea:wiki.

Steps

  1. Model gate and stage lock — run jsc-cli/tools/model-tags.sh sync, then jsc-hooks/hooks/sdlc-gate.sh lock implement. This stage requires the coding capability tag. Rules: references/model-gate.md. Completion condition: the script exited 0, and you have reported the stage, the required tag, the actual model id it read from the transcript, and the verdict.

  2. Confirm the source branch — it is also this stage's PR target:

    1. Run git fetch --prune origin, then read the source branch from the analysis page and report it, along with the current branch and whether the working tree is clean.
    2. Ask per jsc-ask:ask rules to confirm that origin/{source-branch} is both the worktree's base and the PR target for every work package in this analysis. State the impact scope: each finished work package merges back into the source branch, and that branch as a whole reaches develop later as its own separate PR.
    3. A source branch missing from the remote is a stop-and-report condition, never a silent fallback. That rule (section 「來源分支在遠端找不到」), the remote-only basis and the uncommitted-changes rules: references/branch.md.
    4. Completion condition: the user has confirmed the source branch explicitly, and it is recorded on the analysis page next to the work ticket.
  3. Generate a work ticket: format TICKET_{yyyyMMdd}_{HHmmss}_{HASH}. {HASH} = the shared wiki hash for {owner}/{repo}, computed by jsc-gitea/tools/hash-id (see jsc-gitea:wiki). Rename the current session to the ticket name; skip the rename only when the CLI exposes no rename command. Completion condition: the ticket string exists, and you have reported it together with which branch applied — renamed, or skipped because this CLI has no rename command.

  4. Settle every already-open work-package PR's comments — this keeps existing PRs moving, but does not by itself decide which new package may start (that's step 6):

    1. Read the analysis page's PR column. For every work package holding a PR that is not marked merged, run jsc-sdlc/tools/wp-gate.sh check {owner}/{repo} {index} --since {the comment timestamp recorded in that PR column}. Drop --since when that package has no recorded timestamp yet.
    2. Exit 0 (status=merged) clears that package: remove its worktree (references/branch.md) and mark the package done on the analysis page.
    3. Exit 1 (status=open or status=closed-unmerged) means that package's own PR is not settled yet. This does not block picking a different, unrelated work package — SDLC implementation can run several independent packages in parallel; an unmerged PR only holds back packages that depend on it (step 6 checks that specifically), never the whole analysis page. Sub-steps 4.4 to 4.9 are the one comment round this skill owns; step 11.5 runs the same sub-steps for the PR it just opened.
    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.
    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.
    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.
    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.
  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:

    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.
    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.
    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.
    5. Record the claim in code, so later steps can tell this package's PR from any other package's: run jsc-sdlc/tools/wp-gate.sh claim {owner}/{repo} {wp-number} --analyze ANALYZE_{HASH}, with the number read off the analysis page — the work package number is the only thing ownership is judged by (references/branch.md). One repository holds one claim at a time; wp-gate.sh check hands it back once the PR merges. Completion condition: check-deps returned status=ready for the picked candidate (any cross-page dependency confirmed with the user), the ticket is saved on the wiki, and claim returned status=claimed; only then may you proceed.
  7. A delivery/handover package confirms its content before its first todo:

    1. Ask per jsc-ask:ask rules what this delivery must contain. The options are fixed: 1. API 文件 and 2. 由使用者輸入. State the impact scope on each. Never assume the type, and never skip this — the answer decides what the whole package produces.
    2. Required fields, sample-data order and the new-versus-existing parameter marking: references/deliver-formats.md.
    3. Completion condition: the confirmed type is written into the analysis page's 交付型別 column and saved back to the wiki before the first todo starts.
  8. Create the worktree — before touching any code. Run git fetch --prune origin, read the source branch and the repositories involved from the analysis page, then ask per jsc-ask:ask rules how to handle the branch. Path layout, the two git worktree add options, quoting, .git/info/exclude and the reporting duty: references/branch.md. Completion condition: every repository the analysis page names has a worktree built from origin/{source-branch}, and you have reported each worktree's path, checked-out branch, source branch and starting commit sha.

  9. Complete the work package's open items one at a time. Every item MUST run as a sub agent, working inside the worktree:

    1. One sub agent takes one item and follows the TDD loop: red before green, one vertical slice. Rules and anti-patterns: references/tdd.md (refactoring belongs to the review stage).
    2. The main agent keeps only the wiki bookkeeping: when the sub agent reports the item done, flip its [ ] to [x] on the analysis page and save to the wiki.
    3. A code comment states why the code is written this way; it never states where the work is documented. The tracking numbers this stage always holds — the work package number, the analysis page number, the TDD todo number, the source branch name and the PR number — stay out of every code comment; write the reason itself into the comment instead. 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 with the same item. Completion condition: the item's own diff holds no comment line carrying any of those numbers, and every warning the hook printed for this item is fixed.
    4. Completion condition: every item of the package shows [x] on the saved analysis page, and each save happened before the next item's sub agent started.
  10. Two closing audits, side by side — a work package is finished only when both of them clear. Neither replaces the other:

    1. Code review — when all items are done, sweep the work package's whole diff for the comment rule of step 9.3, then call jsc-review:code-review and wait for the verdict. Each round of fixes MUST run as a sub agent inside the same worktree. Completion condition: the review passes, and the diff handed to it holds no comment line carrying the work package number, the analysis page number, a TDD todo number, the source branch name or a PR number (full list: jsc-review/references/comment-scope.md).
    2. API document audit — on a project that supports Swagger, the work package stays unfinished until its controller files are fully documented. Whether the project supports Swagger is decided in code by jsc-review/tools/swagger-detect.sh {worktree path}; run it and branch on its exit code instead of judging the project yourself:
      • 0 — the project supports Swagger. Call jsc-review:api-doc over the work package's changed controller files and wait for its verdict. What that audit checks belongs to jsc-review:api-doc; read the items there and keep no copy of them here.
      • 1 — the project does not support Swagger. Skip this audit explicitly and report the skip. A reported skip is a pass, never a failure.
      • 2 — bad arguments or a bad path. Fix them and run the script again; an undecidable detection is neither a pass nor a skip. A failing verdict is fixed, never waived: each round of fixes MUST run as a sub agent inside the same worktree, and jsc-review:api-doc runs again over the fixed files until it passes. Completion condition: swagger-detect.sh has run for this worktree and its exit code is reported, and either jsc-review:api-doc returned a passing verdict, or the skip is reported together with the exit code that caused it.
  11. One work package finished → commit, push, PR back to the source branch, then hold on that PR until it merges:

    1. Call jsc-git:pr from inside the worktree, passing {source-branch} as the base branch. One package, one PR; the branch ladder and how the base is derived are in references/branch.md.
    2. Write the PR URL and number into that work package's PR column on the analysis page and save it back to the wiki, so the next run of this skill can find it (step 4).
    3. Run jsc-sdlc/tools/wp-gate.sh lock {owner}/{repo} {index} --wp {wp-number}. The lock is what makes step 4's gate hold across work sessions — a new session starts blocked until that PR merges — and --wp is what hangs this PR on the claim from step 6.5, so owns can keep other sessions off it. Leave --wp out and every session is free to touch this PR. Completion condition: the script printed status=locked and named the work package.
    4. The work package is finished the moment its PR is open — call jsc-log:worklog now, under the Rules section's one-task-one-entry rule. Completion condition: the entry is saved on LOG_{HASH} before the wait starts.
    5. Wait for the merge with jsc-gitea/tools/pr-watch.sh {owner}/{repo} {index} — it polls every 60 seconds (JSC_PR_WATCH_INTERVAL overrides), never times out, and never repeats a comment it already reported. Branch on its exit code:
      • 0 — the PR merged or was closed. Run jsc-sdlc/tools/wp-gate.sh check {owner}/{repo} {index} to tell merged from closed-unmerged, release the lock and hand the claim back. status=merged → remove the worktree (references/branch.md) and mark the package done on the analysis page; status=closed-unmerged → report it and stop, closed without merging is not finished. Comments printed in that final round still get an outcome per step 4.5 to 4.9.
      • 10 — new comments are waiting. Run step 4.4 to 4.9 over them (ownership, consensus, sub agent fixes, outcomes, timestamp, work log), then run pr-watch.sh again. Repeat for as many rounds as the reviewer needs.
      • 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.
    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.
  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).
    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.
    3. Wiki page: write DELIVER_{HASH} through jsc-gitea:wiki, where {HASH} comes from jsc-gitea/tools/hash-id over {owner}/{repo} plus the work package number (for example plugins/sdlc#WP-01), so each work package gets its own page instead of overwriting the previous one. A new page is added to DELIVER_CONTENTS per templates/deliver-contents.md.
    4. Issue comment: confirm the issue number with the user (propose the one referenced by the work package or the PR; never guess), then post via jsc-gitea/tools/gitea.sh api POST /repos/{owner}/{repo}/issues/{n}/comments with the body passed in as a UTF-8 file — real newlines, never a literal \n.
    5. Completion condition: the chosen format has actually been produced, and you have reported where it landed (wiki page name, or the comment URL).
  13. Ask per jsc-ask:ask rules whether to register this project for maintenance: append to MAINTAIN_CONTENTS with templates/maintain-contents.md. Required: repository {owner}/{repo}, maintenance method, start date. Optional: end date (NULL = maintain forever), last-maintained time. Completion condition: the user has answered, and a chosen registration is saved on the wiki.

  14. Stage report — the last thing this stage does, including every early stop (the work package gate blocked, no work package was selectable, the source branch was missing from the remote). Run tools/stage-report.sh implement with:

    • one --page TYPE:{page} per wiki page this run wrote — ANALYZE_{HASH}, DELIVER_{HASH} and DELIVER_CONTENTS, MAINTAIN_CONTENTS;
    • --worklog and --worklog-heading pointing at the entry step 11.4 wrote — following the Rules section's one-task-one-entry rule, a stage that finished anything already has one. --pending-file {file} --log-hash {HASH} is the fallback for a stage that stopped before any task finished: it holds the content for the next jsc-log:worklog run, and held content is not a written log;
    • --worktree {path} --source-branch {name} --work-branch {name} --pr {url} — the script reads the commit count, the push state and whether the source branch exists on the remote by itself, so pass the names, not your own count.

    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 it names the worktree, all three branches and every wiki page this run wrote.

Rules

  • One finished task, one work log entry. A task is one of three things: one work package, one round of PR-comment fixes, or one standalone fix commit. Call jsc-log:worklog the moment one of them finishes — never let a stage end and then write a single catch-up entry, because by then the elapsed time, the token counts and the difficulties are gone. Every entry appends to the same LOG_{HASH} page, so one package that took five comment rounds leaves five entries. 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.
  • The work ticket is a mutex: always skip work packages that already hold a ticket; never take one over.
  • Never batch wiki updates across items; one item, one update.
  • Sample data written into code or fixtures follows the analysis page's 資料來源 column, under the rules in references/deliver-formats.md.
  • Everything the skill writes out (wiki content, commit messages, PR descriptions) stays Traditional Chinese per the STE100 rule.