SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-23

Old Coder skill:審查證據,不看程式碼

讓 agent 先寫 SPEC 供你核准,再提交可重跑的 EVIDENCE 報告。了解 Old Coder gauntlet 如何以 mutation testing 補足 coverage,並檢視確切命令與數值。

Old Coder skill 實際會變更的內容

Old Coder skill 會以文件審查取代程式碼審查。你的 coding agent 會先撰寫 SPEC,再撰寫任何程式碼。你核准該文件後,它才會開始實作。接著,它會使用一組固定的自動化檢查執行自己的工作,這組檢查稱為 gauntlet,並交付一份 EVIDENCE 報告,其中包含確切的命令與實際數值。你只需閱讀兩份文件,不必閱讀 diff。

這項取捨只有在兩份文件具備原本由 diff 提供的可信度時才有效。SPEC 之所以具備可信度,是因為你在任何程式碼存在之前就已核准它,因此不可能配合 agent 已經撰寫的程式碼來塑造內容。EVIDENCE 報告之所以具備可信度,是因為其中每個數值都來自你可以自行執行的命令,並且可以監看該命令產生相同數值。如果其中任何一半失去嚴謹性,你實際上只是用審查摘要取代審查。這比閱讀 diff 更糟,因為它會讓人誤以為工作已經完成。

這個 skill 使用純 markdown,因此任何遵循書面指示的 agent 都能使用,包括 Claude Code、Codex CLI、Cursor 或你自己的迴圈。它與 Ponytail 懶散資深開發者 persona skill 屬於同一類型。如果你不熟悉這種檔案格式,agent skill 是什麼,以及 agent 如何載入它 會說明相關機制。

SPEC 是你仍需做出的唯一決策

SPEC 是在程式碼存在之前撰寫的測試計畫。技能檔案要求其中包含 4 項內容。

  • 具體情境:輸入、預期輸出、邊界情況與錯誤情況。divide(1, 0) raises ZeroDivisionError with message X,不能只寫「能處理錯誤輸入」。
  • 負向限制:哪些內容不得變更,例如現有測試與公開 API 簽章。
  • 設定計畫:列出每項工具與新增相依套件,並各用一行說明用途。
  • 絕對檔案路徑,讓你無須搜尋即可開啟檔案。

設定計畫最能顯示模型的訓練資料截止時間。模型記憶中的工具或固定版本可能已經過時一年。因此,提供代理程式 可自行代管的 SearXNG 實例以進行網路搜尋,並要求它在提出建議前確認目前版本,會更有幫助。

核准後,將它提交。核准後仍可編輯的 SPEC 不是契約;而提交內容能讓你日後確認,證據是否是根據你簽署的內容測量。

這是你僅剩的唯一是非決策,這也是重點與風險所在。請將它視為對正式環境所做的變更,因為它確實就是這種變更。如果你已在代理程式動作前設定 明確的核准閘門,SPEC 核准就能放入工作流程中的相同位置。

EVIDENCE 報告:附上指令的數據

EVIDENCE 報告是你最後閱讀的內容。這項技能要求將每個規格行為對應到驗證該行為的測試,報告每個 gauntlet 層級所執行的指令及其實際結果,所有數字都必須取自最後一次程式碼編輯後的新鮮執行結果,並列出每個略過的層級及其原因。形容詞不是證據。「All 41 tests pass, coverage 49/49 statements」是結果;「Well tested」不是。

儲存庫中的示範報告 demo-rate-limiter/evidence.md 會以 commit 加上 sha256 tree hash 標示其來源狀態。這行資訊的重要性超出表面,因為它能指出產生這些數字的確切位元組。缺少這項資訊時,報告可能在不知不覺間描述一個已不存在的 working tree。

三項防止作弊的規則能讓報告維持可信,而 skill file 將這些規則列為絕對要求。絕對不要削弱測試來讓它通過:不得放寬 assertions,也不得提高 tolerances。不要在同一個步驟中同時修改測試與實作以取得綠燈,因為同時修改會掩蓋究竟是哪一方出錯。絕對不要報告未執行的層級:「skipped, no tool available, manual mutation instead」能維持信任,而捏造結果會摧毀整套機制。

安裝 skill,並固定所安裝的 commit

此 repository 是 AmazingAng/old-coder,採用 MIT 授權。其 README 提供透過 skills CLI 安裝的一行指令:

npx skills add https://github.com/amazingang/old-coder

這會安裝執行指令當下 main 所指向的內容,而 CLI 本身也可能持續變動。確認檔案的安裝位置,再假設 skill 已啟用:

ls ~/.claude/skills/old-coder/

您應該會看到 SKILL.mdreferences/ 目錄。如果找不到這些內容,表示 skill 不在 Claude Code 尋找的位置。較舊版本的 skills CLI 會寫入 ~/.agents/skills/,但不會將結果連結至 ~/.claude/skills/,因此檔案雖存在磁碟上,agent 卻不會載入。執行 npx skills@latest add ... 可避免使用過時 CLI 的問題。

建議採用手動方式,因為這樣可以記錄實際安裝的內容:

git clone https://github.com/AmazingAng/old-coder.git
cd old-coder
git checkout acc5a89
git rev-parse HEAD
mkdir -p ~/.claude/skills
cp -r skills/old-coder ~/.claude/skills/

acc5a89 在 17 August 2026 是 main 的最新 commit。請自行選定版本並記錄下來。此 repository 仍在積極開發中,gauntlet 參照、範本及 verifier protocol 已經在不同檔案之間移動。如果 EVIDENCE 報告沒有指出評分時使用的 skill 版本,您就無法判斷變更來自程式碼,還是來自規則。請將該 commit hash 與 SPEC 放在一起,並儲存於管理該程式碼的同一個 repository 中。

如果 agent 不會讀取 ~/.claude/skills,請將 skills/old-coder/SKILL.mdskills/old-coder/references/gauntlet.md 加入其 system prompt 或 rules file。整合工作就完成了。

防護關卡中執行哪些檢查

防護關卡是一組分層檢查,所有規格行為都通過後才會執行一次。此技能包含以下檢查:

  • 完整測試套件,用於防止回歸。不得出現新的失敗;任何既有失敗都必須先記錄為基準。
  • 靜態型別檢查,以及 lint 和格式檢查,用於找出整類錯誤與偏移。
  • 變更行覆蓋率。未達門檻時,命令必須以非零狀態結束。
  • 變異測試,用於找出不會驗證任何內容的測試。
  • 屬性型測試,用於涵蓋沒有人預想到的邊界案例。
  • 複雜度預算、實際執行一次真正的程式、供應鏈與 secret 掃描,以及以隨機順序執行的套件健康檢查。
  • 依任務風險選擇的領域層:並行壓力測試、API 相容性、回滾演練及延遲基準測試。

此示範將這些檢查整合到單一指令檔 demo-rate-limiter/tools/gauntlet.sh 中,並使用 requirements-dev.txt 內鎖定版本的工具鏈:pytest、pytest-cov、coverage、hypothesis、mypy、ruff、pip-audit 及 pytest-randomly。每個工具都鎖定至確切版本(截至 August 2026:pytest 9.1.1、ruff 0.16.0)。執行方式如下:

cd demo-rate-limiter
python3 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt -e .
./tools/gauntlet.sh

此指令檔會為每個層顯示一個標題,例如 === tests + coverage ====== mutation ===,最後顯示 === gauntlet: all layers green ===。它會在 set -e 下執行,因此第一個失敗的層會停止整個流程,最後的標題也不會顯示。看到最後的標題即代表檢查通過:上方的每一層都以零狀態結束。

其中有一個細節值得套用到自己的設定。覆蓋率層的寫法如下:

pytest -q --cov=ratelimiter --cov-report=term-missing --cov-fail-under=100

如果沒有 --cov-fail-underpytest --cov 只會輸出百分比,無論覆蓋率下降多少都會以 0 狀態結束。這會讓原本第一行承諾在第一個失敗層停止的指令檔,包含一個失效開放的層。無法失敗的防護關卡層只是裝飾。

涵蓋率之外,突變測試增加了什麼

涵蓋率只回答一個問題:測試套件是否執行了這一行。它無法回答你真正關心的問題:如果這一行有錯,是否會有任何 assertion 失敗。測試若呼叫函式卻不檢查任何結果,對所有執行到的行仍會回報完整涵蓋率。涵蓋率能找出未測試的程式碼,但找不出什麼都沒測試的測試。

突變測試會直接回答第二個問題。它會刻意修改程式碼,每次只做一個小變更,然後重新執行測試套件。若測試套件失敗,表示該 mutant 被 kill,代表有某個 assertion 正在檢查那項行為。若測試套件仍然通過,表示該 mutant 存活:該行確實執行了,但沒有任何檢查驗證結果。

這個示範使用 tools/mutants.py 完成上述流程。它會將編號過的單一修改植入 src/ratelimiter/__init__.py,每次修改後執行 pytest,最後還原檔案。這些修改模擬疲憊的人員容易犯的錯誤:>= 變成 >,或遺漏 return 值。

這個 runner 的 kill 規則,是許多自行撰寫的突變測試 script 最容易弄錯的部分。只有 pytest 結束代碼 1 才算 kill,因為 1 表示測試已執行,且至少有一項測試失敗。結束代碼 0 表示 mutant 存活。其他任何結果,例如 collection error 或完全沒有收集到測試,都表示沒有完成驗證,不能計入。若 script 將「非零」一律視為 kill,就會把自身的當機算成成功,而該數字只會持續上升。

同一個檔案中還有兩個需要如實說明的細節。其中一個 mutant,M11,不在清單中,因為它是 equivalent mutant:在單調時鐘下,只清除一筆過期項目與清除所有過期項目會產生相同的可觀察行為,因此沒有任何測試能 kill 它。runner 會設定 PYTHONDONTWRITEBYTECODE=1,而 gauntlet 會先刪除所有 __pycache__,因為兩個大小相同且在同一秒寫入的 mutant 可能共用快取的 .pyc,導致第二個 mutant 沿用第一個 mutant 的判定結果。

這項風險正是 gauntlet 在正式突變測試前先執行 negative control 的原因:

.venv/bin/python tools/mutants.py --negative-control
.venv/bin/python tools/mutants.py

該 control 會在固定的修改時間下執行兩個 mutant:一個必須被 kill,另一個嚴格等價且必須存活。若兩者都回報為 killed,表示 bytecode cache 在執行之間外洩,報告中的所有 kill 計數都會被高估。這正是本技能所說的 checker 規則具體化的例子。pytest 和 mypy 經過多年的使用,已建立可信的失敗行為。你上週才撰寫的 script 還沒有,因此在它通過時信任它之前,先證明它能夠失敗,並將這項證明記錄在 EVIDENCE 中。

ChartMutants killed by each suite run alone (demo-rate-limiter evidence.md, August 2026)
The data behind this chart
[
  {
    "label": "Scenario tests",
    "mutants_killed": 22,
    "mutants_run": 22
  },
  {
    "label": "Property tests",
    "mutants_killed": 3,
    "mutants_run": 22
  }
]

示範本身的 EVIDENCE 報告說明了為何單一彙總數字仍會隱藏重要資訊。scenario suite kill 了 22 個 mutant,共執行 22 個 mutant。針對相同的 mutant 單獨重新執行 property-based tests 時,kill 了 3 個。系統會將 kill 歸因於最先失敗的測試,因此完美的總數只能驗證整個測試套件,無法說明其中任何一層的情況。這些 properties 仍然有存在價值,因為它們能捕捉沒有人列舉過的輸入形狀。但它們並未承擔正確性的主要負擔;只有分別測量每一層,才能得知這一點。

在伺服器上完整執行測試,不要在筆記型電腦上執行

EVIDENCE 報告宣稱某些命令產生了某些數值。只有其他人能產生相同數值時,這項宣稱才可驗證,而筆記型電腦是最不適合進行驗證的環境。你的 Python 可能是不同的修訂版本,而你的 PATH 可能包含下一台機器沒有的工具。變異測試會讓問題更嚴重,因為它會針對每個變異體重新執行整套測試,因此示範中的清單本身就代表額外執行 22 次測試套件。

將它放入 VPS 上的容器。容器固定作業系統與直譯器,鎖定版本的 requirements-dev.txt 固定工具,而 VPS 提供一台不會同時執行瀏覽器的機器。

FROM ubuntu:24.04
RUN apt-get update && apt-get install -y --no-install-recommends \
      python3 python3-venv git ca-certificates \
 && rm -rf /var/lib/apt/lists/*
WORKDIR /work
docker build -t gauntlet:24.04 .
docker run --rm -v "$PWD:/work" -w /work/demo-rate-limiter gauntlet:24.04 \
  sh -c 'python3 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt -e . && ./tools/gauntlet.sh'

成功的執行會在 === gauntlet: all layers green === 結束。有兩個步驟需要對外連線:pip 安裝鎖定版本的工具,以及 pip-audit 層。該層會將相依套件與漏洞服務比對。離線執行不會靜默略過這一層。它會失敗,而這正是閘門應有的行為。

若要在每次 push 時執行相同的腳本,可將它設為一個 CI 工作步驟。此 repository 會在 GitHub Actions 上,使用 Python 3.12,於 ubuntu-latest 執行自己的完整測試。將 runs-on 指向 self-hosted runner,工作就會改在你的 VPS 上執行:

name: gauntlet
on:
  push:
    branches: [main]
jobs:
  gauntlet:
    runs-on: self-hosted
    defaults:
      run:
        working-directory: demo-rate-limiter
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - run: python -m venv .venv && .venv/bin/pip install -r requirements-dev.txt -e .
      - run: ./tools/gauntlet.sh

將觸發條件限制為你控制的分支上的 push。若 self-hosted runner 也建置來自 fork 的 pull request,就會在你的伺服器上使用 runner 的憑證執行陌生人的程式碼。同樣的原則也適用於 agent 本身:應提供 可直接丟棄的 VM,不要使用工作站。若希望完整測試結果傳送到討論變更的位置,請將它整合到 self-hosted PR review agent

此方法失效的情況

第一個問題出在結構本身,任何工具都無法消除。gauntlet 會將 SPEC 中的限制轉換成可執行的證據,但無法判斷 SPEC 是否正確。若核准了包含錯誤需求的 spec,得到的會是針對錯誤程式的完整 EVIDENCE 報告:涵蓋率完整、所有 mutant 都被測試淘汰、每一層都顯示通過,但軟體執行的功能並不是你要的功能。未閱讀 diff 所省下的每一小時,都應該用來閱讀 spec。

第二個問題是檢查器。repository 在自己的 evidence file 中如實記錄了這點。其獨立驗證 protocol 執行了六輪,第六輪回傳 failed;第六輪之後完成的修正從未重新驗證,因此實際發布的狀態並未完成端對端驗證。shell lint layer 被記錄為 unavailable,而不是 pass。較早的輪次曾發現真實的行為缺陷,以及埋藏在先前已回報 green 狀態後方、但本身不可靠的 mutation runner。gauntlet 顯示 green,並不代表它已完成自我驗證。

第三個問題是範圍。手寫的 mutant 清單只能涵蓋有人想到要植入的錯誤,而從清單中刪除的每個 equivalent mutant,都是你選擇信任的一項判斷。現成的 mutation tools(mutmut、cosmic-ray、Stryker、PIT)會系統化產生 mutants;只要你的語言有對應工具,這些工具通常是較好的預設選擇。

依風險調整投入程度

這項技能定義 3 個層級,並要求 agent 宣告所選的層級。

  • Tier 1,簡單:錯字、註解或設定值。執行完整測試套件與 lint,不新增測試,並用一句話說明不需要新增測試的原因。
  • Tier 2,一般:錯誤修正或小型功能。執行完整流程。錯誤修正必須先從能重現錯誤的失敗測試開始,讓昨天的錯誤成為明天的回歸測試。
  • Tier 3,高風險:金流、驗證、資料遺失、並行處理或公開 API。先建立失敗模型,列出這項變更可能造成傷害的方式;再為每種模式加入完整的測試關卡,接著執行完整流程、性質測試、mutation testing,以及一次明確針對實作、使用惡意輸入的攻擊測試。

Tier 3 另包含一個實驗步驟。另一個 agent 使用全新的上下文,只能看到任務契約、核准的 SPEC 與原始碼狀態,並在簽署 EVIDENCE 前嘗試破壞已完成的工作。它不修正任何內容,只提交報告,再由人員評估其發現。這能降低因共用任務上下文而產生的相關性,但無法降低因共用同一模型而產生的相關性。

如果你想建立類似的技能,而不是採用這項技能,撰寫自己的 agent 技能涵蓋檔案配置,以及決定 agent 何時載入該技能的 description 欄位。

FAQ

Mutation testing 能捕捉哪些 code coverage 遺漏的問題?

Coverage 只能記錄某一行是否執行過。它無法記錄該行若有錯誤,任何 assertion 是否會失敗。因此,即使測試呼叫函式後完全不檢查結果,仍可能回報完整 coverage。Mutation testing 會刻意修改程式碼,每次只進行一項變更,然後重新執行測試套件。仍然存活的 mutant 表示該行確實執行了,但沒有任何測試驗證結果。這也是為什麼該技能將「絕不追逐 coverage 數字」列為絕對規則,並指出 mutation 是用來避免測試造假的那一層。

我仍然需要閱讀 agent 寫出的程式碼嗎?

依照這套流程,你會在撰寫程式碼前閱讀 SPEC,完成後閱讀 EVIDENCE 報告,並重新執行報告中引用的指令進行抽查。Diff 變成選用項目。問題在於,現在所有判斷都集中在同一份文件上,因為如果 SPEC 中的需求本身錯誤,就會為你根本不需要的程式產生一套全數通過的測試關卡。把省下的時間花在 SPEC 上。

我可以在自己的伺服器上於 CI 執行 Old Coder gauntlet 嗎?

可以,而且 CI 正是更適合執行它的地方。在 container 內安裝 requirements-dev.txt 指定的 toolchain,並將專案的 gauntlet script 作為一個 job step 執行。在 GitHub Actions 中設定 runs-on: self-hosted,並在你的 VPS 上註冊 runner。請將觸發條件限制為你所控制分支的 push,因為 self-hosted runner 若建置來自 fork 的 pull request,就會使用 runner 的憑證執行不受信任的程式碼。

我應該安裝哪個版本的 skill?

固定使用一個版本。此 repository 正在積極開發中,參考檔案也已經拆分並移動,因此上個月產生的報告,可能是依據不同規則評分。Clone repository,checkout 特定 commit,將 skills/old-coder 複製到 ~/.claude/skills/,並在 SPEC 旁記錄該 commit hash。如此一來,evidence 的變更就代表程式碼有所變更。