test-driven-development (obra/superpowers)
失敗するテストを先に書き、その後に実装コードを書くテストファーストで機能追加や修正を行います。
superpowers テスト駆動開発:エージェントにまずテストを書かせます。トークンは約 1.6 倍かかります。
Codex CLI · gpt-6-astra
24.0 / 30
スキルなしに対するリフト:+1.00 · 推奨 · 18 実行
推奨:合計 24.0/30 が 22 以上、出力品質 5.0 が 3.5 以上、リフト +1.00 が +1.0 以上。
SOTA
合格Codex でテスト済み。
カバー対象 Codex, Claude Code
Codex CLI 0.166(SOTA ティア):採点対象 18 実行。当ティアのルールでは、ここでの合格は Claude Code もカバーします。第2ティアについては何も述べません。
スコア
各ディメンションは 0〜5 点で、6 つの合計が 30 点満点の合計スコアになります。すべてのディメンションで 5 が最良です。コスト 5 は低コストで高速、インストール 5 は簡単であることを意味します。
- トリガーの信頼性
- 5.0
- スキルなしに対するリフト
- 3.0
- 出力品質
- 5.0
- トークンと時間のコスト
- 2.0
- インストールと移植性
- 4.0
- 安全性
- 5.0
セキュリティレビュー
安全静的スキャン:CRITICAL 0 / HIGH 0 / MEDIUM 0。手動レビュー:ネットワーク無効のサンドボックスで実行しても安全(指摘なし)。クリーンなスキャン結果はスキルの安全性を証明しません。
インストール
npx skills@latest add obra/superpowers --skill test-driven-development
固定コミット: 2ce8aa15d05bd57213e6f746f953aafb7ded7a8b
テスト済み: 2026-11-02
テスト内容
- 正確な仕様から関数を実装 — slug.py(Python 3、標準ライブラリのみ)に slugify(text, max_length=None) を実装してください。仕様:テキストを小文字にする。ASCII の英字でも数字でもない文字の連続を 1 つの '-' に置き換える。先頭と末尾の '-' を取り除く。結果が空になる場合は 'n…
- 小さなステートフルなクラスを実装 — ratelimiter.py(Python 3、標準ライブラリのみ)に class RateLimiter(limit, window_seconds, clock=time.monotonic) を書いてください。キーごとのスライディングウィンドウ制限です。allow(key) は、直近の window_seconds 内に記録された呼び出しが limit 件未満なら True を返してその呼び出しを記録します。…
- 丸めバグを修正 — お客様から、cart.py の cart_total が会計システムと比べて 1 セントずれることがあると報告されています。会計システムは各ステップ(各行の合計、割引後の小計、税金)でセント単位に切り上げて四捨五入します。例えば cart_total([(1.005, 1)]) は 1.09 を返すべきですが…
長所
- スキルなしと比べ平均スコアを 4.0 から 5.0 に引き上げ(+1.00)。
- スキルは名前を出さずとも採用されました:スキルあり群 6/6 実行でスキルファイルが読み込まれました。
- 自身のルールの一文版を +0.33 上回ります。
- スキルありの絶対品質は高水準:5 点中 5.0。
短所
- スキルなしの 1.65 倍のトークンを消費。
- テスト上の注意:一文プロンプト群(6 実行)は後から、対照群とスキルあり群とは別のマシンで追加されました。
- タスク・群ごとに n=2。1 ポイント未満の差はノイズです。
レビュー
Mac テストマシン上で Codex CLI 0.166(gpt-6-astra、低推論)、実行ごとに新規の一時プロジェクトと一時 HOME/TMPDIR/キャッシュを使用、スキルをインストール(スキルあり群)、スキルなし(対照群)、またはスキルの中核要件をプロンプト末尾に付けた一文に圧縮(一文プロンプト群)、タスクごとに各群 2 実行、ネットワーク無効、/tmp への書き込みはブロック。プロンプトはスキル名に一切言及しません。採点はプログラム的(隠しテスト/仕込み問題の検出/制約チェック/該当する場合はレンダリング+OCR)で、実行ごとに 0〜5 点。スコアはどの LLM 判定者も決めていません。
3群の比較
| 群 | 平均スコア(0〜5) | 1実行あたりのトークン |
|---|---|---|
| スキルなし | 4.0 | 65k |
| 一文プロンプト | 4.67 | 127k |
| スキルあり | 5.0 | 108k |
Codex CLI で 18 実行を計測し、LLM 判定なしのルールベースのチェックで採点。合計 24.0 / 30、判定は 推奨。
開示事項 一文プロンプト群(6 実行)は、対照群・スキルあり群とは別のマシンで後から追加しました。
判定:推奨(24.0 / 30)。 出典:obra/superpowers、skills/test-driven-development、コミット 2ce8aa1 に固定。インストール:npx skills@latest add obra/superpowers --skill test-driven-development。ライセンス: MIT(リポジトリの LICENSE)。
概要
obra/superpowers の test-driven-development スキル。その説明文には「機能やバグ修正を実装する際、実装コードを書く前に使う」とあります。約 1,500 語の Markdown(red-green-refactor の「鉄則」、テストを省く言い訳の表、検証チェックリスト)に、良いテストの書き方に関する追加ファイルが 1 つ。スクリプトなし。
テスト方法
Mac テストマシン上で Codex CLI 0.166(gpt-6-astra、低推論)、実行ごとに新規の一時プロジェクトと一時 HOME/TMPDIR/キャッシュを使用、スキルをインストール(スキルあり群)、スキルなし(対照群)、またはスキルの中核要件をプロンプト末尾に付けた一文に圧縮(一文プロンプト群)、タスクごとに各群 2 実行、ネットワーク無効、/tmp への書き込みはブロック。プロンプトはスキル名に一切言及しません。
- 正確な仕様から関数を実装 — slug.py(Python 3、標準ライブラリのみ)に
slugify(text, max_length=None)を実装。仕様:テキストを小文字にする。ASCII 英数字以外の文字の連続を単一の '-' に置換。先頭と末尾の '-' を除去。結果が空の場合は 'n… になる。 - 小さなステートフルクラスを実装 — ratelimiter.py(Python 3、標準ライブラリのみ)にクラス
RateLimiter(limit, window_seconds, clock=time.monotonic)を書く:キーごとのスライディングウィンドウ制限。allow(key)は、直近の…以内に記録された呼び出しがlimit未満なら True を返して呼び出しを記録。 - 丸めバグの修正 — 顧客によると、cart.py の
cart_totalが、各ステップ(各行の小計、割引後の小計、税)でセント単位に四捨五入する当社会計システムと比べて、ときどき 1 セントずれるそうです。例:cart_total([(1.005, 1)]) は 1.09 を返すべきで、…
採点はプログラム的(隠しテスト/仕込み問題の検出/制約チェック/該当する場合はレンダリング+OCR)で、実行ごとに 0〜5 点。スコアはどの LLM 判定者も決めていません。
結果
第 3 群に与えた一文プロンプト:"厳格な red-green-refactor に従う:最初に失敗するテストを書き、正しい理由で失敗することを確認し、それを通過する最小限の実装を書き、それからリファクタリングする。失敗するテストを先に書かずにプロダクションコードを書かない。"
| タスク | 対照群スコア | 一文プロンプト | スキルあり | 対照群トークン | 一文プロンプトトークン | スキルありトークン | スキル読み込み |
|---|---|---|---|---|---|---|---|
| t1-slugify | 4.0 | 5.0 | 5.0 | 62k | 134k | 108k | 2/2 |
| t2-ratelimiter | 4.0 | 5.0 | 5.0 | 63k | 147k | 97k | 2/2 |
| t3-cart-bugfix | 4.0 | 4.0 | 5.0 | 69k | 97k | 116k | 2/2 |
平均スコア:スキルなし 4.0 vs スキルあり 5.0(差分 +1.0)。1 実行あたりのトークン:65k vs 108k(1.65 倍)。時間:55s vs 51s。一文プロンプト群:4.67(一文プロンプトに対するスキルの上乗せ:+0.33。一文プロンプト自身のスキルなしに対する上乗せ:+0.67)。一文プロンプトのトークンは 1 実行あたり 127k、つまりスキルのコストは一文プロンプトの 0.85 倍。
何が起きたか
- 正しさは同一でした:隠しテストスイートは両群の 12 実行すべてで合格(12/12、10/10、11/11 テスト)。これらの小さなタスクでは、スキルはコードが動くかどうかを変えません。
- 変わるのは作業の順序です。6 回のスキルあり実行すべてで、テストファイルが実装より前のステップで書かれました。6 回の対照群実行すべてでは、エージェントはテストと実装を同じパッチで書きました(cart のタスクでは、先にバグを修正して後からテストを追加)。読み通したスキルあり実行(slugify)では、エージェントはテストを書き、実行して失敗を確認し、それからコードを書きました。
- 説明文だけでトリガーされます:どのプロンプトも TDD に言及していないにもかかわらず、スキルファイルはスキルあり群 6/6 実行で読み込まれました。
- コストは増えます:1 実行あたり約 1.65 倍のトークン(107k vs 65k)で、実時間はほぼ同じ(51 秒 vs 55 秒)。エージェントがスキルと付属ファイルを読み、ループを数回回すためです。
- 一文版(厳格な red-green-refactor、失敗するテストなしにプロダクションコードを書かない):平均 4.67 で、対照群(4.0)とスキル(5.0)の間。1 実行あたり 127k トークン(対照群 65k、2.0 倍。スキル 108k、スキルの 1.2 倍)。
- テストが実装より先に書かれたのは、対照群 0/6、一文プロンプト 4/6、スキルあり 6/6。一文プロンプトで欠けた 2 実行は cart のバグ修正タスクです。毎回実行したのはスキルだけであり、コマンド数も一文プロンプト(19)より少なく済みました(1 実行あたり 10)。
評価項目別スコア
| 評価項目 | スコア | 理由 |
|---|---|---|
| 出力品質 | 5.0 | スキルありの平均スコアは 5.00/5(プログラム的チェック。タスク別の表を参照)。 |
| スキルなしに対するリフト | 3.0 | スキルなしの 4.00 に対して +1.00 ポイント(タスクごとに n=2。約 1 ポイント未満の差はノイズ)。 |
| トリガー | 5.0 | スキルあり群 6/6 実行でスキルファイルが読み込まれました。 |
| 手順の移植性 | 4 | |
| 効率 | 2 | トークン 1.65 倍(1 実行あたり 108k vs 65k)、時間 0.93 倍(51s vs 55s)。 |
| 安全性と衛生 | 5 |
このテストの限界
- 隠しテストは両群ともすべて合格(天井)するため、測定されたリフトはプロセスチェック(実装前にテストを書いたか)であり、私たちがイベントログから算出したもので、成果の差ではありません。
- タスクは小さな単一ファイルの Python 演習です。より大きなリポジトリ、他の言語、テスト品質(ミューテーションテストなど)はテストしていません。
- タスク・群ごとに n=2。約 1 ポイント未満の差はノイズです。
- ルールベースの採点はチェックが捉えられる範囲を測るもので、センスや、その結果が最善かどうかは判定できません。
セキュリティ
security.md を参照。スキャン:CRITICAL 0 / HIGH 0 / MEDIUM 0。判定:実行しても安全(ネットワーク無効のサンドボックス)。クリーンなスキャン結果はスキルの安全性を証明しません。
結論
言ったとおりに機能します:失敗するテストを毎回最初に書いたのはこの群だけです(6/6。対照群 0/6、一文版 4/6)。トークンは対照群の 1.7 倍、一文版の 0.85 倍。これらの小さなタスクでの最終的な正しさは全群で同じだったため、得られるのはコードではなくプロセスです。
トランスクリプト
実行ログ:test-driven-development (Codex CLI, network off, per-run temp HOME/TMPDIR, one row per graded run.) 列:タスク、群-回、スコア(0-5)、トークン、秒、合格したチェック、エージェントが開いたスキルファイル。 t1-slugify control-1: スコア 4.0, トークン 62017, 秒 55.5, チェック 2/3, 開いたファイルなし t1-slugify control-2: スコア 4.0, トークン 62139, 秒 53.8, チェック 2/3, 開いたファイルなし t1-slugify oneliner-1: スコア 5.0, トークン 135535, 秒 52.9, チェック 3/3, 開いたファイルなし t1-slugify oneliner-2: スコア 5.0, トークン 134448, 秒 46.7, チェック 3/3, 開いたファイルなし t1-slugify treatment-1: スコア 5.0, トークン 118034, 秒 56.3, チェック 3/3, 開いたファイル test-driven-development t1-slugify treatment-2: スコア 5.0, トークン 97974, 秒 48.3, チェック 3/3, 開いたファイル test-driven-development t2-ratelimiter control-1: スコア 4.0, トークン 63363, 秒 46.1, チェック 2/3, 開いたファイルなし t2-ratelimiter control-2: スコア 4.0, トークン 63431, 秒 98.9, チェック 2/3, 開いたファイルなし t2-ratelimiter oneliner-1: スコア 5.0, トークン 140042, 秒 60.8, チェック 3/3, 開いたファイルなし
18 実行、3 成果物
サンプル出力
SOTA · With the skill: test_slug.py (t1-slugify, run 1, Codex)
import unittest from slug import slugify class SlugifyTests(unittest.TestCase): def test_normalizes_text(self): cases = [ ('Hello, World!', 'hello-world'), (' --ABC__123\t\nxyz!! ', 'abc-123-xyz'), ('café déjà vu 12٣', 'caf-d-j-vu'), ('İ X', 'i-x'), ('already-a-slug', 'already-a-slug'), ] for text, expected in cases: with self.subTest(text=text): self.assertEqual(slugify(text), expected) def test_empty_result_uses_fallback(self): for text in ('', '--- !\t', '中文', '😀'): with self.subTest(text=text): self.assertEqual(slugify(text), 'n-a') def test_length_limits_respect_word_boundaries(self): cases = [ ('Hello, World!', 8, 'hello'), ('Hello, World!', 11, 'hello-world'), ('Hello, World!', 20, 'hello-world'), ('Hello, World!', 5, 'hello'), ('Hello, World!', 6, 'hello'), ('one two three', 7, 'one-two'), ('one two three', 9, 'one-two'), ('Supercalifragilistic', 5, 'super'), ('Supercalifragilistic next', 5, 'super'), ('abc', 1, 'a'), ('abc', 0, ''), ('!!!', 1, 'n'), ('!!!', 2, 'n'), ('!!!', 3, 'n-a'), ] for text, limit, expected in cases: with self.subTest(text=text, limit=limit): self.assertEqual(slugify(text, limit), expected) def test_explicit_none_leaves_length_unlimited(self): self.assertEqual(slugify('Hello, World!', None), 'hello-world') if __name__ == '__main__': unittest.main()