長い基準文書をAIレビューに渡す——条と行の対応を出力に書かせる

基準文書が数百行になると、材料を貼る順を変えて試すことになる。基準と差分の順を入れ替えても、出力からは何も確かめられない。20条の基準文書と8ファイルの差分で条ごとの該当行を引くと、候補が差分の中にある条は16で、外にしか候補が無い条が4あった。この4条について出力が黙っていても、見落としと対象外の区別が付かない。落ちているのは材料の位置ではなく、条と行の対応付けを書かせていないことである。

この記事の提案を使うのは、判定基準の文書が長い(数百行以上)とき、または材料が複数のファイルにまたがるときである。

20条に対して該当行を引く

題材は TypeScript のモジュールで、差分は8ファイル、差分に入る変更後の行は76行である(スキーマで出力を固定する記事で定義したものと同じ)。リポジトリ全体は165行である。

判定基準を20条・573文字で書いた。条はこの題材の約束を細かく割ったもので、それぞれが行に当たる形にしてある。

判定基準の20条から4条を引く
 1. 金額は円の整数で持つ。小数で保持しない
 2. 金額の端数は切り捨てる。四捨五入と切り上げを使わない
 ...
 6. 在庫が足りないときは専用の例外を投げる
 ...
19. モジュール間の参照は相対パスで書く
20. 配列の畳み込みには初期値を渡す

条ごとに「該当行の候補を引く規則」を正規表現で先に決めて、リポジトリ全体に当てた。候補が差分の中にあるか外にあるかで分けて数えた(2026-10-12 に数えた。モデルは走らせていない。数えたのは入力の側、つまりどの条がどの行に当たりうるかである)。

条 差分の中 差分の外 対応の規則
1 8 9 :\s*number|unitPrice|amount
2 2 0 Math\.(floor|round|ceil)
3 7 0 rate
6 0 2 throw new|OutOfStock
12 1 0 !\s*;|\)!
13 0 2 extends Error|throw new
19 0 9 from "\.
20 0 1 reduce\(

20条のうち、候補が差分の中にある条は16だった。残る4条(6、13、19、20)は、候補がリポジトリの中にはあるが差分には1行も入っていない。

差分の外にしか候補行が無い4条
条6  在庫が足りないときは専用の例外を投げる    src/seats.ts:1, src/seats.ts:16
条13 例外は Error を継承した専用のクラスにする  src/seats.ts:1, src/seats.ts:16
条19 モジュール間の参照は相対パスで書く        src/checkout.ts:1〜4
条20 配列の畳み込みには初期値を渡す           src/money.ts:7

条6と条13が指す行は同じ src/seats.ts の1行目と16行目で、どちらも差分の文脈に入っていない。この差分は src/seats.ts に reserve を足しているので、ファイル自体は材料に入っている。それでも条6と条13が見る行は材料の外である。

この4条について出力が何も書かなければ、読んだ側には3つの可能性が残る。 条を見て該当が無いと判断したのか、条を読み落としたのか、該当行が渡されていないことに気付いて黙ったのかが区別できない。順序を入れ替えても、この区別は付かない。

消化表の大きさは条の数で決まる

基準文書を膨らませて、出力に要る行数が動くかを見た。条の説明を書き足して 573 文字を 2869 文字(5倍)、11479 文字(20倍)にしても、条の数は20のままなので消化表は20行である。入力の長さは条の書き方(説明の長さ、例の数)で変わるが、出力に要る行数は条の数だけで決まる。基準文書が長いことと、出力が長くなることは別の話である。

消化表を「条と該当行の対」まで細かくすると大きさが変わる。差分の中の候補行をすべて書かせると50行になった。条1が8行、条3が7行を持つためである。条ごとに1行へまとめる形なら20行で、該当行は代表の1つだけを書く。

成果物

対応付けを強制する1行

出力の末尾に、全条についての1行を書かせる。指摘の有無とは別に、条の数ぶんの行を必ず出させる。

レビュー指示に足す「条の消化」の節
## 条の消化

指摘を書いたあと、判定基準の全 <条の数> 条について、次の1行を条番号の順に書く。
指摘が出なかった条も飛ばさない。条の数と行の数を一致させる。

- 条<番号>: <判定> / <該当行>

<判定> は次の4語のいずれか1語に限る。
- 違反: 該当行が条に反している(指摘の通し番号を <該当行> の後ろに書く)
- 適合: 該当行があり、条に反していない
- 該当なし: 渡された材料の中に、この条が見る対象が無い
- 材料外: この条が見る対象は存在するが、渡された材料に含まれていない

<該当行> は `<ファイルのパス>:<行番号>` を1つだけ書く。
複数ある場合は最初の1つを書き、後ろに `ほか <残りの件数> 件` と足す。
「該当なし」のときは `—` と書く。
「材料外」のときは、その対象があると判断した理由を1行で足す。

この表の要は <該当行> である。判定の4語は、該当行が書けないときにその理由を分けるために置いてある。条を何ファイルに分けて持つか、受け取った表をどう点検するかは扱わない。扱うのは、条の番号と差分の行を対にして出させる1段だけである。

この消化表は出力全体に1つ置くもので、指摘1件あたりの欄ではない。指摘1件の欄を増やす提案とは別の枠なので、1件あたりの欄数の上限(6欄)を消費しない。条番号を指摘の側にも書かせたい場合は1件あたり1欄増えるので、そのときは消化表の <該当行> を落として判定だけにし、対応は指摘の側で持つ。

4語に限る理由は、「該当なし」と「材料外」を分けることである。この題材の4条(6、13、19、20)は、src/seats.ts や src/checkout.ts が材料に入っているのに、条が見る行だけが文脈の外にある。この2つを1語にまとめると、材料を足せば判定できる条が「該当なし」に埋もれる。

消化表から次の入力を決める

「材料外」が付いた条を集めて、2回目に足す材料を決める。この題材では4条が材料外になり、足すべきファイルは src/seats.ts の全文と src/checkout.ts の先頭部分と src/money.ts の全文である。差分の文脈を広げるのではなく、条が見る行を名指しで足す。

条の数が多くて消化表が読みにくい場合は、「違反」と「材料外」の行だけを先に出させて、「適合」と「該当なし」をその後ろへまとめる。並べ替えは判定の内容を変えないので、条番号の順を崩してよいかを指示文で決めておく。

条の数ぶん書かせると何を使うか

払うのは出力項目である。20条なら20行、1行あたり30文字前後なので約600文字が指摘の本体に足される。この題材の指摘8件を5欄で書くと約1800バイトなので、消化表は出力の3割ほどを占める。条を50条に増やせば50行になり、指摘の本体と同じ量になる。

人の確認時間も増える。20行を読んで、「材料外」と「該当なし」の区別が妥当かを見る。この題材では4条が材料外で、残り16条のうち該当なしになるものは0だった。見る量は条の数に比例するので、条が多い基準文書では消化表そのものを分けて渡す判断が出てくる。差分を切って複数回に分ける場合は、分割の単位を依存から決める記事の形で集合ごとに消化表を出させることになり、条の数×集合の数だけ行が増える。

この指示を落としていい条件は、条の数が差分のファイル数より少ないときである。 3条の基準で8ファイルの差分を見るなら、条が落ちたかどうかは指摘を読めば分かる。消化表が要るのは、条の数が人の記憶で追えない規模になったときに限る。目安として、条の数が10を超えたあたりから、出力に条番号が出ていない条を人が列挙できなくなる。

指示文の点検

長い基準文書を渡すときに確かめる項目
  • 全条について1行ずつ書かせているか(指摘が出なかった条も含めて)
  • 条の数と、出力の行の数が一致しているかを確かめたか
  • 判定の語を4つに限ったか
  • 「該当なし」と「材料外」を別の語にしたか
  • 「材料外」のときに、対象があると判断した理由を書かせているか
  • 該当行を ファイル:行 の形で1つ書かせているか
  • 該当行が複数ある条について、残りの件数を書かせているか
  • 「材料外」が付いた条から、2回目に足す材料を決める段取りがあるか
  • 消化表の行数(条の数)と、指摘の本体の長さを比べたか
  • 条の数が差分のファイル数より多いことを確かめたか

おわりに

20条の基準文書と8ファイルの差分で条ごとの該当行を引くと、候補が差分の中にある条は16で、差分の外にしか候補が無い条が4あった。この4条のうち2条は、ファイル自体は材料に入っているのに、条が見る行だけが文脈の外にある。

出力がその4条について黙っていると、該当が無いのか読み落としたのか材料が足りないのかを区別できない。基準文書を20倍に膨らませても消化表は20行のままなので、出力に要る量は入力の長さではなく条の数で決まる。

次に取る行動を1つ挙げる。手元の基準文書の条を1つ選び、その条が見る行がいま渡している差分に入っているかを確かめる。入っていなかったなら、その条は出力から消えている。消えた1条が、全条について1行を書かせる理由になる。