claude-dd / tests
CLAUDE.md12 starsChanged 13 days agoMITView on GitHub
放「不屬於任何一支部署腳本、但 CI 要跑」的測試。不部署:不在 scripts/ 底下, 所以 DD_SCRIPTS ↔ scripts/*.sh 那道一致性檢查不會把它當成要部署的腳本。 - CI 在兩種 bash 上各跑一次:ubuntu(bash 5)與 macOS 的 /bin/bash 3.2(.github/workflows/ci.yml)。 gate 與它的 hook 都靠 shebang #!/bin/bash 執行,所以在 macOS 上測到的就是使用者機器上的那個 bash - test-gate.sh 在 gate 的輸出裡看到 shell 錯誤就判失敗(bad substitution、syntax error、command not found、 invalid option、unbound variable,以及 bash 報腳本錯誤固定的「: line N: 」前綴):bash 3.2 不支援的寫法常常 只印一行錯誤、判斷結果照舊,只看 pass/block 的話 macOS job 照樣全綠。2026-10-01 實測:在 gate 的 staged=$(…) 下一行加 lc=${staged,,},3.2 下 36 個 ❌、bash 5 全過;shopt -s lastpipe、 ${a[-1]} 這類清單外的錯誤,是加了「: line N: 」前綴才抓到的。test-install.sh 不做這層檢查,靠 set -e: 3.2…
- Deletes or force-pushes
In this repository18 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- scripts/CLAUDE.mdCLAUDE.md
- skills/gate-guard/hooks/CLAUDE.mdCLAUDE.md
- skills/self-improving-agent/CLAUDE.mdCLAUDE.md
- skills/self-improving-agent/hooks/CLAUDE.mdCLAUDE.md
- skills/tech-diagram-gif/scripts/CLAUDE.mdCLAUDE.md
- code-simplifierSkill
- dd-loopSkill
- design-brainstormSkill
- frontend-designSkill
- plan-reviewSkill
- reviewSkill
- self-improving-agentSkill
- task-plannerSkill
- tech-diagram-gifSkill
- verification-gateSkill
- worktree-managerSkill
- writing-great-skillsSkill
The file
Files
tests/ — CI 跑的情境測試
放「不屬於任何一支部署腳本、但 CI 要跑」的測試。不部署:不在 scripts/ 底下,
所以 DD_SCRIPTS ↔ scripts/*.sh 那道一致性檢查不會把它當成要部署的腳本。
關鍵檔案
| 檔案 | 用途 | |
test-install.sh | 安裝腳本的端到端測試:拋棄式 HOME 裡非互動安裝,驗部署內容等於部署清單、重跑冪等、--force 內容相同不重寫、--update、--commands-only(另在乾淨 HOME 驗它不部署 output style)、--uninstall 非互動預設取消、--uninstall --yes 移除 adhd.md 但不動使用者自己的風格檔、--check 不寫入、--help 可執行。跑完清掉暫存目錄 | |
test-gate.sh | CLAUDE.md gate(scripts/check-claude-md.sh)的情境測試:段落起點、SKIP 欠帳、merge、改寫過的歷史、中文與含空白的路徑。在拋棄式 repo 裡掛上 gate 實際 commit,逐案印 ✅/❌,有 ❌ 就 exit 1。第一個參數可以換成別的 gate 路徑,做「改壞一行、確認會出現 ❌」的變異測試。2026-10-07(S6)新增 review 報告強制的情境(導入路徑被擋 / SKIP 申報放行 / 沒報告擋下 / 兩份報告放行 / CLAUDE.md 不算 / 只改既有報告不算新增 / amend 過的歷史仍照擋 / SUMMARY.md 不算 / 刪目錄退出)。2026-10-07(S4)又加了「三處退化政策各自的行為」(起點不是祖先時:--segment-base 硬失敗、reviews_missing 退到共同祖先照樣擋;連共同祖先都沒有時:兩處放行但必須印出警告)—— ⚠️ 這幾則有三個容易寫成空洞斷言的地方:①docs/reviews/ 是 opt-in、判準是工作目錄裡有沒有那個目錄,切分支或 rm -rf docs 之後沒重建就整個檢查不啟用,測試會「為了錯的理由而通過」(⑩第一版、⑪前一版都踩過 —— ⑪那次實測:把 reviews_missing 的「沒有共同祖先」那一支改成擋、或拿掉它的警告,全綠零紅);②--start-segment 通過時會寫入新起點,所以 base_is 只能放在它之前;③兩處共用 resolve_fork_base 之後,警告句的共同部分(「改從共同祖先」「找不到共同祖先」)誰印都算過關 —— said 一律挑「只有一處會印的字串」(review 檢查改從共同祖先 / 只檢查 staged / 跳過 review 報告檢查)。2026-10-16 又加了 ⑫「記憶檔名可設」(git config dd.docfile GEMINI.md:只有 GEMINI.md 也過關 / CLAUDE.md 不算 / 欠帳認 GEMINI.md / 非法值拒絕 / unset 回到預設)—— 它自己開一個乾淨 repo,不碰 ⑩⑪ 收尾的狀態。⚠️ 這一段有一個「同批 staged 蓋掉銷帳」的陷阱:測「欠帳銷掉了」時若只寫「補上該目錄的記憶檔 → 放行」,放行的理由會是這次一起 staged([ -f "$md" ] && grep -qxF "$md" && continue 的短路)—— owed_dirs 照樣跑、也確實把該目錄算成欠帳,只是結果被那條短路蓋掉,所以把 awk 那行改回寫死 CLAUDE.md 時全綠零紅。要釘住銷帳必須再加一個完全不碰該目錄的 commit。2026-10-19 加了「已知的三條繞過路徑」的特性測試(放在 ⑧ 與 ⑨ 之間;說明以「繞過①」「繞過②」「繞過③」開頭,對應 scripts/CLAUDE.md 那三句,各配一則對照;區塊開頭另有一則「正常流程」:報告 commit 之後還有步驟 6 的 commit,開下一段要放行)—— 變紅時怎麼判、變異實測,都記在 scripts/CLAUDE.md 那條底下(⚠️ ②跟正常流程是同一個形狀,②變紅多半是回歸)。⚠️ 寫這類對照時,放行那則不能用 --start-segment 之後的第一個 commit:那時 HEAD 就是起點、範圍是空的,reviews_missing 裡的 [ "$base" = "$head_sha" ] && return 1 直接放行,斷言什麼都釘不住(docs/reviews/2026-10-18-pstack-gaps/S1-b.md 的 B1,實測)。⚠️ 不要在這裡寫「N 項」 —— 本檔寫過「61 → 73」,收 review 時又加了三個情境就過期了;項數自己跑 `bash tests/test-gate.sh | grep -c "^✅"`。 |
test-dd-init-upgrade.sh | /dd-init 升級分類腳本(scripts/dd-init-upgrade.sh)的情境測試:fixture 從 v1.6.12、v1.6.4、6a9addd、v1.1.0 用 git show <tag>: 抽各版蓋章區塊,插入自編的 LOCAL* 在地行(步驟 1 之前、步驟 4、5 的圍欄、8 底下、驗證不過之後、一行 ---、維護小節、區塊外小節),斷言在地行各剩一次且落在原錨點之間、該版有而現行區塊沒有的範本行在輸出裡 0 次、標記與 ## 開發流程 各一個;另有純範本、rental-management 型(在地 ###)、在地 ## 截斷、後段在地內容、--plan 各節與行號、React 圍欄改一行、exit 2–5。斷言不讀腳本的清單(獨立於被測物)。要 git 歷史:兩個 CI job 的 checkout 都設了 fetch-depth: 0。另斷言輸出的標記是現行區塊那一行(rev 13)、現行區塊自己跑一次輸出不變、rental 型升級過再升一次輸出不變、步驟 1 之前的在地行(LOCALP)留在標記與步驟 1 之間、專案改寫過步驟 5 那一行時底下的指令仍列在「步驟 5 既有的驗證指令行」。變異對照(2026-10-30 S2 審查修正後重跑,記「哪個變異 → 哪幾則紅」):空殼腳本(只 exit 0)→ 36 ❌,紅在「沒有產生輸出檔」與各斷言的錯值;圍欄一律算範本(tpl[nu] = 1)→ 9 ❌,四版的 LOCAL5 圍欄內容不見、React 圍欄沒列;終點遇同級標題就停(拿掉 !inL(trim(F[i])))→ 10 ❌,四版 LOCALV 落到 ## CLAUDE.md 維護 之後、四版各留 3–4 行舊範本、純範本與現行區塊不等於預期;單行判範本不看降級標題(inL(t) 改回 (t in L))→ 1 ❌,rental 型第二次升級輸出改變;改寫過的步驟行不更新錨點 → 2 ❌,LOCALS5 沒列進步驟 5 那一節、落在新的步驟 5 之前;拿掉「步驟 1 之前」的插入 → 8 ❌,四版 LOCALP 不見。⚠️ 寫 count_is 時挑只出現在那一行的字串:LOCAL5 也出現在圍欄裡的 curl 那行,第一版因此每版都報「出現 2 次」 |
此層約束
- CI 在兩種 bash 上各跑一次:ubuntu(bash 5)與 macOS 的
/bin/bash3.2(.github/workflows/ci.yml)。 gate 與它的 hook 都靠 shebang#!/bin/bash執行,所以在 macOS 上測到的就是使用者機器上的那個 bash test-gate.sh在 gate 的輸出裡看到 shell 錯誤就判失敗(bad substitution、syntax error、command not found、invalid option、unbound variable,以及 bash 報腳本錯誤固定的「: line N:」前綴):bash 3.2 不支援的寫法常常 只印一行錯誤、判斷結果照舊,只看 pass/block 的話 macOS job 照樣全綠。2026-10-01 實測:在 gate 的staged=$(…)下一行加lc=${staged,,},3.2 下 36 個 ❌、bash 5 全過;shopt -s lastpipe、${a[-1]}這類清單外的錯誤,是加了「: line N:」前綴才抓到的。test-install.sh不做這層檢查,靠set -e: 3.2 在set -e下遇到這類錯誤會直接中止- 兩支都在暫存目錄裡跑、
trap跑完清掉(本機會拿來重跑與做變異測試) - 腳本開頭是
set -e(2026-10-01 從 ci.yml 內嵌 step 搬出來時照 GitHub Actions 預設的bash -e保留): 預期會被擋的 commit 一律包在expect的if裡,新增情境時別讓會回非 0 的指令裸跑- ⚠️ 預期放行、但會觸發 hook 的指令(
git commit --amend這類)也要包進expect:裸跑的話, 變異版 gate 擋下它時set -e中止整支,後面的情境一則都沒跑,看起來像「只紅了前面幾則」。 2026-10-19 實測:拿「pre-commit 也查報告」的變異跑,整支停在 ⑦ 那行裸跑的 amend,新加的繞過①根本沒跑到; 包進expect後才跑完。驗法:變異版與固定版的判定行數(grep -cE '^(✅|❌ .*:(預期 |輸出裡有 shell 錯誤))')要一樣
- ⚠️ 預期放行、但會觸發 hook 的指令(
- ⚠️⚠️ 變異測試要選對「變異方向」,否則它證明的不是你以為的那件事。曾把 opt-in 守門
[ -d docs/reviews ] || return 1改成永遠return 1(= 功能全關),拿到的紅全部落在新區塊 —— 那證明「新情境在測這個功能」, 跟「opt-in 保護了沒採用的專案」完全無關。對應後者的變異是把那行整個拿掉 (檢查對所有 repo 生效),紅的才會落在舊的那批。三組實測:變異 紅 證明的是 那行 → 永遠 return 112 新情境真的在測這個功能 那行整個拿掉 5,其中 4 在舊的那批 ← opt-in 那句的佐證 --diff-filter=A→ACMR2 「只改既有報告不算新增」有被釘住 做法:寫「變異測試證明了 X」之前,先問「把 X 弄壞的最小改動是哪一行」, 然後改那一行 —— 不是改一個會讓整個功能消失的地方。 - ⚠️⚠️ 一個「恆真」的斷言比沒有斷言更糟。
情境 ① 曾寫
BEFORE_BASE=$(cat "$BASE_FILE")然後base_is "$BEFORE_BASE", 但那行讀檔是在expect … --start-segment跑完之後 —— 等於拿檔案跟自己比,永遠綠。 實測:對變異版,①的起點確實被搬動了而斷言照樣過;那個不變量實際只有情境 ③ 在守。 做法:斷言「X 沒有被改動」時,快照一定要在被測指令之前取; 而且用變異測試檢查這個斷言本身會不會紅 —— 不會紅的斷言是裝飾品。 - ⚠️ 新增的 review 強制情境刻意跑在「有
docs/reviews/目錄」的 repo 裡,而它之前的情境沒有 —— 那正是 opt-in 的證明:加了新功能,既有情境一項都不用改。 寫新情境時不要把mkdir docs/reviews往上搬,會把前面那些情境的前提改掉。 - ⚠️ 「剛採用慣例時第一次
--start-segment被擋」是情境 ①,不是待修的邊角 —— 上一段本來就沒報告,那是真實的導入路徑,預期結果是擋下、不是pass。 - 本機跑:
/bin/bash tests/test-gate.sh(repo 根目錄或任何地方都可以,gate 路徑以腳本位置推算)- bash 5(CI 的 ubuntu 那份)要在 repo 根目錄跑(
"$PWD"掛成/repo):docker run --rm -v "$PWD":/repo:ro bash:5 sh -c 'apk add --no-cache git >/tmp/apk.log 2>&1 || exit 3; ln -sf /usr/local/bin/bash /bin/bash; cd /tmp && bash /repo/tests/test-gate.sh'—— 映像沒有 git,也沒有/bin/bash(bash 在/usr/local/bin/bash,gate 的 shebang 寫#!/bin/bash),兩步都不能省。 少裝 git,一則情境都沒跑就git: command not found;少了ln,gate 跑不起來 —— 直接叫印/bin/bash: bad interpreter,從 hook 叫印的卻是…/check-claude-md.sh: not found(檔案明明在,缺的是直譯器;apk add git也不會順便帶來/bin/bash)
- bash 5(CI 的 ubuntu 那份)要在 repo 根目錄跑(
- 要通過
shellcheck -S warning(CI 的 ShellCheck 清單逐檔寫死,這支已列入)
與上層的關係
gate 本體的規則與「改了 gate 要做變異測試」的規定在 scripts/CLAUDE.md;CI 防線的總表在
根目錄的 DD_PIPELINE_ARCHITECTURE.md。
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

