検証主張の完全性
エージェントが「テストが通りました」「カバレッジ87%です」「このコードはもう使っていないので削除しても大丈夫です」と言うとき、その言葉をどう信じればよいのでしょうか? 検証主張の完全性 (Verification-Claim Integrity) は、まさにこの点を扱います。観測されていない成功を主張せず、検証されていない欠陥を主張しないルールです。
エージェントは「完了しました」と言うことに学習的にバイアスされています。ユーザーが聞きたいことなど何でも、結果を肯定的に要約して報告する方向に訓練されたグラディエントがあります。このバイアスをシステムが補正しないと「通った」という言葉が信じられなくなります。
より危険な方向があります。エージェントが「このSPECはクローズ処理が漏れている」「このパッケージはカバレッジが低い」「この機能はまだ使われているので削除すべきではない」と主張するとき、その主張が事実でない可能性があります。テキストパターンだけを見て欠陥を推論したり、参照が存在するという理由だけで生きている機能と判断すると、存在しない問題を修正したり、すでに削除されたコードを残そうとして無駄が生じます。
注意証拠の欠如は成功の証拠でも、失敗の証拠でもありません。 検査を実行しなかったことだけで「通った」「失敗した」と言うことはできません。どちらも観測されていない主張です。
核心のルールは1行です。
エージェントは直接検証していない完了、欠陥、負債、ドリフト、または推奨の前提を主張してはならない。
このルールは両方向に縛られます。
- 成功方向 — 「テストが通った」「カバレッジ87%である」「リントがクリアである」という主張は、実際にコマンドを実行してその出力を観察したときにのみ成立します。実行していないコマンド、スキップしたステップは空欄であって、合格ではありません。
- 欠陥方向 — 「このSPECはクローズ負債である」「このパッケージはカバレッジが低い」「このコードはドリフトである」という主張も、ドメインの専用ツールで検証したときにのみ成立します。フロントマatterテキストやgrep結果だけで欠陥を推論すると、観測されていない欠陥主張になります。
欠陥方向の方が危険です。誤った「削除せよ」という主張は次のビルドやテストで直ちに反論されますが、誤った「そのままにせよ」という主張は死んだコードを残したまま何の信号も出さないからです。
ルールは1つの表面にのみ縛られません。観測されていない主張が染み込む可能性のある4箇所すべてを縛ります。
| 表面 | 縛る対象 | 例 |
|---|---|---|
| オーケストレータ自己報告 | 完了報告と検証マトリックスのすべてのPASS行 | 「すべての検証が通過しました」バナーの各行 |
| エージェント完了報告 | エージェントの自己検証マトリックス(テスト・ビルド・カバレッジ・リント) | 「テストPASS、カバレッジ87%」報告 |
| 欠陥・負債・ドリフト主張 | 欠陥や技術負債が「存在する」というすべての主張 | 「SPEC Xはクローズ負債である」「パッケージ Yはカバレッジが低い」 |
| 推奨の前提主張 | 「維持せよ/削除せよ」推奨の理由となる前提 | 「この機能はまだ生きている」「他の消費者が依存している」 |
4番目の表面は、推奨の理由を検証しなければならないというルールです。「削除すべきではない」と推奨するには、その機能のプロデューサーがまだ存在するか、消費者がまだ到達可能かを直接確認しなければなりません。到達可能性は正当化ではありません。 参照が存在するということは、参照が生きている証拠ではありません。
このルールを実際に強制する運用メカニズムが5段落報告形式です。エージェントが完了や検証を報告するときに5段落に分けて書くと、観察したものと観察していないものを分けることになり、観察していない部分が空欄として明示されます。
何を断言するかを1行で書きます。検証マトリックスの1行、または散文報告の1文が1つの主張単位です。
実際に実行したコマンドとその出力をそのまま書きます。要約ではありません。主張が「テストが通った」なら、この段落にはgo test ./...コマンドとそのコマンドが出力したブロックがそのまま入ります。「すべてのテストが通った」という要約は証拠ではありません。出力そのものが荷重を負うアーティファクトです。
この主張をどの基準に対して測定したかを明示します。今回の実行で、このツリーに対して直接実行したコマンドと観察した出力です。別のSPEC、別のパッケージ、別の時点で記憶していた数値を借りてくるべきではありません。「カバレッジ87%」なら、このツリーでgo test -cover ./internal/<pkg>/...を実行してcoverage: 87.0% of statementsを観測したという意味です。
明示的に検証していないものを列挙します。この段落が形式全体の核心です。観測されていない主張が空欄で通過するのを防ぎます。未検証段落が空なら「検証していないものはない」という強い主張であり、それ自体が真でなければなりません。確信が得られないときは空欄のままにせず、名前を書いてください。
観測された証拠の後でも残る不確実性です。未検証(観察していないもの)とは異なります。残余リスクは観測したにもかかわらずまだ間違っている可能性があるものです。不安定なテスト、環境依存の動作、後回しにした受容基準、検証時点と使用時点の間の窓などがここに該当します。
あるステータス報告書がstatus: implementedでera:フィールドがないSPEC 29個を数え、フロントマatterテキストだけを見て「この29個はV3R6クローズが漏れているSPECである」と推論した後、一括クローズを提案しました。
これは観測されていない欠陥主張でした。報告者はドメインの専用ツールを実行していませんでした。最終的にmoai spec audit --jsonを実行してみると、29個すべてが既存の特例(grandfather)era(V3R2-R4 28個 + V2.x 1個)と分類されました。era_final: true、保護対象、V3R6 3フェーズクローズ対象ではありませんでした。カタログ全体のMUST-FIXドリフトは0でした。推論された「クローズ負債」は存在せず、一括クローズが進んでいたら保護されている29個を理由なく触れるところでした。
情報教訓: 欠陥主張はドメインツールが確認するまで仮説に過ぎません。era:フィールドがなくimplementedであるテキストパターンは2つの解釈(祖父レガシー vs 現代クローズ負債)の両方と両立します。ツールだけが分岐できます。ドメインツールが存在するとき(moai spec audit、go test -cover、golangci-lint)、テキストだけで欠陥を主張してはなりません。
ユーザーが特定のディレクトリを削除するよう指示しました。オーケストレータはアーティファクトを削除しながら1項目だけ残しました。削除すると「すべての分散ユーザーから生きている機能を取り上げる」という前提でした。別のリタイアSPECを推奨しました。
その前提は一度も検証されませんでした。オーケストレータは当該スキャンが到達可能であることとSPECがまだstatus: implementedと読まれることだけを確認し、両方をその機能が生きている証拠として扱いました。両方ともそうではありません。プロデューサーを直接列挙してみると、すでにすべて消えていました。コマンドも、ワークフローも、エージェントも、CLIも、スキャフォールドも、4ロケイルのドキュメントページもありませんでした。すでに完了したリタイアSPECがその機能を分散ユーザー全員から永続的に削除し、後続するクリーンアップコミットが残った孤児を一掃していました。スキャンは2度の整理をただ耐えたに過ぎません。
情報教訓: 到達可能性は正当化ではなく、SPECがまだstatus: implementedと読まれるからといってその機能が生きている証拠でもありません。後続するSPECがリタイアさせた可能性があります。ユーザーの指示に反する維持推奨を出すには、維持しようとしているもののプロデューサーを列挙し、完了したリタイアSPECがあるかを確認しなければなりません。前提を検証していない異議の申し立ては、観測されていない主張です。
このルールは、エージェントの報告を読むとき「根拠は何か?」を尋ねる習慣の体系的表現です。MoAI-ADKはエージェントが「通った」で終わるのではなく、5段落に分けて報告することを強制し、ドメインツールで直接検証した結果のみを証拠として認めます。その結果:
- 完了報告を信頼できます — 「テスト合格」は実際のコマンドと出力を意味します。
- 偽の欠陥でコードを触ることが減ります — 欠陥主張はツール確認を経ています。
- 死んだコードが生き返るのを防ぎます — 維持推奨はプロデューサーの存在を確認しなければなりません。
TRUST 5品質の「追跡可能 (Trackable)」原則がここで現実になります。すべての主張が観測された証拠に帰属されるとき、報告は初めて監査可能になります。
- TRUST 5品質 — 5つの品質原則、追跡可能原則の上位フレームワーク
- SPECベース開発 — 受容基準を証拠で判定する3フェーズライフサイクル
- ハーネスエンジニアリング — エージェント環境を設計するパラダイム