| name | plan-close |
| description | 結案前先跑文件漂移硬關卡(FAIL 擋、WARN 需明示放行),通過後蓋章 verified_at_commit、提交 Git、批次同步 plan.md 與 deploy.sql 到 Notion。當使用者提到 /plan-close、「feature 結案」、「同步 spec 到 Notion 並結案」時觸發此 Skill。 |
plan-close — 統一結案(漂移硬關卡 + 批次 Notion 同步)
結案 = 蓋章。順序固定且不可調換:
漂移檢查(唯一硬關卡)→ 通過 → 寫 verified_at_commit → git add -f + commit → Notion 同步 → 知識庫 → 結案狀態
為什麼關卡在這裡:/plan-build 時符號還在流動(誤殺率最高),此刻程式碼已穩定、誤殺最低;
而錯過這一刻,漂移的文件會被原樣推到 Notion 知識庫並長期腐爛 —— 把不可信的內容傳播出去比不同步更糟。
將 .spec/{slug}/plan.md 與 deploy.sql 一次性批次同步到 Notion,更新狀態,同步到知識庫,並提交到 Git。整個流程約 3-7 次 Notion API 呼叫(Bug 類型有 related_feature 時會多出關聯 Feature 頁面的 fetch + update,達到上限)。
v1 舊任務:.spec/{slug}/plan.md 不存在 → 這是 v1 結構,依
../../references/legacy-v1.md 的相容模式執行,並在開頭提示一次。
過渡期限定,到期本段連同該檔一併刪除。
設定目錄
依 plugin 根目錄 references/config-resolver.md(相對 SKILL.md 為 ../../references/)的漸進式載入邏輯讀取設定。本 Skill 需要:
- 第 1 層:
config.md(Notion IDs — 功能設計庫 / 專案資料庫)
- 第 2 層:
projects/{repo-id}.md(專案對應、技術棧 ID)
- 第 3 層:
stacks/{id}.md(技術棧定義,用於設計庫同步)
Bug 類型還需 bug-workflow 設定檔(~/.claude-company/bug-workflow-config.md 或 ~/.claude/bug-workflow-config.md)。
前置條件
- 已使用
/plan-start 建立任務
- 已完成規劃和開發(
.spec/{slug}/plan.md 各節有內容)
- 程式碼已 commit
前置檢查:參照 plugin 根目錄 references/prerequisites.md(相對 SKILL.md 為 ../../references/)執行完整前置檢查(CLAUDE.md + 設定目錄 + 專案註冊)。
紀律護欄
紀律護欄:../../references/discipline-preamble.md(通用紀律)+ ../../references/anti-rationalizations.md「plan-close 專用」+ ../../references/boundaries.md「plan-close」段。
🔴 本 skill 最容易出現的合理化是「漂移只有一兩筆,先同步再說」—— 那正是文件變不可信的機制,不可放行(規則見『漂移硬關卡』一節)。
流程
1. 定位活躍任務
參照 plugin 根目錄 references/plan-common.md(相對 SKILL.md 為 ../../references/)的「定位活躍任務」(crew-state.py list)。
type(feature/bug)與 name 從 .spec/{slug}/plan.md frontmatter 讀取
notion.page_id / notion.url 從 state.json 讀取(crew-state.py list --slug {slug} --format json)
2. 清點要同步的產物
.spec/{slug}/ 只有三種產物,逐一確認(✅/❌):
| 產物 | 用途 | 缺少時 |
|---|
plan.md | Notion「📝 規劃文件」區塊的來源(含檢查報告摘要) | 🔴 BLOCK — 沒有它就不是 v2 任務,見『邊界情況』 |
deploy.sql | Notion「🗄️ 部署 SQL」+初始化「🚀 部署狀態」(見 5-2a) | DB_REQUIRED=false 時正常,跳過該區塊 |
state.json | Notion Properties 與結案狀態的來源 | 跑 crew-state.py rebuild --slug {slug} 修復 |
.cache/、screenshots/、evidence/ 都在 .gitignore 內:不進版控、不同步 Notion。
review/security/verify 的報告依設計不落檔 —— 要同步的是 plan.md「檢查報告摘要」節那幾行,以及 state.json 的 results.*。
3. 從 Git 擷取變更摘要
從專案設定檔讀取 prod_branch(PROD 分支),用作 merge-base 計算 diff:
git branch --show-current
git log --oneline $(git merge-base HEAD {prod_branch})..HEAD
git diff $(git merge-base HEAD {prod_branch})..HEAD --stat
git diff $(git merge-base HEAD {prod_branch})..HEAD
若 prod_branch 未設定(舊專案),回退邏輯:先取 origin/HEAD 指向的分支,若無則依序嘗試 production → master → main。
根據 CLAUDE.md 的架構描述,產出分層變更摘要。
4. 智慧判斷目標狀態
狀態推斷邏輯:
- 使用者輸入含「完成」、「done」、「上線」、「結案」→
已完成
- 含「測試」、「QA」→
測試中
- 無法判斷 → 詢問,預設
測試中
5. 漂移硬關卡(唯一硬關卡,🔴 不可跳過)
必須在 git add -f 與任何 Notion 呼叫之前執行。 這是全流程唯一會擋下結案的檢查。
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/check-spec-drift.py" \
--spec .spec/{slug}/plan.md --format json
echo "exit=$?"
依 exit code 分流(🔴 不可自行改判,也不可只憑 JSON 是否為空就當通過):
| exit | 意義 | 處置 |
|---|
0 | 無 FAIL、無 WARN | ✅ 通過 → 進『蓋章』一節 |
1 | 有 FAIL(D1 錨點檔案不存在/D2 符號不在檔內),或 WARN 被 drift_policy: strict 升級 | 🔴 阻擋結案,照下方「FAIL 的回報格式」列出並引導 /plan-drift |
2 | 只有 WARN(D4 hash、D5 表無引用、D6 文件落後程式碼、D7 缺蓋章/零錨點) | ⚠️ 需使用者逐筆明示放行(見下方) |
3 | 環境問題(非 git 工作區、verified_at_commit 不在歷史、檔案讀不到) | 🔴 阻擋蓋章,回報「無法檢查」+原因+script 的「修法:」原文 |
FAIL 的回報格式(exit 1)
🔴 結案已擋下:文件與程式碼不一致({N} 筆 FAIL)
• [D2] plan.md:23 `@code:src/.../LoginAttemptService.java#recordFailure`
檔內找不到 recordFailure
修法:{原文照登 script 的「修法:」那一行}
• [D1] plan.md:31 `@code:src/.../OldService.java`(git 偵測到改名,可自動修)
下一步:
/plan-drift --fix # 機械型(改名、行號)自動修
/plan-drift # 語意型逐條確認(符號消失常代表決策變了)
修完重跑 /plan-close。
- exit 1 但 JSON 內
level 全無 FAIL → 是 WARN 被 drift_policy: strict 升級,照 WARN 流程逐筆放行即可,不要去找不存在的 FAIL。
- 🔴 不得在本 skill 自行改錨點、自行跑
--fix、或建議使用者改 drift_policy: off 來繞過。修復迴路是 /plan-drift 的職責(它有使用者逐條確認機制)。
WARN 的放行流程(exit 2)
逐筆顯示,一次問一條,使用者明示才放行(不提供「全部放行」選項 —— 那等於沒問):
⚠️ [D6] plan.md 的錨點檔案自 {verified_at_commit} 後有變更(3 個檔案),plan.md 未同步更新
影響:文件可能落後程式碼;蓋章後這份文件會被同步到 Notion 知識庫
修法:{原文照登 script 的「修法:」那一行}
[1] 放行(我確認這些變更不影響決策紀錄) [2] 中止,我先去 /plan-drift 處理
- 每筆都選 1 → 視為通過,繼續『蓋章』一節,並在最終回報列出「已放行的 WARN」清單
- 任一筆選 2 → 終止 plan-close(不寫蓋章、不 commit、不呼叫 Notion)
ENV 項目一律單獨回報
JSON 中 level 為 ENV(code = E1)的項目代表「這次沒檢查成」,可能與 FAIL 並存(此時 exit 為 1)。
每次都要掃有無 ENV 項目,不能只看 exit code。🔴 ENV 不得說成「有漂移」,也不得說成「檢查通過」。
drift_policy: off 的任務
script 會明示「已跳過未檢查」。此時不蓋章(沒檢查就沒有承諾),照常結案,並在回報中寫「本任務 drift_policy: off,未做漂移檢查」,🔴 不得寫成「全部通過」。
5.5 蓋章 verified_at_commit(只有通過才做)
前置條件:『漂移硬關卡』一節得到 exit 0,或 exit 2 且每筆 WARN 都經使用者明示放行。
exit 1、exit 3、有 ENV 項目、drift_policy: off → 不蓋章。
git rev-parse --short HEAD
date +%F
用 Edit 更新 .spec/{slug}/plan.md frontmatter 的兩行(🔴 只改這兩行,不動其他 frontmatter 欄位、不整檔改寫):
verified_at_commit: 3f2a91c
verified_at: 2026-07-28
值一律用上面兩個指令的實際輸出,不憑印象填。
單一寫入點:verified_at_commit 全流程只有 /plan-drift 與本 skill 能寫。
/plan-build、/plan、/plan-review、/plan-security、/plan-verify 一律禁止 —— 剛改完程式碼自己蓋章等於作廢。
5.6 部署步驟數登記(deploy.sql 存在時)
deploy-checklist.md 已廢除(它是 deploy.sql 的 derived view,會自己過期)。部署進度改記在 state.json:
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/crew-state.py" set --slug {slug} \
--deploy-total {deploy.sql 的 -- Step N 數量} --deploy-confirmed 0
deploy.sql 無 -- Step N 註解無法分段 → --deploy-total 1(整份視為一步),並在回報中提醒。
實際執行結果由 /plan-deploy-confirm 回報時更新 --deploy-confirmed。
5.7 提交 .spec/ 到 Git(在 Notion 同步之前)
蓋章後先進版控再同步 Notion —— 順序反了會出現「Notion 有、git 沒有」的狀態,且 commit 的內容不含蓋章。
plan-start 在 .gitignore 寫入的是整個 .spec/(排除目錄),此時用 !.spec/{slug}/ 反向取消忽略無效(Git 不會遞迴進入已被排除的目錄),因此改用 git add -f 強制加入:
git add -f .spec/{slug}/plan.md
git add -f .spec/{slug}/deploy.sql
git add -f .spec/{slug}/state.json
git commit -m "docs: 新增 {slug} 規劃文件(plan.md + deploy.sql)"
🔴 逐檔指定,不要 git add -f .spec/{slug}/:整個目錄會把 .cache/、screenshots/、evidence/ 一起強制加入(-f 會蓋掉 gitignore),binary 與一次性暫存不該進版控。
commit 後跑 git status --short .spec/{slug}/ 確認沒有意外被加入的檔案。
6. 一次性 Notion 批次更新(只在漂移關卡通過後執行)
6-1. Fetch 現有頁面(1 次 notion-fetch)
使用 state.json 的 notion.page_id fetch 頁面。
6-2. 更新頁面內容(1 次 notion-update-page content)
同步映射表(v2,來源只有 plan.md + deploy.sql + git):
區塊標題以 plugin 根目錄 references/notion-page-template.md(相對 SKILL.md 為 ../../references/)的模板為準。
| Notion 區塊 | 來源 | 條件 |
|---|
| 📋 需求描述 | plan.md「目標與範圍」+「驗收條件」(AC-n 原樣) | 必有 |
| 📐 技術規格 | plan.md「決策紀錄」+「已知取捨與風險」+「指路」(錨點原樣,不展開內容) | 必有 |
| 🗄️ 資料庫設計 → 遷移 SQL | deploy.sql 全文 | deploy.sql 存在 |
| 🚀 部署狀態 | 由 deploy.sql 的 -- Step N 初始化(見 6-2a),每筆預設「待執行」 | deploy.sql 存在 |
| 📁 程式碼清單 | git diff --name-status +『從 Git 擷取變更摘要』一節的分層變更摘要 | 必有 |
| 📝 開發日誌 | plan.md「檢查報告摘要」節的條目 + 追加結案紀錄:
### [{日期}] 開發完成
- **分支**:{branch}
- **Commit 數**:{N}
- **蓋章**:verified_at_commit {sha}
- **變更摘要**:{分層變更摘要} | 必有 |
- 原樣搬運,不重寫:章節內容照抄,不要「順手潤稿」或補充 —— 那會讓 Notion 與 plan.md 講不同的話。
- 📋 需求描述 的原始需求原文要保留:使用者貼的長需求原文留在該區塊(plan.md 只放萃取後的目標與驗收條件)。同步時附加在原文之後,不覆蓋原文。
- 對應表兩處要一致:
/plan-sync(中途同步)用同一組區塊。改這張表時要同步確認 plan-sync 的版本,否則同一份 plan.md 會在中途同步與結案同步落到不同區塊。
🔴 不再同步(來源檔案已廢除):spec/db/arch 三份設計文件、上線前置作業 checklist、檔案清單文件、review/security/verify 全文報告。
需要細節的人看 plan.md 的錨點與 git 本身 —— 抄一份到 Notion 就是製造第二份會漂移的副本。
state.json 的 results.review / results.security / results.verify 只用來核對摘要行的數字是否一致,本身不同步。
只有蓋過章的內容才推上去:本節必須在『漂移硬關卡』通過(exit 0 或 WARN 全放行)後才執行。
舊流程把本地文件原樣同步、不校對,等於把不可信的內容傳播到知識庫,這是本次重構要解掉的第三個症狀。
6-2a. 建立「🚀 部署狀態」區塊(僅 Feature 且 deploy.sql 存在)
deploy.sql 寫入「部署 SQL」子區塊後,一併建立「🚀 部署狀態」追蹤區塊,作為 /plan-deploy-confirm 回流機制的寫入標的。此處只初始化(每筆預設「待執行」),實際執行結果由 /plan-deploy-confirm 之後覆寫。
依 -- Step N:{描述} 註解切割 deploy.sql,每個 Step 產生一列,狀態一律填「⏳ 待執行」:
## 🚀 部署狀態
### 最後執行:(尚未執行)
| Step | 描述 | 狀態 | 執行時間 | 備註 |
|------|------|------|---------|------|
| 1 | 建立 users 表 | ⏳ 待執行 | — | — |
| 2 | 建立 email 唯一索引 | ⏳ 待執行 | — | — |
### 執行紀錄
(尚無執行紀錄,執行後由 /plan-deploy-confirm 追加)
### 備註
(無)
契約:區塊標題固定為「🚀 部署狀態」、狀態詞固定用「待執行」,與 /plan-deploy-confirm 讀寫的名稱一致。若 deploy.sql 無 -- Step N 註解無法分段,退回單一列(Step 1 = 整個 deploy.sql,狀態「待執行」)。
表格內容與 state.json 的 deploy.steps_total(見『部署步驟數登記』一節)必須一致。
語意一致性註記:Notion「狀態」欄位值(本步驟『智慧判斷目標狀態』寫入的 測試中/已完成)與本地 state.json 的 steps.close.status = done(見『結案狀態』一節)是兩套獨立語意,不可混用。/plan-deploy-confirm 的 Notion 搜尋以「🚀 部署狀態含待執行」為主判準,不依賴 Notion 狀態欄位值。
Bug 類型:
Bug 頁面用的是 /plan-start 的 Bug 模板(🔴 問題描述 / 🔍 調查過程 / 🧠 根因分析 / ✅ 修復方案 / 🧪 驗證 / 📝 經驗教訓)。內容一律取自同一份 plan.md:
| Notion 區塊 | 來源 |
|---|
| 🧠 根因分析 | plan.md「決策紀錄」節中根因判定的條目(含被否決的假設與否決理由) |
| ✅ 修復方案 | plan.md「指路」節的修改落點錨點 + git diff 分層摘要 |
| 🧪 驗證 | plan.md「檢查報告摘要」節的 verify/review/security 摘要行 |
| 📝 經驗教訓 | plan.md「已知取捨與風險」節 + 決策紀錄中「為什麼一開始會錯」的條目 |
🔴 不再有 investigation.md / root-cause.md / fix.md / log.md 這些獨立檔案。
6-3. 更新 Properties(1 次 notion-update-page properties)
Feature:
| 欄位 | 值 |
|---|
| 狀態 | 『智慧判斷目標狀態』判斷結果 |
| 開發階段 | 測試中 |
| 修復分支 | 當前 Git branch |
Bug:
| 欄位 | 值 |
|---|
| 狀態 | 『智慧判斷目標狀態』判斷結果 |
| 根因分類 | 從 plan.md「決策紀錄」節的根因決策條目推斷(邏輯錯誤/資料異常/設定問題/第三方API/效能/權限/前端UI) |
| 修復分支 | 當前 Git branch(state.json 的 git.branch) |
7. 同步到知識庫
Feature → 功能設計庫(1 次 notion-create-pages)
同步邏輯:
| 欄位 | 值 |
|---|
| Name | 功能標題 |
| Tags | 自動推測(API/報表/標籤/推播/排程 等) |
| 設計類型 | 依 plan.md 走過的 pass 判斷(state.json 的 steps.spec/db/arch 哪些是 done) |
| 技術棧 | 設定檔中的技術棧 ID |
| 參考連結 | Notion 頁面 URL |
| 專案資料庫 | 同一專案 |
知識庫條目的內容以 plan.md 的決策紀錄為主體(那是唯一不會過期的資產)。🔴 不要把程式碼事實(欄位、簽章、DDL)抄進知識庫。
Bug → Bug 知識庫(1 次 notion-create-pages)
複用 bug-close 的同步邏輯:
| 欄位 | 值 |
|---|
| Name | Bug 標題 |
| Tags | 自動推測 |
| 難易度 | 依修改檔案數和行數判斷 |
| 專案資料庫 | 同一專案 |
| 參考連結 | Notion 頁面 URL |
8. Feature-Bug 關聯(僅 Bug 且有來源 feature)
來源 feature 記在 Bug 的 plan.md「指路」節(由 /plan-start --related 寫入,格式 - 來源 feature:{slug}(Notion:{URL})):
- 用
crew-state.py list --all --format json 取得該 feature 的 notion.page_id
notion-fetch 取得關聯 Feature 的 Notion 頁面(1 次)
- 在「📝 開發日誌」區塊追加:
### [{日期}] 🔴 相關 Bug
- Bug: {Bug 名稱}({Bug Notion URL})
- 根因: {Bug plan.md「決策紀錄」節的根因條目摘要}
- 修復: {Bug plan.md「指路」節的修改落點摘要}
notion-update-page 更新 Feature 頁面(1 次)
9. 結案狀態(唯一權威 state.json)
Notion 同步完成後寫回狀態,不手寫任何欄位:
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/crew-state.py" set --slug {slug} \
--step close --status done --phase close \
--last-commit "$(git rev-parse HEAD)" \
--mirrored-status "{Notion 上的狀態字串,例:測試中}" --synced-now
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/crew-state.py" validate --slug {slug} --expect-phase close
steps.close.status = done 就是「已結案」的唯一判準;/plan-status、/plan-next、SessionStart 提醒都讀這裡。
- 舊流程的任務索引檔與 README frontmatter 的狀態欄位皆已廢除 —— 任務清單由
crew-state.py list 即時掃 state.json 生成,沒有快取可漂移。
--synced-now 記錄 notion.last_synced_at;--mirrored-status 記錄 Notion 上呈現的狀態(供下次比對,衝突時本地贏)。
- 不刪除
.spec/{slug}/ 目錄,保留供未來 Bug 關聯匹配。
state.json 已在『提交 .spec/ 到 Git』一節被 commit,此處的更新屬結案後的狀態變化,
使用者可自行決定要不要再補一個 commit(/plan-status 讀工作區檔案,不受影響)。
10. 回傳結果
結案完成!
🔍 漂移檢查:exit {0|2}({錨點全部有效 / N 筆 WARN 經使用者放行 / drift_policy: off 未檢查})
🔖 蓋章:verified_at_commit {sha}({日期}){未蓋章時改為「未蓋章(原因)」}
📁 已提交到 Git:plan.md{、deploy.sql}、state.json
📊 Notion 頁面:{URL}(已更新)
📚 知識庫:{知識庫條目 URL}(已同步)
{📎 Feature 關聯:已更新 {來源 feature slug} 的開發日誌}
{🗄️ 部署步驟:{N} 個 Step 待執行 → 之後用 /plan-deploy-confirm 回報}
✅ 狀態:steps.close = done
Notion API 呼叫統計:{N} 次(fetch: 1, update: 2, create: 1{, 關聯更新: 2})
{已放行的 WARN(逐筆列出,含使用者放行理由)}
後續事項:
📋 測試驗證:在 Notion 頁面勾選驗證項目
🔀 Git 合併:{根據 CLAUDE.md Git Flow 產出合併建議}
何時不用
close 組 + sync 組 —— feature/.spec 任務結案用本 skill;bug 型結案用 /bug-close;未結案的中途同步用 /plan-sync。
- bug 型任務結案 → 改用
/bug-close
- 未結案的中途同步 → 改用
/plan-sync
- 更新單一 bug 頁 → 改用
/bug-update
- 部署 SQL 執行回報 → 改用
/plan-deploy-confirm
- 只想檢查/修錨點漂移,還不打算結案 → 改用
/plan-drift
Gotchas
- 關卡順序不可調換:漂移檢查 → 蓋章 →
git add -f → Notion 同步。任何「先同步、之後再修文件」的變體都會把不可信內容推上知識庫,而那正是使用者最在意的症狀。
- exit code 才是判準,不是 JSON 看起來乾不乾淨:D3(行號位移)是 INFO,不影響 exit code;只看 JSON 有沒有項目會誤判。反過來,exit 1 但無 FAIL 代表 WARN 被
drift_policy: strict 升級。
- exit 3 不是漂移:環境問題代表「這次沒檢查成」。把它說成「有漂移」或「檢查通過」都是假資訊,一律原文照登 script 的「修法:」那行,並且不蓋章。
- 蓋章是承諾,不是儀式:
verified_at_commit 只有 /plan-drift 與本 skill 能寫,且必須在檢查真的通過之後。這個欄位一旦被隨手蓋,整套漂移偵測就失去意義(下次 D6 的比較基準也會錯)。
- 一次 update_content 的大小限制:Notion API request body 約 2MB 上限。v2 只同步 plan.md(≤100 行)+ deploy.sql,通常遠低於上限;
deploy.sql 特別大時才需分批呼叫 update_content。
- Bug 類型需讀取兩個設定檔:知識庫 ID(Bug 知識庫)在 bug-workflow 設定檔中,只讀 feature-workflow 設定檔會靜默跳過知識庫同步。Bug 類型結案時,兩個 workflow 的設定檔都要讀取。
- 提交 .spec/ 用
git add -f,但要逐檔指定:plan-start 在 .gitignore 忽略整個 .spec/,而 Git 無法用 !.spec/{slug}/ 反向取消對「已排除目錄」的忽略(re-include 對已被排除目錄下的內容無效),故必須用 -f;力求不改動 .gitignore,避免規則順序踩坑。但 -f 對整個目錄會連 .cache/、screenshots/、evidence/ 一起強制加入 —— 只逐檔加 plan.md / deploy.sql / state.json。強制加入後檔案即成 tracked,後續修改 Git 會正常追蹤。
- Notion 呼叫次數統計:基本情況 3-5 次,但 Bug 有來源 feature 時會多 2 次(fetch + update 關聯 Feature 頁面),實際可達 7 次。回傳結果的統計數字要如實反映。
邊界情況
notion.page_id 為空:建議先用 /plan-sync 建立 Notion 條目
- plan.md 不存在(v1 舊任務,只有 README.md):本 skill 的 v2 流程不適用 —— 明說「該任務仍是 v1 格式」,不要當成通過、也不要跑漂移檢查(沒有錨點可檢查)
- plan.md 存在但零錨點:script 回 D7 WARN(過渡期),照 WARN 流程請使用者放行;放行後照常蓋章
drift_policy: off:不檢查、不蓋章,照常結案,回報明寫「未檢查」
check-spec-drift.py 回 exit 3:阻擋蓋章,回報「無法檢查」+原因;使用者修好環境後重跑
- diff 過大(> 500 行):僅摘要檔案清單和分層變更
- 知識庫 ID 為空:跳過知識庫同步
- 來源 feature 的 Notion 頁面不存在:跳過關聯更新,提示使用者
- Notion API 失敗:顯示已完成和失敗的步驟,建議用
/plan-sync 重試(此時 git commit 與蓋章已完成,不需重跑漂移檢查)
- CLAUDE.md 無 Git Flow 描述:使用通用提示