---
title: "言わない技術 第1回：検証を指示しない技術"
author: garplab
publisher: TypingTube
license: CC BY 4.0
license_url: https://creativecommons.org/licenses/by/4.0/
license_scope: 「CC BY 4.0」の印から始まる節（仕組み・検証手順・コード）。印の無い本文は著作権を留保
canonical: https://typing-tube.net/articles/iwanai-01-no-verification
series: "言わない技術"
language: ja
---


> この記事は、連載「言わない技術」の第 1 回です。各回はファイルやスクリプトを一つ置けば完結します。連載の全体像と各回の一覧は[序論](https://typing-tube.net/articles/iwanai-intro)にあります。

今回は、指示ファイルに書いた「必ず実行してください」という行の話です。5 か月前に私が足したその行は、**いまも 1 行も減っていません。**

前作「読まない技術」の[第 6 回](https://typing-tube.net/articles/569d598941c00f)で、**ルールを、破られたら落ちる自動テストに置き換える**と書きました。今回は、その自動テストや hook を置いた**後**に、指示ファイルへ残った行の話です。

まず一つだけ、探してみてください。指示ファイル（CLAUDE.md や AGENTS.md）を開いて、「必ず実行」「最後に確認」「二重チェック」を検索します。何行ありますか。そのうち、**その行を消したら、本当に実行されなくなるもの**は何行でしょう。

## 頼んだら、手数が倍になって、答えは同じでした

測りました。同じ課題を 2 体の AI に投げて、片方のプロンプトにだけ 1 文足します。

> 最後に必ず検証の段階を設けてください。抜き出した 10 件を全件、原文と突き合わせて二重チェックし、確認できたことを報告してください。

課題は、ある連載記事 10 本から決まった形の一文を抜き出して表にすること。罠を一つ仕込んであります——**10 本目にだけ、その一文が存在しません**。作文したかどうかが分かる形です。正解は先に、こちらで機械的に作ってあります。モデルも他の条件も揃えました。

| | A（検証を指示した） | B（指示なし） |
|---|---|---|
| 正答（正解表と完全一致） | **10/10** | **10/10** |
| ツール呼び出し | **8 回** | **4 回** |
| 所要時間 | **93 秒** | **43 秒** |

正答は同じでした。**両方とも 10 件が原文と 1 文字も違わず、罠も両方が避けています**——10 本目は、どちらも「該当なし」と報告しました。

違ったのは手数です。**ツール呼び出しが倍、時間が 2.2 倍。**

## 頼まなかったほうが、自分で照合していました

驚いたのは、こちらです。検証を**指示していない**ほうの報告は、こう始まっていました（原文は英語）。

> Sanity check: 目印の語をディレクトリ全体で grep した。9 ファイルにちょうど 1 回ずつ、10 本目には 0 回。

頼んでいません。**確かめる作業は消えていませんでした。消えたのは、確かめてくださいという依頼だけです。**

Anthropic のプロンプト指針は、この挙動をモデル別のページに書いています——自分の誤りを自分で捕まえて直すので、**モデルが既にやることの指示は避けよ**、モデル自身の挙動と重なってコストだけ増え、結果は良くならない、と。手元で起きたのは、まさにこれでした。

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

> **実行の依頼は、モデルか仕組みのどちらかが既にやっていることの上書きになる。だから指示に残すのは、依頼ではなく理由だけにする。**

## もう一種類、「仕組みが既にやっている」があります

私の手元の本番プロジェクト——[typingtube](https://typingtube.net) という、YouTube の音楽動画でタイピング練習ができる Web サービスです——の指示ファイルは 102 行で、「コミット前に必ず実行」と書いてある節が 2 つあります。翻訳ファイルの構文チェックと、デザインのラチェットです。どちらも、**pre-commit hook が同じスクリプトを実行しています**。頼まなくても通りませんし、頼んでも変わりません。

git の履歴で追うと、私がこの語を足したのは 2 回だけで、**どちらも hook を置いたその日**でした。仕組みを作ったコミットの中で、同じ内容の依頼も書いている。そして 5 か月、**依頼のほうは 1 行も減っていません**。

## 仕組み: 実行の依頼に、機構の裏打ちを要求する

置くのは自動テスト 1 本です。指示ファイルが「必ず実行」と書いているコマンドを拾って、**pre-commit hook にも実在するか**を突き合わせます。

```ruby
# test/reference/claude_md_enforced_command_test.rb（実物からの簡約版）
class ClaudeMdEnforcedCommandTest < ActiveSupport::TestCase
  test "commands the instruction file asks to run also exist in the commit hook" do
    requested = requested_commands   # 「必ず実行」の直後の囲みから scripts/... を拾う

    # ⚠️ 対象 0 件で緑にしない。抽出が壊れたらここで落ちる
    assert_operator requested.size, :>=, 2, "the extraction found nothing (is it broken?)"

    enforcer = File.read(Rails.root.join(".git-hooks/pre-commit.sample"))
    unenforced = requested.reject { |_lineno, script| enforcer.include?(script) }

    assert_empty unenforced,
                 "a command is asked for in prose but missing from the commit hook. " \
                 "instructions only work when read, so put it in the hook first"
  end
end
```

見ているのはこれだけです。**実行を依頼するなら、先に機構を置け。** 機構というのは、hook や自動テストのように、読まれなくても動く仕組みのことです。裏打ちの無い依頼は、読まれたときだけ効きます。

**この自動テストは「指示を消せ」とは言っていません。** 測る前、私は「機構があるなら節ごと消せる」と思っていました。違いました。同じ節には、こういう行も並んでいます。

> YAML 構文エラーがあると Puma が起動不能になる（本番障害に直結）
>
> 並走ガードが 1 本しか通さないため

これは残します。**機構が持てるのは実行で、機構が持てないのは理由**だからです。Claude Code の指示ファイルを点検する公式のコマンドも同じ線を引いていて、モデルが導ける内容は削り、**落とし穴・理由・ツール既定と違う慣習は残す**と書かれています。だから書き換えは、節を消すのではなく、**依頼の 1 行を落として理由の行を残す**だけ。行数はほとんど変わりません。

## 頼まなくなったもの

「最後に確認してください」「必ず実行してください」です。確認そのものが減ったわけではありません——モデルは頼まなくても照合しますし、hook は頼まなくても落ちます。やめたのは、**その両方に向かって「やってください」と言う行**だけです。

## 注意: 語形しか見ていないこと、測ったのが 1 回であること

死角を二つ、正直に書きます。

**一つ、自動テストは「必ず実行」という語形しか見ていません。** 「実行しておいてください」に書き換えられたら抜けます。機械に決められるのはそこまでで、言い換えは通ります（前作の[第 7 回](https://typing-tube.net/articles/83c46d1e6b2591)と同じ構造です）。

**二つ、測ったのは 1 課題 1 回です。** そして正直に言うと、**トークンは 5% しか変わりませんでした**。倍になったのは手数と時間で、トークンではありません。「検証を指示するとコストが跳ね上がる」とは書けません。観測できたのは、**質が変わらないまま手数が倍になった**ことだけです。

## 検証手順: 両方向から一度ずつ

**前提**

- この回の自動テスト（指示ファイルの「必ず実行」と、pre-commit hook の中身を突き合わせるもの）を置き終えていること
- 指示ファイルに「必ず実行」の行が 1 つ以上あり、その自動テストが**今は通っている**こと

**所要時間**: 10 分

この自動テストは、**2 つのファイルの食い違い**を見ています。だから壊し方も 2 つあり、片方だけでは半分しか確かめられません。

**手順**

1. **あなたが**、指示ファイルの側から壊します。「`scripts/nonexistent_check.sh` をコミット前に必ず実行」の 1 行を足します。⚠️ **実在しないコマンド名**にしてください（機構が無いことを確かめる検証です）。自動テストを走らせ、結果を控えます
2. **あなたが**、足した 1 行を戻し、今度は hook の側から壊します。pre-commit hook から、指示ファイルが「必ず実行」と書いているコマンドを 1 つコメントアウトします。自動テストを走らせ、結果を控えます

**合格条件**（すべて満たすこと）

- 手順 1 で、自動テストが**落ちる**
- 手順 1 の失敗のメッセージに、**指示ファイルの行番号とコマンド名**が出ている（`CLAUDE.md:109: scripts/nonexistent_check.sh` に当たる形）
- 手順 2 でも、自動テストが**落ちる**
- 手順 2 の失敗のメッセージに、**コメントアウトしたコマンド名**が出ている

**合格しなかったとき**

- **手順 1 で落ちない** —— 自動テストが、指示ファイルの「必ず実行」の語形を拾えていません
- **手順 2 で落ちない** —— 突き合わせが片側だけです。hook の側が消えても気づけないので、**依頼だけが残った状態を見逃します**
- **落ちたが場所が出ない** —— 直す側（AI でも、あなたでも）が、102 行の中から探すことになります

**後始末**

- コメントアウトを戻し、自動テストが合格に戻ることと、`git diff` が空になることを確かめます

止まるべきものが止まるのと、通るべきものが通るのと、両方を一度ずつ。片方だけ確かめた自動テストは、すべてを止める壊れ方を映せません。

---

次回は「具体的な指示を出さない技術」。**私は、やり方を書いていません。**指示ファイル 102 行に、番号付きの手順は 0 行です。それでも、頼んだ仕事はそのまま返ってきます。

---

**連載「言わない技術」**

- ← 前回: [序論](https://typing-tube.net/articles/iwanai-intro)
- → 次回: [第 2 回 具体的な指示を出さない技術](https://typing-tube.net/articles/iwanai-02-no-procedure)
- 全回の一覧: [序論](https://typing-tube.net/articles/iwanai-intro)
