Files
review/skills/code-review/SKILL.md
jiantw83 ced541faa5 fix(review): 補上註解腳本路徑與缺漏的失敗分支
- 註解範圍腳本的路徑少一層目錄,照著寫會找不到檔案,補上 hooks 那一層。
- 建置測試跑完卻失敗時沒有分支可走,只寫得出「通過」。現在要指出指令、結束碼,並判斷失敗是不是本次改動造成的。
- 取得差異失敗時原本會安靜跳過,現在原樣帶出錯誤並停手。判不出範圍不等於沒有東西要審。
- 禁止清單原本抄了兩份,改成只指向註解範圍的正本,兩份不會各自演化。
- 第二組不再重掃樣式判得出來的項目。hook 關掉或沒接上時就沒有最後一道網,這件事寫進技能文件,不讓它默默消失。
- 差異只算一次,落成一份快照檔給六組共讀;檔名帶執行代號,同一台機器平行跑不會互相覆蓋。註解清理改成一個檔案一個 sub agent 平行跑。
2026-08-31 11:07:05 +08:00

8.7 KiB

name, description
name description
code-review Review changed code against the Refactoring smell catalog in six groups (bloaters, obscurity, couplers, dispensables, comment contract, shallow modules). Run when a file change is complete or an implementation is complete, e.g. from jsc-sdlc implement. Each group runs as a sub agent over the git diff; findings are reported with file:line, severity, and refactoring, and the caller decides whether to fix. Not a replacement for the CLI's built-in security or bug review.

code-review

Review changed code against references/smells.md (from the book Refactoring). The reference is written in Traditional Chinese; read it as-is.

When to run

  1. When a file change is complete: one file or one related group of files is done.
  2. When an implementation is complete: all todos of a work package are done. This is the call site in jsc-sdlc:implement — the end of a work package, after its last todo and before it is committed and turned into a PR.

Division of labor

  • This skill covers the Refactoring smells, the comment contract (group 5), and shallow modules (group 6).
  • Security, logic bugs, and test coverage belong to the CLI's built-in review (e.g. claude's /security-review); do not duplicate them.
  • Swagger document auditing belongs to jsc-review:api-doc: response type declarations per HTTP status code, Swagger parameter descriptions, and Swagger examples down the nested data models. Group 5 here covers the source comment contract only; the two never report the same gap twice.

Steps

  1. Snapshot the review scope once, to a path that belongs to this run. In one command, expand ${TMPDIR:-/tmp}/jsc-code-review.$$.diff into a variable, redirect git diff (uncommitted changes) or git diff {base}...HEAD (against the base branch when an implementation is complete) into it, and print the expanded path. The $$ is what keeps two runs on one machine apart; a fixed file name lets a second run overwrite the first one's snapshot mid-review, and the six groups in step 2 would then judge bytes that were never their own diff. Read git's exit code: 0 the snapshot is written; any non-zero code means git refused (not a repository, unknown base revision, unreadable object) — report git's stderr verbatim and stop, spawn no sub agent. An empty snapshot file → delete it, report the literal 「無發現」 and stop; spawn no sub agent. The six groups in step 2 all read this one file, so git computes the diff once and every group judges the same bytes. Completion condition: the expanded snapshot path is reported as a literal path — never as the unexpanded $$ pattern — together with a non-empty changed-file list, or the run already ended with 「無發現」 or with git's error.

  2. Review in six groups, and every group MUST run as a sub agent; the six groups may run in parallel:

    Group Scope
    1 Bloaters smells.md group 1
    2 Obscurity smells.md group 2. For 2.5 comment scope leaks, report only what a pattern cannot decide: project code names, customer names, and context-dependent review traces. references/comment-scope.md is the single source of the banned and allowed lists — read it, never restate it here. Pattern-detectable items belong to jsc-hooks/hooks/comment-scope.sh and stay outside this group (see Notes for what that leaves uncovered)
    3 Couplers smells.md group 3
    4 Dispensables & Others smells.md group 4
    5 Comment contract smells.md group 5, 5.1 to 5.8 — including 5.6 navigation links to the functions a method calls, 5.7 XML comment tag layout (opening and closing tag each on its own line), and 5.8 code-element markup by language convention (<paramref>, <see cref>, <c> in XML; backticks in JSDoc and docstrings)
    6 Shallow Module smells.md group 6

    Instructions for each sub agent: read only, change nothing; read the diff snapshot at the exact path step 1 reported, that one file only, and never run git diff again; check every changed line and its enclosing function or class against the group's definitions and detection signals in smells.md.

    Each sub agent returns its findings as TSV rows — one finding per row, six fields separated by a single tab, in this order:

    Field Content
    1 file path relative to the repository root
    2 line line number, a positive integer
    3 severity 高, 中, or 低 on the smells.md scale
    4 group this group's number, 1 to 6
    5 item the smell name
    6 detail one sentence of evidence plus the suggested refactoring

    Fields 5 and 6 are written in Traditional Chinese. Free-form prose is not accepted: tools/merge-findings.sh deduplicates on fields 1 and 2, so any row off this format is rejected and its finding never reaches the report. A group with nothing to report returns the single line 「無發現」 instead of rows.

    Completion condition: all six groups have returned, each with TSV rows or with 「無發現」.

  3. Merge with tools/merge-findings.sh. Concatenate the six groups' TSV rows in group order and pipe them into the script on stdin. Start this step only once all six groups have returned; a group still running means the merge waits. Read its exit code: 0 take its stdout as the merged list — deduplicated by location and sorted by severity, 高 first and 低 last; 1 no group returned a row, so report the literal 「無發現」 and stop; 2 environment or input error, so report the script's stderr verbatim and stop, and never hand-merge as a substitute; 3 a group returned a malformed row, and the stderr names which row, so ask that one group's sub agent to re-emit in the format above and run the merge again — after a second 3, report the malformed rows verbatim and stop. Completion condition: the merged list is on hand with every location appearing exactly once, or the run ended with 「無發現」 or with the reported error.

  4. Report the finding list in Traditional Chinese, one line per merged row. This skill never modifies code. jsc-hooks/hooks/write-guard.sh in review mode enforces that in code: while this skill runs, it blocks write tools. Which tools those are is declared in that script's own header; never restate the list here, because a stale copy of it reads as coverage the guard does not have. Only claude has a PreToolUse hook, so codex, copilot, antigravity, and kiro never reach that guard — on those four this rule and the sub agent instructions are the only constraint. The caller decides what to fix (inside the implementation flow, 高 and 中 are normally mandatory, 低 is judgment).

    Then close the run down in two moves. Delete the step 1 snapshot file; nothing else ever reads it, and left behind it accumulates one stale diff per review. Release the review lock by running jsc-hooks/hooks/write-guard.sh release, which clears $JSC_HOME/sessions/{sid}.lastskill. That file is how the guard recognizes the running skill, and no event tells the guard a skill ended: leave it in place and the caller's first fix — the fix this very report asked for — is blocked by the audit that just finished. State the fallback in the report either way, because an older jsc-hooks treats release as an unknown mode and exits 0 without clearing anything: the lock then lifts by itself once the file is older than JSC_WRITE_GUARD_TTL (900 seconds by default), and JSC_WRITE_GUARD=off opens it immediately.

    Completion condition: the report is handed to the caller, the snapshot is deleted, the release command has been run and the wait plus the JSC_WRITE_GUARD=off escape hatch are stated, and the fix decision is left to them.

Notes

  • jsc-hooks/hooks/comment-scope.sh already matches the pattern-detectable comment scope items after every file write. Group 2 covers what patterns cannot decide — project code names, customer names, and context-dependent review traces — plus the overall judgment; the two never report the same finding twice.
  • Removed protection, on purpose. Group 2 used to re-scan the pattern-detectable items as well, which made it the last net whenever the hook was not running: JSC_COMMENT_SCOPE=off turns comment-scope.sh off entirely, and a CLI with no comment-scope.sh wiring never runs it at all. That net is gone. On such a run, an issue id, a wiki page id, a work package id, or a commit hash left in a comment now reaches the commit with nothing catching it. Run jsc-review:comment-cleanup before commit whenever the hook is off or unwired.
  • If group 5 examples are fetched from a database, they must be de-identified; never include personal data.
  • When there are no findings, report the literal 「無發現」 explicitly; never leave the report empty.