| name | oops |
| description | 踩坑經驗整合入口(查 + 寫,跨 consumer 共享)。Use when 升 npm 套件大版(升前/升後各查一次)、看到 cryptic runtime error(含「while capturing another error」「Cannot read properties of undefined」等通用訊息)、動 evlog / audit / Supabase RLS / Workers config / nuxt-security / Better Auth / supabase-js、跨 consumer 散播某 fix 前 → 先查經驗庫;或 user 表達踩到坑、被糾正、解完問題想記下來、session 結束想補登 missed lesson → 走新增分流;或 CWD = ~/offline/clade 且 user 未帶具體 error,想分析 consumer 累積貢獻、評估 clade 標準層該怎麼補 → 走 Mode D self-improvement sweep。SoT 在 ~/offline/clade/docs/pitfalls/,查詢走 codebase-memory-mcp search_code w/ path_filter="^docs/pitfalls/"。 |
| effort | medium |
| license | MIT |
| metadata | {"author":"clade","version":"1.0"} |
/oops — 踩坑經驗整合入口(跨 consumer 共享,查 + 寫)
繁體中文
核心命題:各 consumer 跑同一套標準(evlog / Supabase / Cloudflare Workers / nuxt-security / supabase-js / vite-plus / Better Auth / vue / nuxt / pinia),任一依賴升版或 contract 變更時 bug 會以同樣型態散落各 consumer。本 skill 是唯一對外入口,提供兩個 mode:
- Mode A 查詢:遇到問題先查 clade 經驗庫,命中 → 直接套 fix recipe(節省 debug 時間)
- Mode B 新增:踩到新坑 → 沉澱到中央庫,避免重踩 + 跨 consumer 散播警示
- Mode C handoff sweep:被 /handoff 呼叫,掃 session 內 missed lessons
- Mode D clade self-improvement sweep(clade-only):在 clade session 主動掃 pitfalls + digest + signals + 各 consumer 狀態,分析跨 consumer 反覆出現的 pattern,輸出「clade 標準層該怎麼補」的 candidate list 進
tasks/<date>-clade-improve-sweep.md
此 skill 優先於個別 skill 內嵌的踩坑指示。
SoT 與工具鏈
- 檔案 SoT:
~/offline/clade/docs/pitfalls/(只在 clade,不散播副本到 consumer)
- 機器 SoT:YAML frontmatter(lifecycle / impact / prevention 狀態都從 frontmatter 解析;markdown body 是呈現層)
- 查詢入口:codebase-memory-mcp(已 indexed clade project)
- 模板:
~/offline/clade/vendor/snippets/pitfalls/TEMPLATE.md
- Tags 詞彙表:
~/offline/clade/docs/pitfalls/tags.yml
- Audit script:
~/offline/clade/scripts/pitfalls-audit.mjs
- 本 skill 散播給 consumer 作入口指引;SoT 知識本體不散
Mode A:查詢經驗庫(預設行為)
何時主動查
| 情境 | 觸發 |
|---|
| 升某個 npm 套件大版(major / minor) | 升版前 + 升版後各查一次 |
| 看到 cryptic runtime error(含「while capturing another error」「Cannot read properties of undefined」等通用訊息) | 先查 pitfalls 是否已記錄 |
| 動 evlog / audit / Supabase RLS / Workers config / nuxt-security / Better Auth / supabase-js | 對應主題 pitfall 先看 |
| 跨 consumer 散播某 fix 前 | 確認該坑是否已記錄;若無 → 進 Mode B 新增 |
怎麼查(用 mcp,NEVER Read 整個目錄)
MUST 用 regex path_filter:
mcp__codebase-memory-mcp__search_code(
pattern = "<關鍵字>",
project = "Users-charles-offline-clade",
path_filter = "^docs/pitfalls/"
)
path_filter 是 regex,不是 glob。path_glob 在 mcp tool silently ignored — 寫了不會報錯但 filter 不生效,會撈到全 clade(這是踩過的坑)。
命中後若需要完整內文:
- 條目通常 < 200 行 → MAY 直接
Read 該檔
- 想再縮小範圍 → 用
search_code 換更窄 pattern
- NEVER 依賴
get_code_snippet 對 markdown module retrieval(不一定穩)
Scale 策略(大量累積後 token 控制)
mcp 向量搜尋天生 scale:search_code 只回相關 chunk 不 dump 全部,5 條到 500 條成本曲線平緩。額外配套:
- active vs archive 拆兩段查:先查 active(< 90 天),miss 才掃
_archive/YYYY-MM/;archive 也在 index 內但匹配優先級低
- tag-first 過濾:query 含 package 名(如
evlog@^2.17.0)→ 先用 pattern="<pkg-name>" 命中 frontmatter affects.packages,再展開內文
- 絕不 Read 整個目錄:路徑列舉 / overview 走
docs/pitfalls/README.md 的 index section,不 ls docs/pitfalls/ + Read 每個
進入 session 前置確認(每個 consumer 首次用)
第一次在 consumer session 使用本機制前MUST:
mcp__codebase-memory-mcp__list_projects()
確認 Users-charles-offline-clade 在清單內。若不在 → 跑:
mcp__codebase-memory-mcp__index_repository(
repo_path = "/Users/charles/offline/clade"
)
之後 search_code 才能命中。
MCP 缺失時 graceful degrade(fallback)
consumer 端若 .mcp.json 沒含 codebase-memory-mcp server 或 binary 未裝,MUST fallback 用 rg 直接掃 clade 路徑(禁止跳過知識庫查詢):
rg --type md "<關鍵字>" ~/offline/clade/docs/pitfalls/
同時提示使用者補 .mcp.json 並重啟 AI Agent session(CLI 限制)。
查無結果時
若 search_code 0 命中:
- 不假設「沒人踩過」就直接動手。換關鍵字(套件版本、錯誤訊息變體、相關 API)再查一次,至少 2 組
- 仍 0 命中 → 視同新坑,動手解決後MUST 進入 Mode B 新增條目
Mode B:新增條目
Hard rule — 合格 pitfall 四條件
每筆條目MUST包含以下四項,audit script 會 block 缺項條目:
- Root cause — 一句話 + 鏈式分析,引用具體版本 / API contract
- Detection — 可執行的 grep regex 或 mcp
search_code pattern(不是描述「該怎麼找」而是給命令)
- Fix recipe — 最小可重現修法(能 copy-paste)
- Prevention decision — 至少一條 prevention candidate 有明確 status(
accepted / rejected / implemented),不能全部停在 candidate
四條件不齊備時的輕量降級
不夠資格 pitfall 不代表不該記錄;改走以下三層分流,未來資訊收斂後可回來升級:
| 情境 | 寫到哪 | 觸發 |
|---|
| 個人偏好 / 跨專案沿用的行為更正 / user 糾正 Claude | auto-memory(feedback type) | user 糾正用詞、強調某做法、表達偏好 |
| 只給當前 repo 的 self-improvement lesson | <consumer>/tasks/lessons.md | 一次 session 內的學到的 pattern,且只對當前 repo 有效 |
| consumer 自家業務規約 | <consumer>/.claude/rules/local/<topic>.md | 跨 session 的 consumer-specific rule,但跟其他 consumer 無關 |
降級寫法不走以下 Step;條目資訊收斂後可回來升級成 pitfall。
NEVER 新增 pitfall:one-off typo、純業務邏輯 bug、純設計問題、TD / follow-up、設計討論、歷史 wave。
Step 1 — Dedupe(強制 ≥ 2 組關鍵字查詢)
MUST 在寫條目前用 mcp 查 clade 至少 2 組關鍵字,確認沒重複(沿用 Mode A 查詢 SOP):
mcp__codebase-memory-mcp__search_code(
pattern = "<關鍵字1:套件名 + 版本>",
project = "Users-charles-offline-clade",
path_filter = "^docs/pitfalls/"
)
mcp__codebase-memory-mcp__search_code(
pattern = "<關鍵字2:錯誤訊息 token 或 API 名>",
project = "Users-charles-offline-clade",
path_filter = "^docs/pitfalls/"
)
若命中既有條目:
- 完全重複 → STOP,回報該條目 id,由使用者決定要更新既有條目(加 cross_consumer scan 結果 / 新 prevention)還是放棄
- 相關但不重複 → 記下 id,後續寫進新條目的
related: [] frontmatter
MCP 缺失時 fallback:
rg --type md "<關鍵字>" ~/offline/clade/docs/pitfalls/
並提示使用者補 .mcp.json + 重啟 AI Agent session。
Step 2 — 收集 frontmatter
從 ~/offline/clade/vendor/snippets/pitfalls/TEMPLATE.md copy frontmatter skeleton。13 個必填欄位 + 規約:
| 欄位 | 來源 | 規約 |
|---|
schema_version | 固定 1 | — |
id | 推導自檔名 slug | pitfall-<kebab-slug>,與檔名一致 |
status | 預設 open | 新建一律 open |
severity | 從 user 對話推 | critical / high / mid / low |
discovered | 當天 ISO date | — |
discovered_at | 觸發 consumer 名 | registry/consumers.json 內任一 consumer_id(role=consumer 或 clade) |
last_verified | 當天 ISO date | 同 discovered |
affects.packages | 從 stack trace 推 | format: <pkg>@^<ver> |
affects.features | feature tag | 從 tags.yml controlled vocabulary |
tags | controlled vocabulary | MUST 在 docs/pitfalls/tags.yml 註冊;1-6 個 |
detection.mcp_patterns | 可執行 search_code pattern | MUST 用 path_filter regex,NEVER path_glob |
detection.grep_patterns | 可執行 grep 命令 | command_ref 指向 markdown body 段落 |
cross_consumer_impact | 每個 consumer 都列 | 走 Step 3 自動填 |
prevention | candidate list | 至少 1 條,MUST 有 status |
references | session + commits + upstream | sessions 必填 |
Agent 自填,不問 user:schema_version / status / discovered / last_verified / id(檔名推)/ affects(stack trace 推)
問 user 才能決定:severity(business impact 判斷)/ wontfix_reason(若 status = wontfix)/ prevention.status = rejected 的理由
tags 一律從 ~/offline/clade/docs/pitfalls/tags.yml 挑;若需新 tag → 先 Edit tags.yml 註冊 + 短描述,再用。
Step 3 — Cross-consumer scan 自動回填 impact
對 registry/consumers.json 列的 role: consumer 條目跑 detection grep,自動填 cross_consumer_impact(MUST 從 registry 動態讀,NEVER 寫死路徑清單 — 新 consumer 加入 registry 時 sweep 才會自動覆蓋):
mapfile -t CONSUMERS < <(
node -e '
const r = JSON.parse(require("fs").readFileSync("/Users/charles/offline/clade/registry/consumers.json", "utf8"));
for (const c of r.consumers) {
if (c.role === "source-of-truth") continue;
console.log(c.consumer_id);
}
'
)
for consumer in "${CONSUMERS[@]}"; do
d="$HOME/offline/$consumer"
[ "$consumer" = "nuxt-supabase-starter" ] && scan_root="$d/template" || scan_root="$d"
echo "=== $consumer ==="
hits=$(<跑 grep, 數匹配檔案數>)
if [ "$hits" -gt 0 ]; then
echo "$consumer: affected (hits=$hits)"
else
echo "$consumer: unaffected"
fi
done
依結果回填 frontmatter 每個 consumer key:
affected: affected / unaffected / unknown
fixed: fixed / partial / not-applicable / unknown
commit: <SHA> 或 null
scanned_at: <today ISO>
reason: <掃描阻擋原因>(affected: unknown 時 MUST 填)
規約:
- 觸發 consumer(
discovered_at)通常 affected=affected, fixed=fixed,commit 由使用者提供或留 null
- 其餘 registry consumer 若 grep 0 命中 →
affected=unaffected(除非有理由懷疑掃不到)
- 若 grep 跑不通(例如該 consumer 不在 ~/offline/)→
affected=unknown, reason: <why>
NEVER 留全部 unknown 而不寫 reason — audit script 會 block。
Step 3.5 — Sweep regression check
對 candidate incident 跑(root cause 已確認、frontmatter cross-consumer 掃完、body 還沒寫死前):
node --experimental-strip-types vendor/scripts/check-sweep-regression.mts \
--symptom "<candidate symptom one-liner>" \
--body-file "<candidate body draft path or /dev/null>" \
--json
該 script:
- 掃
docs/sweeps/*.md 每個 SWEEP-XX-NNN 的 incident_pattern_for_oops.grep
- 對 candidate symptom + body 做 regex / 字串 match
- 命中 → 回傳
{ "regression_of": "SWEEP-V2-XXX", "matched_pattern": "...", "matched_in": "symptom" | "body", "sweep_id": "SWEEP-V2" }
- 未命中 → 回傳
{ "regression_of": null, "matched_pattern": null, ... }
Step 3.5.1 — Regression hit(命中)
若 regression_of 不為 null:
- MUST 在 pitfall frontmatter 加:
regression_of: SWEEP-V2-XXX
- 在 pitfall body 開頭(
# <title> 之後、## Symptom 之前)加 banner:
> ⚠ **Regression of SWEEP-V2-XXX** — 預防失效,回頭補強對應 prevention。
- /oops 結尾 surface user:「這條是
SWEEP-V2-XXX regression — 該 prevention 不夠,需下一輪 sweep 補強,或直接立刻補 RNI(後續 audit-sweep-regression --window 14 跑會把這條算進 regression matrix)」
Step 3.5.2 — 未命中(新類)
加 frontmatter(最新 sweep id,視 docs/sweeps/ 最末檔案決定):
discovered_after: SWEEP-V2
讓 audit-sweep-regression.mts 知道這條是「新類」,不算 regression。
為什麼這步在 Step 4 之前
regression_of: SWEEP-V2-XXX 屬於 frontmatter — Step 4 寫 markdown body 時要在 banner block 就反映出來;事後再回頭補容易漏。Step 3.5 跑 check-sweep-regression 已有 root cause 一行 symptom + frontmatter,足以餵 grep。
Step 4 — 寫 markdown body
從 TEMPLATE.md copy body section 結構:
# <人類可讀標題>
## Symptom
## Root Cause
## Why it slipped past tests / CI
## Detection
### grep pattern
### mcp pattern
## Fix Recipe
## Cross-Consumer Impact
## Prevention
## References
每段都要實質內容:
- Symptom:實際 log / 錯誤訊息原文(盡量複製不改寫),含 stack trace 關鍵 frame,讓未來 grep 能命中
- Root Cause:一句話 + 引用具體 source code 路徑 / 版本 / contract
- Why slipped past tests / CI:為什麼 typecheck / unit test / CI 沒抓到(防止下次同類 bug)
- Detection:grep + mcp 各一塊 code block,可 copy-paste 直接跑
- Fix Recipe:寫「在 X 補 Y」「把 A 改 B」,不是 diff dump
- Cross-Consumer Impact:人類可讀 markdown table(frontmatter 已是 canonical SoT;table 只是 view)
- Prevention:7 種 type 列表(audit-signal / pre-commit-hook / upstream-pr / rule-section / catalog-adoption / cookbook / regression-test)+ status + ref + note
- References:session、相關 ADR、upstream issue URL、修正 commit SHA
Step 5 — 寫進 clade(Bash workaround)
從 consumer session 用 Write tool 寫 ~/offline/clade/... 會靜默無視(回報 success 但檔案不存在 — Write tool 受 primary working directory 限制)。
MUST 走以下 workaround:
Write(file_path = "/tmp/clade-pitfall-<slug>.md", content = "<完整檔案>")
/bin/mv /tmp/clade-pitfall-<slug>.md \
/Users/charles/offline/clade/docs/pitfalls/<YYYY-MM-DD>-<slug>.md
/bin/ls -la /Users/charles/offline/clade/docs/pitfalls/<YYYY-MM-DD>-<slug>.md
從 clade session 跑時 Write tool 直接 work;無需 workaround(但 Edit tool 也 OK)。
Step 6 — Reindex mcp graph
新檔需要 reindex 才能透過 search_code 命中:
/Users/charles/.local/bin/codebase-memory-mcp cli index_repository \
'{"repo_path":"/Users/charles/offline/clade"}'
驗證:
/Users/charles/.local/bin/codebase-memory-mcp cli search_code \
'{"pattern":"<剛建立的 id 中 unique token>","project":"Users-charles-offline-clade"}'
預期回傳含剛建立的檔案路徑。若 0 命中 → 等幾秒重試 reindex(auto_index 偶爾 lazy)。
Step 7 — 跑 audit quality gate
cd /Users/charles/offline/clade && node scripts/pitfalls-audit.mjs
預期 exit 0 + 「all signals green for 」。
若有 block signal(例:schema.requiredMissing / tags.unknown / impact.unknownWithoutReason / prevention.acceptedWithoutRef):
- 修對應問題(補 frontmatter 欄位 / 註冊 tag / 補 scan reason / 建 TD entry)
- 重跑 audit 確認綠燈
- audit 沒綠MUST NOT 結束 skill
Step 8 — Prevention accepted 但未實作 → 建 TD-NNN
對每條 prevention[] status = accepted 的條目:
- Edit
~/offline/clade/docs/tech-debt.md 加 TD entry:
- 下一個未用的
TD-NNN
- 描述:本 pitfall id + prevention type + 預期落地動作
- Status:
open
- Priority: 從 pitfall severity 推(critical→high / high→mid / mid→low / low→low)
- Discovered: 同 pitfall discovered date
- 把
TD-NNN 填回 pitfall frontmatter prevention[<idx>].ref
- 重跑 audit 確認
prevention.acceptedWithoutRef 不再觸發
NEVER 跳過此步 — accepted 但無 TD-NNN 等於口頭 follow-up,最終會遺失。
Step 9 — Final report
回報使用者:
- ✅ 新 pitfall id + 路徑
- ✅ Cross-consumer scan 結果(各 consumer 哪幾個受影響)
- ✅ Prevention candidates list + 對應 TD-NNN(若 accepted)
- ✅ audit script all signals green
- 待 user 決定:要不要立即 propagate clade(按 memory rule「Propagate 需授權」)
Step 10 — Surface clade 治根快速路徑(optional, conditional)
何時 surface(MUST 同時成立才提供此選項;任一不成立 → skip 本 step):
- 至少一條
prevention[].status = accepted
- 該條 prevention
type ∈ {rule-section, cookbook, audit-signal}(純 clade 標準層 SoT 改動,propagate 投影層後 consumer 立即拿到新版)
- CWD ≠
~/offline/clade(已在 clade 直接動手,不用提示切換)
為什麼硬限制 type:
- ✅
rule-section / cookbook / audit-signal — 改 rules/core/ / vendor/snippets/ / scripts/*-audit.mjs,propagate 後 consumer .claude/rules/<topic>.md 投影層立即更新
- ❌
upstream-pr — 要去外部 repo 開 PR,無法靠 clade propagate 解
- ❌
pre-commit-hook — 雖然 hook 在 plugins/hub-core/hooks/ 可改,但 hook 行為通常需在 consumer 自家先 prototype 才確定 contract
- ❌
catalog-adoption — 即使 clade 升 catalog.* baseline,consumer 還要自行升 catalog version
accepted 條件 + 上述 type 同時成立 = 治根動作清楚 + 治法明確 + propagate 立刻見效 = 走快速路徑性價比最高。其他組合 user 仍可手動切去 clade 處理(skill 不擋,只是不主動 surface)。
Surface 內容範本:
[/oops] 偵測到 clade 標準層治根候選:
pitfall: <id>
accepted prevention:
- type: <rule-section | cookbook | audit-signal>
target: <具體 file path>
note: <一行說明>
TD: <TD-NNN>
選項:
A. 切去 clade 立刻治根 + propagate(推薦)
依 [[clade-role-and-todo-discipline]] § Direction B「user-explicit cross-boundary authorization」執行:
1. cd ~/offline/clade
2. 走 plan mode(非瑣碎工作)或直接 Edit + vp check(簡單 § 補強)
3. vp check + git commit --only -- <paths>(per § Ad-hoc commit hard rule)
4. node scripts/publish.mjs patch + git push && git push --tags
5. node scripts/propagate.mjs(同時散播投影層 + plugin update)
6. 切回 <current consumer>:
- 跑 pnpm hub:check 確認投影層 banner / checksum 已是新版
- 注意:plugin update 需要 AI Agent session 重啟才會 reload plugin cache(CLI 限制)
- 大多數 rule / cookbook / audit-signal 改動不需重啟 session(投影層直接生效)
7. 繼續原 consumer 工作
B. 只留 TD-<NNN>(已建),之後另開 session 處理
建議:若當前 consumer 工作有時間壓力 / 治根改動較大需獨立 session 拍板,選此
C. 先繼續 consumer 工作,自行決定何時治根
skill 不再追蹤;user 想跑時可重新觸發 /oops 或直接到 clade 動手
請告知選擇(A/B/C),或說「都不要」結束 /oops。
選 A 時的執行紀律:
- skill MAY 在同一 chat session 內 agent 自行切 CWD 到 clade、執行步驟 1-5、再切回 consumer
- 切換時MUST 明示 user:「現在切到 ~/offline/clade 治根,完成後回到 繼續」「現在切回 」
- NEVER 在 clade 端順手做其他 unrelated 改動(per [[clade-role-and-todo-discipline]] § Direction A/B 共通「授權僅及該次明確指定範圍」)
- NEVER 跳過 propagate(半成品狀態);clade 標準層改動完整跑完 publish + propagate 才算治根完成
- propagate 後在 consumer 端MUST 給 verify 指令(
pnpm hub:check)但不替 user 自動跑(per request_user_input 答覆,user 想自己驗)
選 B 時的後續:
- TD-NNN 已在 Step 8 建好,本 step 不額外動作
- user 之後想跑時可重觸發 /oops 或自行到 clade 動手
選 C 時的後續:
Mode C:handoff sweep(被 /handoff Mode B 2B.0 呼叫)
當 /handoff skill 進入 Mode B 並執行 2B.0 Session-end pitfall sweep 時觸發本 mode:
- 掃當前 session transcript,找:
- user 糾正 Claude 的訊號(「不對」「不是這樣」「不要這樣做」「重做」)
- 解過的 cryptic error 但沒登記
- 升 npm 大版 / 動 evlog/RLS/Workers/Better Auth 過程中發現的非預期行為
- 對每個 candidate 分類:
- 符合 Mode B 四條件齊備 → 啟動 Mode B 完整流程寫 pitfall
- 不齊備但屬個人偏好 / 跨專案行為 → 寫 auto-memory
feedback type
- 不齊備但屬 consumer-local → 寫
<consumer>/tasks/lessons.md 或 rules/local/
- 回報 /handoff 本次 sweep 結果(新增條目數 / 跳過項 / 升級候選)
入口契約見 plugins/hub-core/skills/handoff/SKILL.md § 2B.0。
Mode D:clade self-improvement sweep(clade-only)
觸發條件
MUST 同時滿足:
- CWD =
/Users/charles/offline/clade(NEVER 在 consumer session 跑 Mode D — 那是 clade 自治區的事)
- user 跑
/oops 時未附帶具體 cryptic error / pitfall 候選內容;或明確說「sweep / 自我改善 / 分析 consumer 貢獻」等字眼
若兩條件不齊備:
- 在 consumer session 跑 → 走 Mode A(查詢)或 Mode B(新增)
- 在 clade session 但帶具體 error → 仍走 Mode A / Mode B(Mode D 不取代)
- 不確定 → 問 user:「要走查詢(A)/ 新增(B)/ self-improvement sweep(D)?」
紀律(自治區規則延伸)
Mode D 輸出只寫「clade 標準層該怎麼補」,NEVER 寫以下任一:
- ❌「對 perno 跑 X」「替 starter 升 Y」這種 consumer 動作(即使 evidence 顯示 consumer 該動)
- ❌ 替 consumer 拆 phase / 規劃實作步驟
- ❌「block production」「user 必做」等催促語(即使真的 block consumer,那是 consumer 自家 HANDOFF 該登)
- ❌ 直接動
docs/digests/(不污染 improvement-digest.mjs auto pipeline)
- ❌ 直接 draft
docs/pitfalls/ 新條目(候選若值得升級成 pitfall,標記 候選升級 → Mode B,由 user 決定後再走 Mode B Step 1-9)
Mode D 是分析 + 候選清單,不是執行;user 看完 tasks/<date>-clade-improve-sweep.md 自行決定哪幾條落地。
Step 1 — 收集 6 個輸入源
每個來源都 MAY skip(檔案不存在 / 路徑不通則跳過並在最後 report 註明)。NEVER 因為單一來源 miss 就放棄整個 sweep。
| # | 來源 | 收集方式 | 看什麼訊號 |
|---|
| 1 | docs/pitfalls/*.md(不含 _archive/) | mcp__codebase-memory-mcp__search_code w/ path_filter="^docs/pitfalls/" + 抽 frontmatter(status, prevention[].status, cross_consumer_impact) | (a) prevention.status = accepted 但對應 TD 仍 open 超過 N 天;(b) cross_consumer_impact ≥ 3 個 consumer affected 但 prevention 全部 candidate;(c) status = open 超過 30 天 |
| 2 | docs/digests/*.md(排除 _bootstrap-*) | Read 最近 3 份;抽 DIG- id + kind + severity | (a) 同一 DIG- 連續 ≥ 2 份 digest 都出現未收斂;(b) candidate kind 集中在某個主題(如同主題 tech-debt 反覆出現) |
| 3 | vendor/ledger/*.jsonl(data 在此;vendor/signals/ 只放 code) | wc -l vendor/ledger/*.jsonl 2>/dev/null 看 signals.jsonl 行數;有檔則 tail -200 vendor/ledger/signals.jsonl 抽最近事件,frequency map by event_type。對照 [[improvement-loop]] § 8:signals.jsonl < 10 = bootstrap-only(signal 分析無意義,跳本源);≥ 10 = partial / steady-state 才做 frequency 分析 | (a) 高頻 reject 比率(validator 擋訊號);(b) 高頻同類 event;(c) 某 consumer signal 量驟降(instrumentation 可能壞了) |
| 4 | consumer git log(最近 30 天) | 對 registry/consumers.json 內 role: consumer 條目跑 git -C <path> log --since="30 days ago" --pretty=format:"%h %s" | head -50;consumer 路徑用 ~/offline/<consumer_id> 推(starter 例外:scan root = ~/offline/nuxt-supabase-starter/template,因 projection_paths.rules = "template/.claude/rules/") | (a) commit message 反覆出現某 keyword(如 fix typecheck, revert, hotfix)→ 標準層可能缺;(b) 多個 consumer 同期出現相似 commit pattern → 系統性問題 |
| 5 | consumer tasks/lessons.md | cat ~/offline/<consumer>/tasks/lessons.md 2>/dev/null(檔案常不存在,skip 即可) | (a) 多個 consumer lessons.md 出現同一類 pattern → 該 promote 進 rules/core/ |
| 6 | consumer .claude/rules/local/*.md | ls ~/offline/<consumer>/.claude/rules/local/ 2>/dev/null(starter 換 template/.claude/rules/local/);列出檔名 + 一行 description(讀檔頭) | (a) 多個 consumer 自寫同主題 local rule → clade core 該補的 signal;(b) 出現「workaround clade 限制」字眼 |
規約:來源 4 / 5 / 6 的 consumer 列表 MUST 從 registry/consumers.json 抽 role: consumer 條目動態決定,NEVER 在 SKILL 內寫死「N 個 consumer」或路徑清單(registry 加 consumer 時 sweep 自動覆蓋;硬編碼必導致漏掃)。
MCP 缺失時 fallback — Step 1#1 改用 rg --files-with-matches "<keyword>" docs/pitfalls/。其他來源都是純檔案讀,不依賴 MCP。
Step 2 — 跨來源比對抽 pattern
對每個收集到的 candidate 訊號,問三個問題:
- 這個 pattern 在幾個 consumer 出現?(單一 consumer 不是 Mode D 該管的;那是該 consumer 自家 session 的事)
- clade 既有標準是否覆蓋?(搜
rules/core/*.md + vendor/snippets/*/ + scripts/*-audit.mjs + vendor/scripts/*-audit.mjs,且 MUST grep scripts/propagate.mjs 的 inline audit 函式(如 auditCladeGateAdoption / auditSharedTreeSafety 等以 audit* 命名、wired 進 post_audit phase 的函式)有沒有相關 §。踩過的坑:稽核常 inline 在 propagate.mjs 而非獨立 audit-*.mjs,只搜獨立檔會漏判「標準層缺稽核」→ 誤列已存在的東西為候選)
- 建議的標準層行動類型(五選一,並非全部都有):
rule-section:在現有 rules/core/<topic>.md 加新 §
cookbook:在 vendor/snippets/<topic>/ 加 template / README
audit-signal:擴充既有 audit script 加新 signal,或新建 <topic>-audit.mjs
pitfall-upgrade:訊號夠成熟,建議走 /oops Mode B 升級成 pitfall
rule-promotion:consumer local rule / lessons 在多 consumer 重複,建議 promote 進 rules/core/
單 consumer pattern 處置:在分析中忽略或 MAY 用一句話標註「僅 觀察到,建議由該 consumer 自家 session 處理」(NEVER 拆 phase / 列步驟)。
Step 2.5 — emit candidate 前必驗 current state(MUST,防 pre-fix snapshot 誤判)
Mode D 的輸入(signal frequency / git log / digest)都是歷史快照。直接據此列「標準層缺 X」候選,常常 X 早已落地——歷史訊號只是 fix 之前累積的。每條候選寫進 tasks 檔之前 MUST 跑以下兩驗,任一驗證出「已落地」就降級為 observation 或直接刪,NEVER 當作待辦候選:
- 覆蓋驗證(所有候選):對「建議落地位置」的目標機制,照 Step 2 question 2 的完整清單 grep(含 propagate.mjs inline audit)。已存在 → 候選作廢,最多標 observation「已由 涵蓋」。
- 反例(本 skill 2026-06-12 sweep 實際誤判):候選「新建 clade-gate wrap-coverage audit」,實際
auditCladeGateAdoption 早已 inline 在 propagate.mjs 且 wired。
- 時序驗證(signal / digest-based 候選):對「某 error/signal 反覆出現」型候選,MUST 比對該訊號的時戳範圍 vs 對應 fix commit 時戳:
git log -1 --format="%h %ci %s" -S "<fix 關鍵字>" -- <suspect file>
若所有命中訊號都早於 fix commit → 純 pre-fix 歷史 noise,NEVER 列候選。
- 反例(同次 sweep 誤判):候選「fingerprint 抓 banner noise」,實際 commit
5380e383(fix)晚於 ledger 內全部 46 筆 noise → 早已修。
對應 memory [[feedback_mode_d_verify_actual_state_not_frontmatter_status]] / [[feedback_mode_d_verify_ledger_semantics_and_digest_timing]]:把這兩條自律 built-in 成強制步驟,避免「memory 有記但 skill 沒擋 → 同類誤判反覆」。
Step 3 — 寫 tasks/-clade-improve-sweep.md
檔名:tasks/<YYYY-MM-DD-HHMM>-clade-improve-sweep.md(用 date +%Y-%m-%d-%H%M 取當下時間)
格式:
# Clade self-improvement sweep — <ISO date>
> Mode D output. 不執行,僅候選清單;user 看完決定哪幾條落地。
> Session-tied tasks file;未升級項 session 結束時走 /handoff 升 HANDOFF.md / docs/tech-debt.md / 直接刪。
## 輸入源狀態
- pitfalls: <N> 條目掃描完成
- digests: 最近 <N> 份
- signals/ledger: <available | not-bootstrapped>
- consumer git log: <N>/<TOTAL> reachable
- consumer lessons.md: <N>/<TOTAL> present
- consumer local rules: <N>/<TOTAL> has rules/local/
> `<TOTAL>` = `registry/consumers.json` 內 `role: consumer` 條目數。
## Candidates
### SWEEP-001 — <一句話標題>
- **行動類型**: `rule-section` | `cookbook` | `audit-signal` | `pitfall-upgrade` | `rule-promotion`
- **跨 consumer 證據**: <N>/<TOTAL> consumer 出現;list: <consumer ids>
- **clade 覆蓋現況**: <既有 rule / cookbook / audit 路徑,或「無」>
- **建議落地位置**: <具體 file path + § 名>
- **Evidence**:
- <來源 1 + 引用片段>
- <來源 2 + 引用片段>
- **預估 effort**: low | medium | high
- **若 user 接受**: 直接 plan mode 動手 / 進 docs/tech-debt.md TD-NNN / 走 /oops Mode B
### SWEEP-002 — ...
## 跳過項(單 consumer / 證據不足)
- <一行說明哪些 candidate 被排除 + 原因>
## 工具鏈缺口(若有)
- <例:`vendor/ledger/signals.jsonl` 行數 < 10 → improvement-loop instrumentation 仍 bootstrap-only(已知 TD-111 / TD-125 / TD-152 追蹤 shim 採用率),signal-based 分析跳過>
- <例:consumer X repo 路徑不通 → registry 可能要更新>
規約:
SWEEP-NNN 編號從 001 開始,per-file 不跨 session 累積(每次 sweep 新檔重編)
- 「建議落地位置」MUST 給具體 file path(不寫「補某個 rule」這種模糊話)
- Evidence 引用 MUST 至少一條可驗證(檔案路徑 + 行號 / commit SHA / DIG-id / pitfall id)
- NEVER 把跳過項當主候選清單第二段(顯著區隔,否則 user 容易誤讀)
Step 4 — Session 對話回報
寫完 tasks 檔後給 user 看:
- 輸入源狀態總覽(哪幾個 source 抓到 / skip)
- Top 3-5 candidates(按跨 consumer 影響度排)— 一行標題 + 建議行動類型
- 工具鏈缺口(若有)— 標準層自身的稽核盲點
- 下一步問句:「要逐條討論哪幾條落地?還是直接 plan mode 處理某條?」
NEVER 在回報結尾推薦 /schedule / /loop 排程 — sweep 是 ad-hoc 觸發,user 想再跑會自己跑。
Step 5 — 不做的事(明確列出避免漂移)
- ❌ 不動
docs/digests/(improvement-digest.mjs 自動跑,Mode D 只讀不寫)
- ❌ 不直接 draft
docs/pitfalls/ 條目(候選若值得升 pitfall,標 pitfall-upgrade,由 user 走 Mode B)
- ❌ 不動
rules/core/ / vendor/snippets/ / vendor/scripts/(這些是「建議落地位置」,不是 Mode D 該執行的事)
- ❌ 不列任何 consumer-side 動作(即使 evidence 顯示)
- ❌ 不跑 propagate / publish(Mode D 完全不該觸發散播)
Status Lifecycle
| Status | 條件 | 判定方式 |
|---|
open | 尚有未知 consumer / 未修 consumer / prevention 未決 | 新建預設 |
mitigated | 所有 consumer 都 scanned + 受影響者已 fixed + 至少一條 prevention implemented 或明確 rejected | audit script 推導 |
fixed-upstream | upstream 已 release fix 且 所有 consumer 都升到安全版本(不只是 upstream release) | 人工 + 版本掃描守住 |
wontfix | 明確放棄;MUST 填 wontfix_reason | 人工 |
Prevention Promotion Path
candidate → accepted → implemented 或 candidate → rejected。
accepted MUST 同時建 docs/tech-debt.md TD-NNN,並把 ID 填進 frontmatter prevention[].ref,否則 audit prevention.acceptedWithoutRef block。
7 種類型:audit-signal / pre-commit-hook / upstream-pr / rule-section / catalog-adoption / cookbook(vendor/snippets 可重用範本)/ regression-test(fixtures / typecheck / publish gate)。
Archive Policy
mitigated / fixed-upstream / wontfix 後:
- < 90 天 → 留
docs/pitfalls/ active 目錄
- ≥ 90 天 → 搬到
docs/pitfalls/_archive/YYYY-MM/<filename>
archive 後 mcp 仍可搜(不在 .gitignore / index exclude),audit script 預設掃 active + archive 但分開 report。
MCP 配置(每個 consumer + clade)
每個 consumer 的 .mcp.json MUST 含 codebase-memory-mcp server entry:
{
"mcpServers": {
"codebase-memory-mcp": {
"type": "stdio",
"command": "/Users/charles/.local/bin/codebase-memory-mcp"
}
}
}
若 consumer 已有其他 MCP server(如 Supabase MCP),MUST merge 進同一 mcpServers 物件,不建第二份 .mcp.json。
clade 自家也MUST有 .mcp.json(~/offline/clade/.mcp.json)。
binary 由 codebase-memory-mcp install 安裝到 ~/.local/bin/codebase-memory-mcp;用實際絕對路徑(不依賴 $PATH expansion)。
必禁事項
- NEVER 把 pitfalls SoT 散播副本到 consumer — 違反「同一份知識庫」前提(skill 本體散播 OK)
- NEVER 在 consumer 自家 docs/ 寫 pitfall — 一律寫進 clade
- NEVER 跳過 Mode A 查詢直接動手解 cryptic error — 先
search_code 看 clade 是否已記錄
- NEVER
Read 整個 ~/offline/clade/docs/pitfalls/ 目錄 — 用 mcp 省 token
- NEVER 用
path_glob — silently ignored;MUST 用 path_filter(regex)
- NEVER 條目缺 root cause / detection / fix / prevention decision 四項任一就 commit — audit script 會 block
- NEVER
prevention.status = accepted 但不建 TD-NNN — audit script 會 block
- NEVER session 結束時把新踩到的坑只留在當下對話 context — 必沉澱到 clade 才算結案
- NEVER 跳過 Mode B Step 1 dedupe / Step 3 cross-consumer scan / Step 5 Bash workaround(從 consumer session)/ Step 6 reindex / Step 7 audit gate / Step 8 TD entry
- NEVER 把不齊備的 candidate 硬塞進
docs/pitfalls/ — 走輕量降級三層分流
與其他規則的關係
knowledge-and-decisions.md:管 consumer 自家 docs/solutions/ 與 docs/decisions/,屬 consumer-local 知識;本 skill 補上跨 consumer共享知識的維度
vendor/scripts/improvement-digest.mjs + vendor/signals/:digest 是自動(事件觸發 batch)從 signal ledger 抽出來的候選;pitfalls 是人類事後寫的根因分析。digest candidate 升級成 pitfall 時 digest 條目加 promoted_to_pitfall: <id>,不標 resolved
tech-debt-routing.md:管 TD 寫在 clade 還是 consumer;本 skill 管 pitfall(非 TD)寫在 clade。判斷:條目能讓「下次同類問題立刻被偵測」屬 pitfall;只是「我們知道有這條 TD 要處理」屬 tech-debt
follow-up-register.md:pitfall prevention.status = accepted 必須在 docs/tech-debt.md 建 TD-NNN 條目,由 follow-up register 規則接管
evlog-adoption.md / audit-pattern.md / logging.md:主題 rule 規範正向做法;pitfalls 補上反向真實踩過的坑,幫助 agent 理解規則背後動機
/handoff skill:session 結束時觸發本 skill Mode C
- Mode D vs improvement-digest.mjs:兩者輸入有重疊(pitfalls / signals / tech-debt),但 cadence 與輸出不同。digest 是事件觸發 batch,產出
docs/digests/<date>.md(半結構化候選,走 DIG-hash + evidence predicate);Mode D 是 user 觸發 ad-hoc sweep,產出 tasks/<date>-clade-improve-sweep.md(session-tied 候選清單,含各 consumer 即時狀態如 git log / lessons.md / local rules,digest 不掃這些)。Mode D 不寫 digest,避免污染 auto pipeline;digest 若已有對應 DIG-id,Mode D candidate 標 related: DIG-xxxx 交叉引用
違反時的回報方式
[/oops] 應該先查 clade pitfalls
問題:偵測到 <情境>(例:evlog 升大版 / cryptic emit error / contract violation),
但 session 內沒有 mcp__codebase-memory-mcp__search_code 呼叫紀錄
修正方式:
- 暫停動作,先跑 search_code project="Users-charles-offline-clade" path_filter="^docs/pitfalls/" pattern="<關鍵字>"
- 命中 → 套用 fix recipe;未命中 → 動手 + session 結束前走 /oops Mode B 新增條目
繞過:
- 若已確認該坑非跨 consumer 議題(純 consumer 自家業務 bug),可繼續;否則必查