開発記録
AI が検証を誤ったら、結論を撤回して証拠を見直す
記事タイトルが出力されていないという誤判定を例に、正しい原稿を保ち、比較ルールの誤りを見つけ、修正後も不正な出力を拒否できることを確かめる手順を整理します。
- AI との協働
- 誤りの修正
- 検証
- HTML
検証で「記事のタイトルが存在しない」と報告されると、まず記事を直したくなります。ですが、タイトルがすでに HTML に正しく出力されていて、検証プログラムが比較する表現を間違えているだけなら、問題のない内容を変更してしまうことになります。
このサイトでも、2026 年 10 月にノートの出力を検証した際、同じ誤判定がありました。タイトルには <button> が含まれており、HTML にはエスケープされた文字列として出力されていました。それなのに、検証では元のタイトルをそのまま検索し、その文字列が見つからないことを、タイトルが出力されていないことと取り違えていました。
AI と一緒に作業するとき、私が重視するのは、すぐに「すみません、間違えました」と言えるかどうかではありません。誤った結論に沿って作業を進めるのをやめ、その時点の状態を保全し、原因を検証できる形で修正できるかどうかです。
証拠の範囲を超えた結論を、まず撤回する
「検証で見つからなかった」ことを「ページに出力されていない」と言い換える前に、比較方法が正しいかを確かめる必要があります。
このケースで、検証の失敗から最初に言えるのは、現在の検索ルールでは一致する文字列が見つからなかったということだけです。ページにタイトルがないと判断するには、実際の HTML を見て、検索対象、文字列の表現、ページの構造を確認する必要があります。
AI がすでに記事の欠落と判断していたなら、まずその結論を撤回するべきです。「記事に問題がある」という前提で修正を進め、最後に検証ルールの誤りを補足するだけではいけません。
撤回したからといって、すぐ別の推測に置き換えてよいわけではありません。たとえば、キャッシュやパッケージのバージョンが原因だと断定することです。より確かな進め方は、わかっている範囲までいったん判断を戻すことです。出力の検証は失敗したものの、原因は実際の出力と照らして確認する必要があるため、原稿はひとまず変更しません。
比較のずれを小さな例で確かめる
このケースは、ごく短いコードで再現できます。以下は既存テストの文言をそのまま使った例で、別の実在する記事のタイトルではありません。中国語の「使用」は「使う」という意味です:
const title = '使用 <button> & links'
const html = '<h3>使用 <button> & links</h3>'
html.includes(title) // false
読者に見えるタイトルには <button> や & を含められますが、この HTML 文字列では、それぞれ <button> と & で表されます。エスケープしていないタイトルをそのまま部分文字列として検索すると、結果が異なります。
その後、このサイトでは Astro の escapeHTML を使い、元のタイトルを出力と同じ表現に変換してから検索するようにしました。このノートを書いた時点で使われていたヘルパーで上の断片を再現すると、元の比較は false、エスケープ後の比較は true になります。これが示すのは、この入力の組み合わせで比較結果が変わることだけで、すべてのページが正しいということではありません。
この最小例から、修正の対象は、検証プログラムが期待する文字列の表現だとわかります。タイトルに含めてよい技術的な識別子を取り除くことではありません。リンクとボタンの使い分けは、HTML のセマンティクスに関する別の問題です。出力検証の誤判定で、その議論を中断させるべきではありません。
正しい例は通し、誤った例は引き続き拒否する
検証ルールを直すときに陥りやすいのは、今回のケースが通るまで条件を緩めてしまうことです。
たとえば、どこかに button があれば合格とすれば、エスケープによる違いは避けられるかもしれません。しかし、それではタイトル全体を照合するという要件が失われます。HTML の文字参照をすべてデコードしてから比較する方法も、<button> という文字列自体を表示したいケースと混同するおそれがあります。
既存の回帰テストでは、一つの合格例だけでなく、次のような区別も確かめています:
| 入力の状況 | 検証で保つべき区別 |
|---|---|
タイトルに <button> または & が含まれ、HTML では正しくエスケープされている |
文字列が存在すると認識する |
タイトル自体が <button> という文字列である |
<button> を表示するケースと混同しない |
| HTML に実際の button タグがある | それだけで、同じ文字がテキストとして存在すると判断しない |
| 別のタイトルが出力されている | 引き続き拒否する |
これらのケースは、元の要件を守るためにあります。修正が完了したとは、エラーメッセージが消えたということではありません。本来は失敗すべきでなかったケースを通しつつ、本当の誤りを拒否する力を残すことです。
このヘルパーの範囲にも限界があります。確認しているのは、シリアライズされた HTML に対応する部分文字列が含まれるかどうかであり、DOM パーサーやサニタイザーではありません。これだけで、文字列が正しい h1 にあること、ページの h1 が一つだけであること、HTML 全体が安全であることは証明できません。それらには、別途、構造と出力の検証が必要です。
テストを通すために、要件まで変えない
もしあのとき、記事タイトルから <button> を削除していたら、読者にとって意味のある識別子が失われる一方、検証プログラムの問題は残ったままでした。次の記事で & などのエスケープが必要な文字が現れれば、同じ誤判定が再発するかもしれません。
そこで、失敗したときは、まず問題を分けて考えます。プロダクトや内容が本当に間違っているのか、検証ルールが間違っているのか、それともそのときの環境では結果を根拠にできないのか、という切り分けです。これは必ず三つのうち一つを選ぶ手順ではなく、原因が重なることもあります。大切なのは、検証される内容に必ず問題があると決めつけないことです。
最小再現は問題を切り分けるためのものです。その後も、影響する検証を再実行し、実際の出力を読む必要があります。テストの期待値を変更しただけで、最初に問題があるとされたページを見直していなければ、その修正がユーザーの求める結果につながったかは、まだ確認できていません。
修正報告では、古い結論を置き換える
このケースの報告なら、次のように書けます。これは書き方の例であり、当時の会話を逐語的に引用したものではありません:
先の報告では、タイトルの検証に失敗したことを記事の欠落と判断しましたが、その結論は成り立ちません。実際の差異は、元の文字列と HTML でエスケープされた表現の違いでした。原稿はそのままにし、比較ルールを修正して、正しい文字列、文字参照そのものを表す文字列、誤ったタイトルを引き続き区別できることを確認しました。この修正によって、ページ全体の構造を検証する必要がなくなるわけではありません。
この説明なら、元の判断が撤回されたこと、本当の原因、そして修正によって何が証明されていないかが伝わります。まだすべての検証を再実行していないなら、その状態も伝えるべきです。先回りして「今はすべて正常です」と書いてはいけません。
事実・推論・不明な点では、結論をどう読むかを扱っています。このケースは、さらに一段さかのぼった話です。結論を生み出した検証そのものが間違っていたなら、正しい内容を検証に合わせるのではなく、検証を修正する必要があります。
一度の修正で、AI が今後もう間違えないと証明することもできません。残せるのは、再現可能な違い、要件を守る回帰テスト、そして古い判断をそのまま使わせないように更新された説明です。