From dbaf81005b1ffd9ea318df26de370b5be2b7300b Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 27 Aug 2026 15:41:38 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat(smells):=20=E7=AC=AC=205=20=E7=B5=84?= =?UTF-8?q?=E6=93=B4=E5=85=85=E6=A2=9D=E5=88=97=E5=BC=8F=E6=AD=A5=E9=A9=9F?= =?UTF-8?q?=E3=80=81=E5=B0=8E=E5=90=91=E9=80=A3=E7=B5=90=E8=88=87=E6=A8=99?= =?UTF-8?q?=E7=A4=BA=E8=AA=9E=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:references/smells.md 第 5 組擴充。5.1 的方法描述後面要接條列式的處理步驟 與規則,5.3 的回傳值是自訂資料模型時要附上型別定義的導向連結;新增 5.6 內含 功能的導向連結、5.7 XML 註解標籤各占一行、5.8 註解裡的專有名詞與變數依語言 慣例標示。文末的嚴重度分級補上一張表,逐項標明這五個新項目的級別與理由。 Why:使用者提出的產出物文件品質規則裡,有三條講的都是原始碼註解要寫到什麼 程度。動手前先比對過既有內容,第 5 組已經涵蓋大部分,缺的是條列步驟、導向 連結與標示語法這三塊。另開一支技能會跟 code-review 的目標重疊,所以直接擴充 第 5 組。新項目多半屬於可讀性層級,混在原本「註解缺漏」一句話裡分不出輕重, 所以級別另外列。 How:5.1 與 5.3 在原有定義後面接上新要求,偵測訊號與建議重構手法同步補列, 原本的判準一個都不動。5.6 到 5.8 照既有小節的四段結構寫:定義、偵測訊號、 建議重構手法、注意事項。5.8 的標示語法用表格對照 XML 與 JSDoc、docstring 兩類格式。5.6 與 5.7 都寫明註解格式不支援時不適用,避免硬造連結字串,也避免 把 XML 的排版規則套到沒有結束標籤的格式上。 Who:jsc-review 的壞味道參考清單,第 5 組註解契約。 --- references/smells.md | 53 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/references/smells.md b/references/smells.md index cc3cf63..443e65a 100644 --- a/references/smells.md +++ b/references/smells.md @@ -122,9 +122,9 @@ ### 5.1 方法描述 -- **定義**:每個公開方法要有一句話描述,並標明所屬層級:**顯示層、邏輯層、存取層**。 -- **偵測訊號**:公開方法無描述;描述未標層級;描述與方法實際行為不符。 -- **建議重構手法**:補上單句描述與層級標記;若一個方法橫跨多層,先依 Split Phase 拆分再各自標註。 +- **定義**:每個公開方法要有一句話描述,並標明所屬層級:**顯示層、邏輯層、存取層**。描述後面要接**條列式的處理步驟與規則**,讀註解就知道這個方法做了哪幾件事、依哪些規則做。 +- **偵測訊號**:公開方法無描述;描述未標層級;描述與方法實際行為不符;描述只有一句話,方法內部卻有多段流程或多條判斷規則,註解裡找不到對應的條列;條列步驟與程式碼實際順序對不上。 +- **建議重構手法**:補上單句描述與層級標記,再把處理流程拆成條列步驟、把判斷條件寫成條列規則;若一個方法橫跨多層,先依 Split Phase 拆分再各自標註;條列長到十項以上,代表方法本身太肥,同時列 1.2 並建議 Extract Function。 ### 5.2 輸入參數說明 @@ -134,9 +134,9 @@ ### 5.3 輸出說明 -- **定義**:輸出(回傳值)要說明回傳的資料內容概要。 -- **偵測訊號**:無回傳說明;未說明 null、空集合、錯誤時的回傳;回傳布林但未說明 true/false 意義。 -- **建議重構手法**:補回傳內容概要與邊界情況說明。 +- **定義**:輸出(回傳值)要說明回傳的資料內容概要。回傳值是自訂資料模型,而註解格式支援導向時(XML 的 ``、JSDoc 的 `{@link}`),說明要附上該資料模型的檔案連結,讀的人一鍵就跳到定義。 +- **偵測訊號**:無回傳說明;未說明 null、空集合、錯誤時的回傳;回傳布林但未說明 true/false 意義;回傳自訂資料模型卻只寫型別名稱純文字,沒有 `` 或 `{@link}` 導向。 +- **建議重構手法**:補回傳內容概要與邊界情況說明;自訂資料模型改用註解格式的導向標籤指到型別定義,泛型集合指到元素型別。 ### 5.4 輸入與輸出範例 @@ -150,6 +150,35 @@ - **偵測訊號**:DTO/ViewModel 僅頂層有註解;內層類別、集合元素型別的欄位無說明或無範例。 - **建議重構手法**:逐層補齊 5.1–5.4;巢狀過深(≥ 3 層)時同時評估 Extract Class 是否被濫用。 +### 5.6 內含功能的導向連結 + +- **定義**:一個功能內部呼叫了其他功能時,註解要交代呼叫了誰、為什麼呼叫。註解格式支援導向就用導向標籤(XML 的 ``、JSDoc 的 `{@link}`),讓 IDE 直接跳過去。 +- **偵測訊號**:方法內呼叫其他公開方法或服務,註解卻完全沒提;提了但只寫純文字方法名,沒有 `` 或 `{@link}`;寫了連結卻沒寫用途,讀的人還是要自己點進去猜。 +- **建議重構手法**:在條列步驟裡把被呼叫的功能改成導向標籤,後面接一句用途;被呼叫的功能多到列不完,代表這個方法在當協調中心,同時列 1.2 或 3.1 評估職責搬移。 +- **注意**:註解格式不支援導向(例如純 `//` 行註解)就只寫用途,不硬造連結字串。 + +### 5.7 XML 註解標籤排版 + +- **定義**:註解採 XML 格式時,起始標籤與結束標籤**各自獨立一行**,內容夾在中間。這樣多行內容、條列與巢狀標籤才排得整齊,diff 也只動到真正改的那幾行。 +- **偵測訊號**:起始標籤、內容、結束標籤擠在同一行(例:`/// 取得訂單`);結束標籤跟在內容尾巴後面沒有換行(例:`/// 取得訂單`);``、``、``、`` 同樣擠成一行;巢狀標籤(`` 內含 ``)沒有逐層換行與縮排。 +- **建議重構手法**:把每個標籤拆成三行——起始標籤一行、內容一行或多行、結束標籤一行;巢狀標籤逐層縮排;`` 這類帶屬性的標籤,屬性留在起始標籤那一行。 +- **注意**:只針對 XML 格式註解。JSDoc、docstring 沒有結束標籤,不適用本項。 + +### 5.8 專有名詞與變數標示 + +- **定義**:註解裡提到程式碼元素時,要用該語言註解格式的標示語法標起來,不能混在純文字裡。標示的目的是讓 IDE 與文件產生工具讀得懂,並在文件上呈現成程式碼樣式。 +- **偵測訊號**:XML 註解裡直接以純文字寫參數名、型別名、成員名或程式碼字面;JSDoc 或 docstring 裡以純文字寫變數名與型別名,沒有加反引號;標錯類別(例如拿 `` 標參數名、拿 `` 標型別)。 +- **建議重構手法**:依語言慣例補標示。 + + | 註解格式 | 對象 | 標示語法 | + | --- | --- | --- | + | XML | 變數、參數 | `` | + | XML | 型別、成員 | `` | + | XML | 程式碼字面、列舉值 | `null` | + | JSDoc、docstring | 變數、型別、程式碼字面 | 反引號 `` `orderId` `` | + +- **注意**:標示規則跟著語言慣例走,不是跟著個人喜好走。IDE 的跳轉與文件工具的交叉引用都靠這些標籤,標錯等於沒標。 + ## 第 6 組:淺模組(Shallow Module) - **定義**:介面複雜度相對於功能深度過高的模組——使用它要懂的事,跟自己寫差不多(出自《A Philosophy of Software Design》:好模組要「介面簡單、實作深」)。 @@ -162,4 +191,14 @@ | --- | --- | --- | | 高 | 會造成錯誤或已阻礙修改 | 吞掉異常、重複程式碼改漏、死碼誤導 | | 中 | 持續增加維護成本 | 巨型類別、臃腫函式、巢狀地獄、Couplers 全組 | -| 低 | 可讀性與一致性 | 命名、魔術數字、註解缺漏、文件編號夾帶、淺模組 | +| 低 | 可讀性與一致性 | 命名、魔術數字、註解缺漏、文件編號夾帶、淺模組、XML 標籤排版、專有名詞未標示 | + +第 5 組新增項目的級別另外標明,避免全部壓在「註解缺漏」一句話裡: + +| 項目 | 級別 | 理由 | +| --- | --- | --- | +| 5.1 缺條列式步驟與規則 | 中 | 讀的人要重讀整個實作才知道規則,維護成本直接上升 | +| 5.3 回傳值缺資料模型連結 | 低 | 型別名稱還查得到,只是多花幾秒 | +| 5.6 缺內含功能的導向連結 | 低 | 同上,影響的是查找速度 | +| 5.7 XML 標籤排版擠在同一行 | 低 | 純排版,不影響語意 | +| 5.8 專有名詞未標示或標錯 | 低 | 影響 IDE 跳轉與文件呈現,不影響執行 | From 57ac9cdcd960dc41e81e9b327b4529537d27f16d Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 27 Aug 2026 15:41:38 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat(swagger-detect):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=88=A4=E6=96=B7=E5=B0=88=E6=A1=88=E6=9C=89=E6=B2=92=E6=9C=89?= =?UTF-8?q?=E5=95=9F=E7=94=A8=20Swagger=20=E7=9A=84=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:新增 tools/swagger-detect.sh,判斷一個專案有沒有真的啟用 Swagger 文件。 涵蓋 dotnet、nodejs、python 三種技術棧,輸出 support=、stack=、package=、 config= 四類欄位;結束碼 0 支援、1 不支援、2 參數個數不對或專案路徑不存在。 Why:API 文件稽核只對產得出 Swagger 文件的專案有意義。支不支援如果交給 agent 自己看程式碼判斷,同一個專案可能這次說支援、下次說不支援。判定寫成腳本,呼叫端 讀結束碼分支就好,不必自己猜。 How:雙重確認,套件與設定缺一不算支援。第一關在套件宣告檔裡找已知的 Swagger 套件,第二關在原始碼裡找真的把 Swagger 接上去的呼叫或裝飾子。設定關鍵字一律 挑接線動作,不挑 import 或 require——光是引入套件不代表文件真的掛上去了。裝了 套件卻沒啟用的專案很常見,只看套件會誤判,讓稽核跑在一個根本產不出文件的專案 上。輸出刻意做成一行一個 key=value,呼叫端逐行讀就好。 Who:jsc-review 的 api-doc 技能,以及 jsc-sdlc 實作階段的收尾稽核。 --- tools/swagger-detect.sh | 170 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100755 tools/swagger-detect.sh diff --git a/tools/swagger-detect.sh b/tools/swagger-detect.sh new file mode 100755 index 0000000..0bdee25 --- /dev/null +++ b/tools/swagger-detect.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env sh +# swagger-detect.sh — 判斷一個專案有沒有真的啟用 Swagger(OpenAPI)文件。 +# 用法:swagger-detect.sh [專案路徑](預設目前目錄) +# +# 規則(雙重確認,缺一不算支援): +# 1. 套件:在套件宣告檔裡找得到已知的 Swagger 套件。 +# 2. 設定:在原始碼裡找得到實際把 Swagger 接上去的呼叫或裝飾子。 +# 只找到套件不算支援。裝了沒啟用的專案很常見,只看套件會誤判, +# 讓 api-doc 稽核跑在一個根本產不出文件的專案上。 +# 設定關鍵字一律挑「接線動作」,不挑 import 或 require。光是引入套件 +# 不代表文件真的掛上去了。 +# +# 涵蓋範圍: +# dotnet 套件 Swashbuckle.AspNetCore、NSwag.AspNetCore +# 設定 AddSwaggerGen、UseSwagger、AddOpenApiDocument、UseOpenApi +# nodejs 套件 swagger-ui-express、@nestjs/swagger、fastify-swagger(含 @fastify/swagger) +# 設定 SwaggerModule.setup、swaggerUi.setup、swaggerUi.serve、 +# register 進 fastify 的 swagger 外掛 +# python 套件 fastapi、flasgger、drf-spectacular +# 設定 FastAPI( 建立 app、Swagger( 掛上 flasgger、SPECTACULAR_SETTINGS、 +# SpectacularAPIView +# +# 輸出(純文字,一行一個 key=value,呼叫端逐行讀就好): +# 第一行永遠是 support=yes 或 support=no。 +# 之後每一組偵測到套件的技術棧輸出三行: +# stack=dotnet|nodejs|python +# package=命中的套件名,多個以半形逗號相連 +# config=命中的設定關鍵字,多個以半形逗號相連;沒命中就是空字串 +# 一個套件都沒找到時只有 support=no 一行。 +# 範例: +# support=yes +# stack=dotnet +# package=Swashbuckle.AspNetCore +# config=AddSwaggerGen,UseSwagger +# +# 結束碼: +# 0 支援(至少一個技術棧同時命中套件與設定) +# 1 不支援(沒有任何技術棧同時命中) +# 2 參數個數不對、專案路徑不存在,或環境缺 grep +# +# 護欄: +# 掃描一律跳過 node_modules、.git、bin、obj、dist、build、venv、.venv、 +# __pycache__、packages、vendor,避免把相依套件自己的原始碼當成專案設定。 +# 錯誤訊息一律印繁中到 stderr,正常輸出只走 stdout。 +set -u + +if [ "$#" -gt 1 ]; then + echo "用法:swagger-detect.sh [專案路徑]" >&2 + exit 2 +fi + +DIR="${1:-.}" + +[ -d "$DIR" ] || { echo "錯誤:找不到專案路徑 $DIR。請確認路徑後重試。" >&2; exit 2; } +command -v grep >/dev/null 2>&1 || { echo "錯誤:環境缺 grep,無法掃描。" >&2; exit 2; } + +EX1=--exclude-dir=node_modules +EX2=--exclude-dir=.git +EX3=--exclude-dir=bin +EX4=--exclude-dir=obj +EX5=--exclude-dir=dist +EX6=--exclude-dir=build +EX7=--exclude-dir=venv +EX8=--exclude-dir=.venv +EX9=--exclude-dir=__pycache__ +EX10=--exclude-dir=packages +EX11=--exclude-dir=vendor + +# scan <延伸正規表示式> <副檔名樣式…>:命中回 0,沒命中回 1。 +scan() { + pattern="$1" + shift + for inc in "$@"; do + if grep -R -l -E -i \ + "$EX1" "$EX2" "$EX3" "$EX4" "$EX5" "$EX6" \ + "$EX7" "$EX8" "$EX9" "$EX10" "$EX11" \ + --include="$inc" -e "$pattern" "$DIR" >/dev/null 2>&1; then + return 0 + fi + done + return 1 +} + +# append <既有清單> <新項目>:以半形逗號相連後印出。 +append() { + if [ -z "$1" ]; then + printf '%s' "$2" + else + printf '%s,%s' "$1" "$2" + fi +} + +SUPPORT=no +RECORDS="" + +# collect <技術棧> <套件清單> <設定清單>:有套件才留紀錄,兩者都有才算支援。 +collect() { + [ -n "$2" ] || return 0 + RECORDS="${RECORDS}stack=$1 +package=$2 +config=$3 +" + [ -n "$3" ] && SUPPORT=yes + return 0 +} + +# ── dotnet ──────────────────────────────────────────────────────────────── +DOTNET_PKG="" +DOTNET_CFG="" +for pkg in 'Swashbuckle\.AspNetCore:Swashbuckle.AspNetCore' 'NSwag\.AspNetCore:NSwag.AspNetCore'; do + if scan "${pkg%%:*}" '*.csproj' '*.fsproj' '*.vbproj' '*.props' 'packages.config'; then + DOTNET_PKG=$(append "$DOTNET_PKG" "${pkg##*:}") + fi +done +if [ -n "$DOTNET_PKG" ]; then + for cfg in AddSwaggerGen UseSwagger AddOpenApiDocument UseOpenApi; do + if scan "$cfg" '*.cs' '*.fs' '*.vb'; then + DOTNET_CFG=$(append "$DOTNET_CFG" "$cfg") + fi + done +fi +collect dotnet "$DOTNET_PKG" "$DOTNET_CFG" + +# ── nodejs ──────────────────────────────────────────────────────────────── +NODE_PKG="" +NODE_CFG="" +for pkg in swagger-ui-express @nestjs/swagger fastify-swagger @fastify/swagger; do + if scan "\"$pkg\"" 'package.json'; then + NODE_PKG=$(append "$NODE_PKG" "$pkg") + fi +done +if [ -n "$NODE_PKG" ]; then + # 每一項都是「接線動作」:掛路由或註冊外掛,不是 import。 + for cfg in 'SwaggerModule\.setup:SwaggerModule.setup' \ + 'swaggerUi\.setup:swaggerUi.setup' \ + 'swaggerUi\.serve:swaggerUi.serve' \ + 'register\(.*swagger:register(swagger)'; do + if scan "${cfg%%:*}" '*.js' '*.mjs' '*.cjs' '*.ts'; then + NODE_CFG=$(append "$NODE_CFG" "${cfg##*:}") + fi + done +fi +collect nodejs "$NODE_PKG" "$NODE_CFG" + +# ── python ──────────────────────────────────────────────────────────────── +PY_PKG="" +PY_CFG="" +for pkg in fastapi flasgger drf-spectacular; do + if scan "$pkg" 'requirements*.txt' 'pyproject.toml' 'Pipfile' 'setup.py' 'setup.cfg'; then + PY_PKG=$(append "$PY_PKG" "$pkg") + fi +done +if [ -n "$PY_PKG" ]; then + for cfg in 'FastAPI\(:FastAPI(' \ + 'Swagger\(:Swagger(' \ + 'SPECTACULAR_SETTINGS:SPECTACULAR_SETTINGS' \ + 'SpectacularAPIView:SpectacularAPIView'; do + if scan "${cfg%%:*}" '*.py'; then + PY_CFG=$(append "$PY_CFG" "${cfg##*:}") + fi + done +fi +collect python "$PY_PKG" "$PY_CFG" + +# ── 輸出 ────────────────────────────────────────────────────────────────── +echo "support=$SUPPORT" +[ -n "$RECORDS" ] && printf '%s' "$RECORDS" + +[ "$SUPPORT" = yes ] && exit 0 +exit 1 From dfaa66fedac5149bf610af820d0733cc2b9bc2d8 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 27 Aug 2026 15:41:38 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat(api-doc):=20=E6=96=B0=E5=A2=9E=20API?= =?UTF-8?q?=20=E6=96=87=E4=BB=B6=E7=A8=BD=E6=A0=B8=E6=8A=80=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:新增 skills/api-doc/SKILL.md。六步流程:偵測 Swagger 支援、不支援就回報 並停手、列出稽核範圍、分三個面向各開一個 sub agent 稽核、彙整去重排序、回報 發現。三個面向分別是狀態碼的回覆類型、參數說明與範例、資料模型遞迴。本技能 只回報「檔案:行號」、嚴重度與建議修法,不改程式碼。 Why:支援 Swagger 的專案要把控制器文件補全:所有可能出現的狀態碼都宣告回覆 類型,輸入輸出都要有說明與真實資料範例,參數是資料模型就每個屬性都套用、內含 模型再往下遞迴。這是 code-review 六組沒碰過的領域,跟第 5 組的原始碼註解契約 也不是同一件事,所以獨立成一支技能,不塞進既有的六組裡。 How:第一步跑 tools/swagger-detect.sh,讀結束碼決定走下去還是停手,不支援時 一個 sub agent 都不開,直接回報未啟用。範例優先取專案的真實資料,資料庫、 種子資料、測試夾具都算;真的取不到才依邏輯推導,並在文件裡標上「推導值」, 讓後面讀的人知道這個值沒被觀察過。取自資料庫的範例一律去識別化,個人資料不 進 Swagger 文件。分工另立一節:本技能只管 Swagger 文件屬性,原始碼註解契約 歸 code-review 第 5 組,同一個缺失不會被回報兩次。 Who:jsc-review 新增的 api-doc 技能,由 jsc-sdlc 的 implement 收尾時呼叫。 --- skills/api-doc/SKILL.md | 58 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 skills/api-doc/SKILL.md diff --git a/skills/api-doc/SKILL.md b/skills/api-doc/SKILL.md new file mode 100644 index 0000000..d2135ed --- /dev/null +++ b/skills/api-doc/SKILL.md @@ -0,0 +1,58 @@ +--- +name: api-doc +description: Audit an API project's Swagger/OpenAPI documentation: every returnable HTTP status code declares a response type, and every input and output carries a description plus a real data example, recursively down nested data models. Run after controller work or an implementation is complete, e.g. from jsc-sdlc implement, next to jsc-review:code-review. Detection runs first via tools/swagger-detect.sh; without both the Swagger package and its wiring, report unsupported and stop. The source comment contract belongs to jsc-review:code-review group 5; this skill covers Swagger document attributes only. Findings carry file:line, severity, and the fix; this skill never modifies code. +--- + +# api-doc + +Audit whether an API project's Swagger (OpenAPI) documentation is complete enough for a caller to integrate against it without reading the implementation. + +## When to run + +1. **After controller work is complete**: one controller or one related group of controllers is done. +2. **When an implementation is complete**: all todos of a work package that touched API endpoints are done. This is the call site in `jsc-sdlc:implement`, right next to `jsc-review:code-review`. +3. **Never on a project without Swagger**: step 1 below decides this in code, not by judgment. + +## Division of labor + +- This skill covers **Swagger document attributes only**: response type declarations, Swagger parameter descriptions, and Swagger examples. +- The comment contract — method description, layer tag, parameter description, return description, examples, nested-structure comments — belongs to `jsc-review:code-review` group 5 (`references/smells.md` 5.1 to 5.8). Never report the same gap twice; when a nested model already fails 5.5, leave it to `code-review`. +- Security, logic bugs, and test coverage belong to the CLI's built-in review. + +## Steps + +1. Detect Swagger support: run `tools/swagger-detect.sh {project path}` (defaults to the current directory). The script confirms package **and** wiring, so an installed-but-never-enabled project comes back unsupported. Read its exit code: `0` supported, `1` unsupported, `2` bad argument or missing path. Completion condition: the exit code and the `support=`, `stack=`, `package=`, `config=` lines are captured. +2. On exit code `1`, report the literal 「本專案未啟用 Swagger 文件,略過 API 文件稽核」 plus the `stack=` and `package=` lines the script printed, and stop. Spawn no sub agent. On exit code `2`, report the script's error message verbatim and stop; the caller supplies a valid project path and re-runs. Completion condition: the run has ended with an honest reason, or exit code `0` moved it to step 3. +3. List the audit scope: every controller in the project, or only the controllers touched by `git diff` when the caller asked for a scoped run. Completion condition: the controller list is non-empty and reported; an empty list ends the run with the literal 「無發現」. +4. Audit in three aspects, and every aspect **MUST run as a sub agent**; the three may run in parallel: + + | Aspect | Scope | + | --- | --- | + | 1 Status codes | For every action, every HTTP status code it can actually return — success, validation failure, authorization failure, not found, server error — has a declared response type and body schema (`ProducesResponseType`, `@ApiResponse`, FastAPI `responses=`, drf-spectacular `@extend_schema`). A status code the code can produce but the document never declares is a finding; so is a declared status code the code can never produce | + | 2 Parameter description and example | Every input parameter and every output field has a description and an example. Examples come from real project data first — query the project's database, seed data, or fixtures. Only when real data is unreachable, derive an example by logic and mark it as a derived value in the document itself | + | 3 Recursive data model | When a parameter or return value is a data model, aspect 2 applies to every one of its properties. A model containing another model recurses to the innermost layer. Walk in from the controller and follow the input and output types down | + + Instructions for each sub agent: read only, change nothing; report each finding as `file:line`, the aspect, severity, one sentence of evidence, and the concrete fix (which attribute to add, on which member). Findings are reported in Traditional Chinese. + + Completion condition: all three aspects have returned — an aspect with nothing to report still returns 「無發現」 for itself. +5. Merge the three aspects' findings: deduplicate by location, then sort by severity. Start this step only once all three have returned. Completion condition: every finding appears exactly once, ordered 高 → 中 → 低. +6. Report the finding list. **This skill never modifies code**; the caller decides what to fix. Completion condition: the report is handed to the caller and the fix decision is left to them. + +## Severity + +The 高、中、低 scale is the one in `references/smells.md`. Map this skill's findings onto it: + +| Finding | Severity | +| --- | --- | +| A returnable status code has no declared response type | 高 | +| A declared response type does not match the body the code returns | 高 | +| An input or output has no description | 中 | +| A data model property is missing from the recursive walk entirely | 中 | +| A placeholder example while real data was reachable | 低 | +| A derived example that is not marked as derived | 低 | + +## Notes + +- Examples taken from a database must be de-identified. Never put personal data into a Swagger document. +- 「推導值」 is the literal marker for a derived example; keep it in the document text so the next reader knows the value was never observed. +- When there are no findings, report the literal 「無發現」 explicitly; never leave the report empty. From 51c2705667c52093b31a37df5c0c56ef6693a7d7 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 27 Aug 2026 15:41:38 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat(review):=20code-review=20=E7=AF=84?= =?UTF-8?q?=E5=9C=8D=E6=94=B9=E7=82=BA=205.1=20=E5=88=B0=205.8=20=E4=B8=A6?= =?UTF-8?q?=E8=A3=9C=E4=B8=8A=E8=88=87=20api-doc=20=E7=9A=84=E5=88=86?= =?UTF-8?q?=E5=B7=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:skills/code-review/SKILL.md 的審查範圍表,第 5 組由原本一句 「smells.md group 5」改成明確的 5.1 到 5.8,並點名 5.6、5.7、5.8 三個新項目; Notes 加一行分工,Swagger 文件稽核歸 api-doc。README.md 新增 api-doc 的技能 小節,另補一張工具表格列出 swagger-detect.sh。 Why:sub agent 讀的是 SKILL.md 的審查範圍表,範圍表沒寫清楚,新增的 5.6 到 5.8 就不會被查。使用者讀的是 README.md,新技能與新工具沒列出來就找不到。 兩支技能都碰註解與文件,界線不寫明就會對同一個缺失重複回報。 How:範圍表的第 5 組直接列出三個新項目與各自的判準重點,完整清單仍指向 references/smells.md。Notes 寫明 api-doc 負責狀態碼的回覆類型、Swagger 參數 說明與範例,第 5 組只負責原始碼註解契約。README.md 的技能小節寫明偵測先行、 只裝套件沒掛接就停手;工具表格列出 swagger-detect.sh 的用途、輸出欄位與結束碼。 Who:jsc-review 的 code-review 技能與存取庫說明文件。 --- README.md | 10 ++++++++++ skills/code-review/SKILL.md | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 44a199b..4cf69ab 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,10 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安 對 git diff 進行六組壞味道審查,每組一個 sub agent 平行執行;回報 `檔案:行號`、嚴重度、建議重構手法,修正與否由呼叫端決定。第 2 組同時擋「文件編號夾帶」:註解只寫「為什麼這樣寫」,議題編號、wiki 頁編號、工作包編號、commit hash、`@` 提及、外部文件連結一律不進註解,清單看 `references/comment-scope.md`。diff 是空的就直接回報「無發現」,不開任何 sub agent;六組全部回覆才進入彙整,沒東西可報的那組也要回「無發現」。安全性與 bug 審查交給 CLI 內建 review,不重複。 +### `api-doc` + +稽核 API 專案的 Swagger 文件:每個可能回傳的 HTTP 狀態碼都要宣告回覆類型,每個輸入與輸出都要有說明與真實資料範例,並沿著巢狀資料模型逐層遞迴。控制器改完或實作完成時執行,例如由 `jsc-sdlc:implement` 呼叫,與 `jsc-review:code-review` 並列為兩關收尾稽核。先跑 `tools/swagger-detect.sh` 偵測,套件與掛接設定要雙重命中才算支援;只裝套件沒掛接就回報未啟用並停手,不開任何 sub agent。原始碼的註解契約歸 `jsc-review:code-review` 第 5 組,這支只管 Swagger 文件屬性與範例,兩支不重複回報。回報 `檔案:行號`、嚴重度與建議修法,本技能不改程式碼。 + ## 參考 @@ -37,6 +41,12 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安 | `references/smells.md` | 六組壞味道完整清單:定義、偵測訊號、建議重構手法、嚴重度分級;範例資料必須去識別化 | | `references/comment-scope.md` | 程式碼註解內容界線:禁止寫進註解的文件編號清單、允許項目與白名單、命中時的改法 | +## 工具 + +| 檔案 | 用途 | +| --- | --- | +| `tools/swagger-detect.sh` | 判斷專案有沒有真的啟用 Swagger。套件與設定雙重確認,缺一不算支援。輸出 `support=`、`stack=`、`package=`、`config=`;結束碼 0 支援、1 不支援、2 參數或路徑錯誤 | + ## 相關 domain - [`jsc-sdlc`](https://gitea.jsc.idv.tw/plugins/sdlc):實作階段完成後呼叫本審查 diff --git a/skills/code-review/SKILL.md b/skills/code-review/SKILL.md index b8a472f..fdb9cff 100644 --- a/skills/code-review/SKILL.md +++ b/skills/code-review/SKILL.md @@ -16,6 +16,7 @@ Review changed code against `references/smells.md` (from the book *Refactoring*) - 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 @@ -28,7 +29,7 @@ Review changed code against `references/smells.md` (from the book *Refactoring*) | 2 Obscurity | smells.md group 2, including 2.5 document reference leak — comments carrying issue ids, wiki page ids, work package ids, commit hashes, @ mentions, or external document links; the full banned and allowed lists live in `references/comment-scope.md` | | 3 Couplers | smells.md group 3 | | 4 Dispensables & Others | smells.md group 4 | - | 5 Comment contract | smells.md group 5 | + | 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 (``, ``, `` in XML; backticks in JSDoc and docstrings) | | 6 Shallow Module | smells.md group 6 | Instructions for each sub agent: read only, change nothing; check every changed line and its enclosing function or class against the group's definitions and detection signals in smells.md; report each finding as `file:line`, smell name, severity (高、中、低 per the smells.md scale), one sentence of evidence, and the suggested refactoring. Findings are reported in Traditional Chinese. From 8b5cc602dc403b0043ecac803bdc0d5f3ab6659c Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 27 Aug 2026 15:41:38 +0800 Subject: [PATCH 5/5] =?UTF-8?q?chore(manifest):=20=E4=B8=89=E4=BB=BD=20man?= =?UTF-8?q?ifest=20=E5=90=8C=E6=AD=A5=E5=8D=87=E7=89=88=E8=87=B3=200.0.6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:plugin.json、.claude-plugin/plugin.json、.codex-plugin/plugin.json 三份 manifest 的 version 由 0.0.5 改為 0.0.6。 Why:這批新增了 api-doc 技能與 swagger-detect.sh,也擴充了第 5 組的審查項目, 屬於功能異動。版本沒跟著升,各 CLI 端的外掛版本護欄就分不出新舊,已安裝的 使用者也收不到更新。 How:三份 manifest 只改 version 欄位,其餘欄位維持原樣,三處版本號保持一致。 Who:jsc-review 外掛的安裝與更新流程。 --- .claude-plugin/plugin.json | 2 +- .codex-plugin/plugin.json | 2 +- plugin.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index b813ab9..9d93fdf 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-review", - "version": "0.0.5", + "version": "0.0.6", "description": "程式碼審查:Refactoring 壞味道六組 + 註解規範 + 淺模組", "skills": "./skills", "author": { diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 5574084..e7b88cd 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-review", - "version": "0.0.5", + "version": "0.0.6", "description": "程式碼審查:Refactoring 壞味道六組 + 註解規範 + 淺模組", "skills": "./skills" } diff --git a/plugin.json b/plugin.json index 78becd3..8bfae14 100644 --- a/plugin.json +++ b/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-review", - "version": "0.0.5", + "version": "0.0.6", "description": "程式碼審查:Refactoring 壞味道六組 + 註解規範 + 淺模組", "skills": "./skills/" }