AI のいうことを、私は確かめずに済ませています。「テストは通っています」も、「画面で確認しました」も同じです。そうすることができるのは、いつ・何回・どこまで・どの手段で確かめるかを、確認を走らせる前に決めておく仕組みを、先に置いてきたからです。連載「確かめない技術」は、その状態を仕組み一つずつで作ってきた記録で、この記事は、その最終回にあたります。確かめ方をその場でAIに決めさせていたときに起きていたのは、検証は高い手段へ流れるという問題(grep で分かることまで、AI が画面で確かめにいくこと。第 1 回)、確認と再実行は区別されないという問題(通ったばかりのテストを、AI が「最終確認」と書いて走らせ直すこと。第 3 回)、速くする工夫は死角を隠すという問題(間引いたテストのことが、AI の報告から消えること。第 5 回)でした。各回の仕組みへの入口は、序論の一覧です。

白状することが一つあります。

私も、仕組みを置いた日には確かめています

各回の終盤に「検証手順」という節があります。置いた仕組みが働くかどうかを、状況をわざと作って確かめる手順です。「確かめない技術」と題した連載が、第 1 回から第 5 回まで、どの回も検証手順で終わっています。

あなたは、テストが 2 本同時に走るのを止める仕組みを置き、2 本目が止まることを、置いた日に自動テストで確かめました。止まったときの案内には、どうしても走らせたいときに付ける環境変数(逃げ道)も書いてあります。ところが、案内どおりに逃げ道を付けて走らせても、テストは止まりました。このとき、あなたなら次のどちらを選びますか。

  • 塞がった逃げ道は、使っていて止められたときに、その場で直す
  • 止まるべきものと通るべきものの両方を、合格条件に書いてから確かめる

答えは、両方を合格条件に書いてから確かめるほうです。逃げ道を付けても止まったのは、案内どおりの形で逃げ道を付けた実行が通ることを、置いた日に確かめていなかったからです。止める仕組みは、通るべきものまで止める壊れ方をしても、止まることを確かめる項目には合格します。その場で直すことにすると、塞がった逃げ道は、通したい実行が止められたときに初めて見つかります。逃げ道が要るのは、仕組みが通るべき実行まで止めたときです。そのときに逃げ道も塞がっていれば、テストを走らせる手段がありません。私の手元では、テストの並走を止める仕組みを置いた日の点検で、止める側だけを確かめて通す側を確かめていなかったことに気づき、案内した逃げ道が 3 か所で塞がっているのを見つけました。そのうち 1 か所は、仕組みそのものが壊れたときに使う、最後の逃げ道でした。私は、逃げ道が通ることを確かめる項目を、自動テストに足しました。通るべきものを合格条件に書いておけば、通す側の壊れは、置いた日のうちに、落ちる項目として出ます。

理解したことは一文にできます。

止まることだけを確かめると、通るべきものまで止める壊れ方は見えない。だから仕組みを置く日に、止まるべきものと通るべきものの両方を、合格条件に書いてから確かめる。

私の手元でも、仕組みを置いた日の確かめ方は、この形です。第 2 回の hook(コマンド実行の直前に割り込むスクリプト)は、置いた日の自動テストで、撮影の前にAIに書かせる宣言(何を検証するかと、grep や単体テストではなぜ済まないかの 2 問への答え)が無ければ撮影が止まり、宣言が埋まっていれば撮影が通ることを確かめました。第 4 回のロック(テストを 1 本しか通さない仕組み)は、置いた日の自動テストで、生きているプロセスがロックを取っているあいだは 2 本目のテストが走り出す前に止まり、ロックが無ければ通ることを確かめました。

どちらの自動テストも、何が起きたら合格とするかを、走らせる前にテストのコードに書いてあり、確かめ方は、確かめる前に決まっています。各回で、AI が確かめる前に、確かめ方を仕組みに決めさせてきたのと同じ形です。

仕組みを置いた入口は、2 つだけです

回先に決めたこと置いたもの置いた先
1手段撮影の前の 2 問と、grep・単体テスト・撮影の順に安いほうから試す決まり指示文 1 枚と、撮影の入口に 1 行
2形跡宣言ファイルの存在を実行の前提にする hook撮影・スモークの入口
3回数前回の結果を読み直す --lastテストの入口
4同時に走らせる本数1 本しか通さないロックテストの入口
5範囲間引きと、走らせていない領域の一覧テストの入口

第 1 回の 1 行は、宣言に「念のため」のような理由が書かれていたら撮影を止める 1 行です。記事では、この 1 行を撮影スクリプトの冒頭に、第 3〜5 回の 3 つを、1 作目「読まない技術」の第 1 回で置いた、テストのコマンドを包んで代わりに実行するスクリプト(ラッパー)1 本に足す形で示しました。

表の「先に決めたこと」を実行より先に決めておくことができたのは、決めたことを、コマンドが必ず通る場所(入口)に置いたからです。第 2 回と第 4 回に書いたとおり、入口に置いた仕組みが見ているのは、その入口を通った実行だけです。テストの入口は、1 作目 第 1 回で、ラッパーを通さずに rails test を直に打つと止める仕組み(hook)を置いて、ラッパー 1 本にまとめてありました。撮影・スモーク(AI がブラウザを自動で動かし、画面で確かめること)の入口は、1 本にまとまっていませんでした。第 2 回で、hook に止める対象として名前を書いたのは、ラッパーの内側で動くスクリプトです。私が普段使っている 14 本のラッパーは、呼び出すコマンドにその名前が出てこないので、hook を判定なしで通っています(第 2 回)。入口がそれぞれ 1 本にまとまっていることが、この連載の仕組みの前提です。

減らしたぶんは、どこかに出ています

5 回で示した仕組みについて、しなくなったことと、その代わりに毎回出るものを並べます。

回しなくなったこと代わりに、毎回出るもの
1スクリーンショットを撮らない残った画像に「何を検証した画像か」の 1 文
2宣言を信じないhook が判定するたびに、日時と理由が記録に 1 行
3テストを再実行しない前回の要約と、全文を残したログの場所
4偽の失敗を読まない走っている 1 本目の開始時刻と、待つか --last かの案内
5全部走らせない走らせていない領域の数が、私の画面に 1 行

確認は、どの回でも続いています。なくなったのは、確かめ方をその場で決める仕事です。右の列のものは、誰かがその場で決めなくても、毎回出ます。確かめずに済ませてよいのは、減らしたぶんが毎回どこかに出る確認だけです。

死角は、全部そのままです

各回の注意に、その仕組みの死角を書いてきました。検証の手段が安いか高いかを決めているのは AI 自身で、撮影の前の 2 問にAIが書いた答えが正しいかは、誰も見ていません(第 1 回)。hook も宣言の体裁しか見ないので、それらしい 1 文が入っていれば、宣言は通ります。しかも、hook が拾うのは、hook に名前を書いた入口だけです(第 2 回)。--last が近道になるのは、コードを変えていないときだけです(第 3 回)。ロックが止めるのは、同じ作業ディレクトリで走る 2 本目だけで、別のクローンやCIで走るテストは止めません(第 4 回)。一覧と数の行がするのは、走らせ忘れを見えるようにするところまでです(第 5 回)。

第 1 回と第 2 回の、宣言の中身の死角は、塞がずに残してあります。理由は第 1 回の出発点と同じで、「この検証は単体テストで済むか」の真偽を、プログラムには決めることができないからです。塞ぐには、AI が書いた宣言の中身が正しいかを判定する仕組みを、もう一段作ることになります。その判定が正しいかも、また誰かが判断することになります。

結論

確かめない技術は、確かめ方を、その場で決めない技術です。

確認は、やるかやらないかの二択に見えます。実際には、やると答えたあとにも、決めることが残ります。いつ・何回・どこまで・どの手段で確かめ、どんな形跡を残すかです。私が二択で答えた時点で、残りを決めるのは、その場にいるAIです。

AI がどう決めたかは、報告には出てきません。

だから、確かめ方を、実行より前に決めておくことにしました。決めたことは、指示文 1 枚のほかは、撮影・スモークの入口と、テストの入口の 2 つに置きました。確かめ方が先に決まっていれば、どう確かめたかをAIの報告から探さなくて済みます。

それでも、確かめる日は残ります。仕組みを置く日です。

その日に一度だけ、状況をわざと作って、止まるべきものが止まり、通るべきものが通ることを確かめてください。

合格条件を先に書いてから走らせれば、その確認も、確かめ方を先に決めた確認になります。

序論で、直近のセッションで確かめるために実行した回数を数えてください、とお願いしました。そのうち、実行する前にどこまで確かめるかが決まっていたものは何回あったか、という問いです。

いま同じ問いに答えると、私の手元では、テストの入口を通った実行と、hook が名前を拾う入口から走った撮影は、全部です。14 本のラッパーから走った撮影とスモークは、hook が判定せずに通しているので、決まっていたかどうかが記録に残りません。


この仕組みを置いてから私が作ったものは、typingtube で動いています。確かめずに済んだぶんの時間で作った画面が、そこに並んでいます。