テストが通ることと、修正が正しいことは別
OSS に不具合修正の PR を出そうとして、実装もテストも用意した。ビルドが通ることも確認した。
ところが、あとから調べ直すと、修正そのものが不要だった。それどころか、仮に採用されていたら、別の問題を隠してしまう可能性もあった。
ビルドエラーを直そうとした
Void というフレームワークで、Markdown だけで構成された静的サイトをビルドすると、クライアントビルドで UNRESOLVED_ENTRY が発生する、という問題に取り組んだ。
原因を調べると、このケースではクライアントビルドの入力が空になっていた。一方、クライアントビルド自体は静的ページの prerender に必要なので、ビルド処理は実行される。
そこで、入力が空の場合にだけ、空の仮想モジュールをエントリーとして追加する方法を考えた。実装を追加し、Markdown だけの playground と integration test も用意した。既存のクライアント入力がある場合には影響しないことも確認する方針にした。 修正の説明も書き、あとは PR を出すだけ、というところまで進んだ。
検証した環境と対象ブランチのずれ
最初に問題になったのは、検証した環境と PR の対象ブランチが一致していなかったことだ。 手元で確認していたのは、公開済みの Void のパッケージに修正相当の変更を加えた環境だった。PR の対象ブランチそのものではなかった。
さらに調べると、対象ブランチでは、関連する問題がすでに上流の変更によって解消されていた。つまり、このブランチで修正が必要であることを確認できていなかった。
手元の環境で仮想モジュールが解決され、ビルドが成功すること自体は事実だった。問題は、その結果を、修正が必要であることの根拠として扱ってしまったことだった。検証した環境で何が確認できたのかと、対象ブランチで何が必要なのかは、別の話だった。
空のエントリーが代替できなかったもの
上流の実装を確認すると、修正の捉え方自体にも問題があることが分かった。 既存の変更は、単にクライアントビルドの入力を用意するためのものではなかった。アイランドページや Markdown ページからコンポーネント経由で参照される CSS を収集し、HTML にリンクする役割も担っていた。
一方、自分が追加しようとしていたのは、何も import しない空のモジュールだった。これなら空入力によるビルドエラーは回避できるが、本来のクライアントエントリーが担っていた CSS の収集まで代替できるわけではない。 仮にこの修正が採用されていたら、ビルドは成功しても、必要な CSS が成果物に含まれない可能性があった。表面上のエラーを解消することと、フレームワークが必要とする成果物を正しく生成することを、同じものとして扱ってしまっていた。
本来確認すべきだったのは、入力が空になるという現象だけではない。クライアントエントリーがなぜ必要で、どのような役割を担っているのか、ということだった。
テストが緑であることは何を保証するか
テストで確認できたのは、仮想モジュールの resolveId と load が動作すること、Markdown だけのサイトがビルドされて HTML が生成されること、そしてページからクライアント JavaScript が読み込まれないことだった。
どれも事実として意味がある。ただし、これらはこの修正が必要であることや、成果物が本来の要件を満たしていることまでは証明しない。
テストは、設定した条件を満たすかどうかを確認するものだ。その条件が問題の本質を捉えていなければ、テストが緑でも、間違った修正を正しいと思い込むことがある。 ビルド成功とゼロ JS は確認した。しかし、クライアントエントリーが担う CSS の収集という役割は、テストの確認条件に含まれていなかった。テストが通ることと、問題が解決していることの間には、まだ確認すべきことが残っていた。
AI と開発して、自分で判断すること
今回の作業では、AI を使って調査や実装を進め、テストを考え、PR の説明を整理した。作業を進めるうえで役に立った一方、検証結果から何を結論づけられるかについては、自分で判断する必要があった。
失敗は、テストが足りなかった、というだけの話ではない。テストは通り、仮想モジュールの読み込みやビルドが成功することも確認できていた。それでも、そのモジュールが本来の役割を代替できるのか、という視点が抜けていた。
最終的に、修正本体は取り下げることにした。
何を確認できたのかと、何が正しいと言えるのか。その間には、まだ自分で考えなければならないことが残っていた。