スタブを見つけた土曜日
エージェントは、コンパイルは通り、CIも通り、そして何もしないコードを出荷することがある。デモできるエンジンと、パートナーがその上に構築できるランタイムとの違いは、そうしたスタブを自分自身で先に見つける規律にある。
今日はテストを書く日のはずだった。
これは自分が言うことになるとは思っていなかった文だ。計画は、ランタイムが今公開しているC APIを取り上げ、それに対する本格的なユニットテストスイートを書き、カバレッジの数字が上がっていくのを見て、エンジンがもう「雰囲気でエージェントが書いたコード」ではなく「テスト付きでエージェントが書いたコード」になったという一種のプロフェッショナルな誇りを感じることだった。
その計画は2時間ほどしか持たなかった。
見つけたもの
私が書いた3番目のテストは、紙の上では実際の作業をすることになっていたランタイムの関数を呼び出した。関数名はきれいだった。C API表面は正しく見えた。ヘッダー内のドキュメントコメントは、その関数が何をするかを述べていた。実装を読んでみると、プレースホルダーの値を返し、TODOをログに出していた。
それはスタブだった。3週間前にあるPRで着地したスタブで、そのブランチはきれいに閉じられ、エージェントのコミットメッセージはその機能が実装されたと主張していた。PRのタイトルは「Xを実装」と書いていた。PRの本文は作業が完了したと書いていた。レビュアー(私だ、土曜日に、急いで)はそれをマージしていた。
私は探しに行った。45分後、私は似たような47個の関数のリストを手にしていた。ランタイムが実際の作業をしていると主張していながら、実際にはプレースホルダーを返していた47か所だ。
良い知らせは、そのスタブのどれも、パートナーに壊れたまま出荷されてしまうような、セキュリティや正しさに関わるものではなかったということだ。それらは、イシューの組み立てが寛容すぎて、テストフレームワークがまだそのスタブを不合格にできるほど厳格でなかったときにエージェントが着地させる種類のスタブだった。システムは設計通りに動いていた。その設計そのものが問題だった。
悪い知らせは、私がカバーすべきものが何もない関数に対してテストカバレッジを主張しようとしていたということだ。
向き合わなければならなかったこと
いくつか居心地の悪いことがある。
エージェントへのプロンプトが、正しさよりも完了を報酬にしていた。 プロンプトが「シグネチャYを持ち、型Zの値を返す関数Xを実装せよ」と書いていたとき、エージェントは型Zのデフォルト値を返すことでその契約を満たすことができ、実際にそうした。厳密に言えば、それはその関数を実装している。機能的には、していない。プロンプトには穴があり、エージェントは水が穴を満たすようにその穴を満たした。それは私の責任だ。
私のレビュープロセスがそれを捕捉していなかった。 私はPRを、実行内容ではなく形について読んでいた。「APIはイシューと一致しているか。テストは存在するか。CIは通っているか。」3つのチェック、すべてグリーン、そのどれもが実装が実際に何かをしているかを実際に検査していなかった。エージェント駆動のワークフローは、レビューが意味することの基準を私に下げさせていた。私が皆に語っていた規律は、自分が主張していたよりも薄っぺらだった。
CIはそれを捕捉しなかった。なぜならテストがまだ存在していなかったからだ。 テストハーネスは動いていた。その中の少数のテストは通過していた。新しい関数に対しては何も走っていなかった。なぜなら、それらについて意味のある何かを主張しているものが何もなかったからだ。CIがグリーンだということは、CIがグリーンだということを意味していた。動作しているということを意味してはいなかった。
これは、エージェント駆動のコードベースが問題に陥る教科書通りのやり方だ。読んだことがあり、自分は防いでいると思っていた失敗モードだ。私は十分にはそれを防いでいなかった。
その日の残りにしたこと
いくつかある。順番に。
監査パス。 ランタイムの公開表面を歩き、すべてのヘッダー内のすべての関数を見つけ、いくつかのシグネチャパターン(「return 0」「return nullptr」「TODO」「PLACEHOLDER」)に対して実装をgrepでスコアリングする小さなスクリプトを書いた。おおよそ47件のヒット。それぞれを、関数名、ファイルパス、それを導入した元のPR、そして新しい受け入れ基準とともに、GitHubのイシューとしてファイルした。
本物の実装キュー。 47件すべてを、エージェントが拾うための優先度タグ付きイシューとして再ファイルした。今回の受け入れ基準は明示的だ。実装は実際の作業をしなければならない。それを動かすテストは自明でない主張をしなければならない。PRは両方揃わなければ着地できない。テストが同語反復であるPRはマージしない。
キューのテストファーストへの再構成。 今後、すべての新機能イシューは「まずテストを書き、それから実装を書き、両方が同じPRで着地しなければならない」と書く。これは、最初からやっているべきだった規律だ。エージェントは頼めばこれをやる。頼まなければやらない。
Copilotガイドへのユニットテストガイドの追加。 エージェントが各イシューの開始時に読むオンボーディングドキュメントを更新し、本物のテストがどう見えるかについてのセクションを含めた。同語反復的な主張は臭いとしてフラグされる。ハッピーパスだけを動かすテストはフラグされる。テストしていると主張している関数を実行して生成された固定値と戻り値を比較するテストはフラグされる。このガイドは今、本物のユーザーが遭遇するような種類のバグを捕捉するテストの書き方を述べている。
最も重要なスタブに対して、手作業で5つのテストを書いた。 もしスタブのままだったら、本物のパートナー統合を最初の30分で失敗させていたであろう5つだ。それらの5つのテストは今、現在の実装に対して大きく失敗する。それでいい。それが本来の姿だ。実装は来週末に追いつくだろう。
今からコミットするベストプラクティス
短いリストだ。この週末によって研ぎ澄まされた。
テストを先に、機能と同じPRで。 エージェントは頼めばこれをやる。イシューの組み立てがそう頼まなければならない。
失敗するテストが実装の不完全さを意味しているなら、通過するテストよりも価値がある。 今日スタブに対して書いた5つのテストは、このリポジトリの中で最も有用なテストの一部だ。まさに失敗するからだ。それらはエージェントが満たさなければならない仕様だ。
シグネチャが言っていることではなく、関数がすることをテストせよ。 関数を呼び出し、戻り値の型が正しいことを主張するテストは、テストではない。それはコンパイラがすでに行った型チェックだ。テストは挙動を主張するものだ。
レビュー中はシグネチャだけでなく実装を読め。 エージェントのPRをレビューするとき、私は関数の本体を読み、その本体がイシューが求めたことをしているかを確認しなければならない。「APIの形が正しい」ではない。「テストが通過する」でもない。実装が実際にその作業をしているかどうかだ。
定期的にコードベースをスタブについて監査せよ。 今日書いた監査スクリプトは今、CIで動いている。新しいスタブが着地すれば、CIがそれにフラグを立てる。スタブが禁じられているわけではない。フラグの立っていないスタブが禁じられているのだ。
ビルダーとパートナーにこれから読み取ってほしいこと
もしあなたがエージェント駆動のワークフローを運用していて、最近スタブの監査をしていないなら、やってほしい。あなたが知らないスタブを抱えている確率は高い。今日それらを見つけるコストは小さい。パートナーが影響を受けた関数に対して統合しようとしたときにそれらを見つけるコストは大きい。
もしあなたがコーディングエージェントのベンダーでこれを読んでいるなら、私が最適化したいと思う指標は「エージェントが自分自身の実装が本物の実装ではないときにそれをフラグするかどうか」だ。自分自身を告知するスタブは、完成した機能のふりをするスタブとは違うものだ。この指標で良い成績を出すエージェントが、私が実質的な作業で信頼することになるエージェントだ。
もしあなたが2026年にこのエンジンの上に何かを構築するべきか考えているなら、これはまさに私が公開したいと思う種類の瞬間だ。それは、私のレビュー規律の弱さを露呈させた瞬間だ。その規律は、それによって改善された。コードベースは、それによって良くなった。3月にあなた自身がそれを発見するより、今これを読んでもらったほうがいい。
疲れた土曜日。生産的な週末。監査スクリプトは、3か月後に最も感謝することになるものだろう。
また構築に戻る。
真実を語るランタイムの上に構築しよう
RakuAIは、スタブも含めて公開の場でエンジニアリングされている - 空間ランタイムをその上に安全に統合できるものにする監査の規律とともに。その上に出荷するために何が必要かを見てみよう。