64 回で書いた名前を、もう一度並べる。名前どおりだった所、ずれていた所、書くために測り直して見つかった穴
Lining up the names from 64 posts again: where they fit, where they drifted, and the holes found by re-measuring to write
D32-4-T64-building-with-ai-summary・技術・日本語入力でプレイする仕組み
返事を一文も生成しない推理アドベンチャーを、二つの開発 AI と一緒に作ってきました。
その作り方のほとんどには、もう名前がありました。最終回は、その名前をもう一度並べ、名前どおりだった所とずれていた所を書きます。
連載で書いてきた約束を、最初に繰り返しておきます。
入力された日本語を、書き下ろした証言のどれに当てるかを決めるだけで、遊んでいる間に文章は作りません。
同じ問いには同じ答えが返り、ネットにつながなくても動きます。
生成 AI を使うのは、作る側の工程(台詞の候補・言い換え・作品データの穴埋め・コード)だけで、採るのは検査に通ったものだけです(T58)。
この回の位置と、前後の回#
区切り: T58〜T64 作り方と周辺(7 回のうち 7 回目)
先に読むとよい回: T01(全体の構造と、使っている技術と言語)・T02(名前のある技術の一覧)
次に読む回: T01(全体の構造と、使っている技術と言語)
この連載の決まり#
各回は、同じ順に書いてきました。
名前(正式名・略称・日本語の呼び名・初出)。
その技術の一般的な解説。
うちの実装。
名前どおりでない所。
弱点と、採らなかった案。
決まりの元は、規約の原則 7 です。
「名前のある方法・失敗はその名前で呼ぶ。新しい罠を踏んだら、対処を考える前に名前を調べる」。
この原則ができたのは、2026-08-17 です。
自分たちの方式について「例が無い」と 2 か所書き、検索したら 2 つとも既にありました。
同じ日に、踏んだ罠 5 件を調べ直すと、5 件とも名前のある失敗でした。
名前があるものを自分の言い方で呼び続けると、外の知見が引けず、人に説明できず、既にある対処を作り直すことになります。
探し方にも、決まりが一つ足されています(翌 08-18)。
1 回の検索で出なかったことを「名前が無い」と書かない。
分野(検索・テスト・統計・ビルド)を変えて 2〜3 回引く。
「検査の記録が被検査物の中にあって、記録すると測定が古くなる」は、最初「名前が見つからない」として登録されました。
角度を分けて引き直すと、ビルドの側で over-invalidation、テストの側で Fragile Test が出ました(T55)。
区切りごとのふりかえり#
T02 と同じ 7 つの区切りで並べます。
T01・T02 全体と一覧。
C++20 のヘッダだけの核を、UE・CLI・Linux のサーバが写さずにコンパイルする作り(T01)と、名前の一覧(T02)。
T03〜T24 日本語入力を解いて返すまで。
文字の正規化、文字 n-gram と tf–idf、文の埋め込み(multilingual-e5-small)、SentencePiece の Unigram、ONNX Runtime、二つの点の混ぜ方、RRF、固有名詞の辞書、時間表現、文の分割、否定、指示語、意図の分類、答えない判断(reject option)、会話の修復、返事の選択、段と旗、主張、出所つきの手帳、図の漏れ、決定論、セーブの指紋。
この区切りは、名前より狭い所がいちばん多い区切りでした。
名前の多くは自然言語処理の研究の名前で、うちはそれを、作者が書いた規則と辞書の範囲で使っています。
T25〜T29 画面と入力。
IME、音声入力、ヘッダだけの核、JSON で書く画面、二つの描画器の照合。
IME と音声入力は、名前どおりでした。どちらも OS とエンジンの口を、本物の入力欄ごと借りているだけです。
T30〜T33 配る仕組み。
状態を持たないサーバ、token bucket、HTTP の条件つき要求と範囲要求、rsync。
token bucket と rsync は名前どおりで、HTTP は RFC 9110 から外れている所を、測って 4 つ見つけました(T32)。
T34〜T49 確かめ方。
lint、clearpath、reach、!expect、golden、metamorphic testing、mutation testing、判定の 4 値、holdout、写し込みの検出、差分テスト、手の台帳、検査の目録、証拠の台帳、AI 初見プレイ、AI に採点させる距離。
この区切りは、名前の対照表の判定が、書いていて動いた所が多い区切りでした(次の節)。
T50〜T57 失敗の名前。
Goodhart 則、surrogation、古い焼き物、陳腐化したテスト、Guru Checks Output、Fragile Test、gold plating、single source of truth。
失敗は、ほとんどが名前どおりに起きていました。
T58〜T63 作り方と周辺。
generate-and-test、spec-driven development、sketch-based synthesis、減色とディザ、音声合成、git worktree。
どれも作る側の工程で、遊んでいる間には動きません。
名前どおりだった所#
名前どおり、と書けた所を挙げます。
- tf–idf と cosine similarity(T04)。tf × idf、L2 正規化、内積
- multilingual-e5-small の "query: " の接頭辞と mean pooling(T05)
- Unigram の分割の Viterbi(T06)
- RRF の実装そのもの(T09)。k=60・順位の逆数の和。負けたのは、使い方の方でした
- IME と Windows の音声入力(T25・T26)
- header-only library(T27)
- token bucket(T31)と rsync の差分転送(T33)
- explicit-state model checking の探索の部分(T36)
- inline assertion(T37)
- Goodhart 則と test-set contamination(T50)、surrogation(T51)、stale artifact による見逃し(T52)、obsolete test(T53)、over-invalidation(T55)
- text-to-speech(T62)と git worktree(T63)
失敗の名前が名前どおりに起きた、というのは、うれしい話ではありません。
けれど、名前どおりに起きた失敗には、名前どおりの対処があります。
古い焼き物には「成果物の新しさを検査に入れる」、Goodhart 則には「評価の文が辞書に写っていないかを見る(L18)」、obsolete test には「期待を仕様と同じ場所に置く」。
どれも自分で考えた対処ではなく、名前を引いて出てきた対処です。
名前とずれていた所#
ずれは、三つの形に分かれました。
一つ目、名前より狭い、限定した規則。
時間表現は TimeML の DATE と TIME の、月・日・時・分だけ(T11)。
文の分割は、記号で切るだけで構文を見ない(T12)。
否定は、掛かり先の区間を求めず「否定があれば確定させない」だけ(T13)。
指示語は、候補を探さず、作者が書いた行き先へ回すだけ(T14)。
段と旗は、information state のうち旗の集合だけ(T19)。
手帳の来歴は、PROV のモデルを使わず、行ごとの欄だけ(T21)。
どれも「近い名前はあるが、どれでもない。限定した表層規則として読んでください」と書いた回です。
名前を借りたのは、外の知見を引くためで、同じものを作ったと言うためではありません。
二つ目、名前の対照表の判定が、ソースを読み直して変わったもの。
連載を書くために、各回の担当がソースを読み、ツールを今日の版で流しました。
そこで、対照表(named-methods-audit)や T02 の印と違う結論になった所があります。
- reach(T36)。対照表は「--max-steps で切っているので、正確には bounded model checking」と書いていました。ソースを読むと、手数の上限は探索の深さではなく、性質の中の「n 手以内」にだけ効きます。到達状態は全部歩いています
- golden(T38)。golden master と呼んでいますが、期待は出力の写しではなく、照合器より前の commit で人が書いた正解の意図の id でした。だから、進行に要る入力の組(probe-critical)で今日落ちている 27 問が、落ちたまま見えています
- 判定の 4 値(T41)。混同行列と言い直せるのは正解のある golden の側だけで、4 値は「話題の語があるか」で近似した判定でした
- 手の台帳(T45)。対照表は「要求 ↔ 実装 ↔ 検査」と書いていましたが、検査の列はありません
- AI 初見プレイの採点(T49)。対照表は「playtesting+LLM-as-a-judge」と呼んでいましたが、採点のスクリプトは LLM を使わない算術でした
- 二つの描画器の照合(T29)。conformance testing と呼んでいましたが、半分は参照実装(UE)との differential testing でした
- Guru Checks Output(T54)。対照表は踏んだことのように書いていますが、書いてみると、踏んでいません。踏みかけて、作業の中で不要と分かった、でした
- saturation effect(T56)。対照表は名前どおりとしていますが、うちは飽和を測っていません。止めているのは、未達の連続回数という素朴な線です
- 背景の網(T61)。制作の手引きは「自動ディザと、手で置く 2 色の網掛けを分けて使う」と書いていますが、第一章の 6 枚は、自動ディザ 0・手の網掛け 0 で、網は全部スクリプトの 2×2 の Bayer の閾値で置いていました
T02 の本文は直していません。
直す代わりに、各回の「名前どおりでない所」に、測った版で何が違ったかを書きました。
三つ目、名前を分けた所と、造語。
「変異テスト」という同じ日本語が、言い方だけを変える検査と、データを壊す検査の両方を指していました。
前者は metamorphic testing(T39)、後者は mutation testing(T40)です。いまは分けて呼んでいます。
RRF は、実装して同じ評価で測り、負けたので消しました(T09)。名前のある方法を採らなかった、という記録です。
推理の「主張」は造語で、近い名前の recognizing textual entailment とは違うことを、違う所を並べて書きました(T20)。
書くために測って、見つかった穴#
連載の各回は、書く日に、書く版で数字を測り直しました。
その途中で見つかった欠陥を、一つの記録にまとめてあります(2026-10-29)。
検査の側 16 件、ゲームの挙動 13 件、ブラウザ版のサーバ 3 件、道具と文書のずれ 13 件(うち 1 件は同じ日に解決)。
第一章の体験版とブラウザ版を止めるものは、ありませんでした。
どれも、テスト計画の欠陥の管理でブロッカーに当たらず、直さずに記録に残しています(規約の原則 2)。
代表的なものを挙げます。
- 合格ラインの無い台本では、!expect が外れても全体が合格に見えます。今日、第二章以降の台本 4 本で 6 件の失敗が隠れていました(T37)。製品版の前に、いちばん先に見直す所です
- 作品データを 12 か所わざと壊したら、2 か所が生き残りました。1 つは、女将の台詞の「8時前」を「9時前」に変えた変異です。第一章の食い違いの要の時刻を壊しても、どの検査も落ちません(T40)
- クリアの手数を、逆算の道具は 60、順路の表示は 61 と数えます(T35)
- セーブの指紋の FNV-1a は、初期値の末尾の 1 桁が標準と違います。式は名前どおりでも、標準のライブラリと値が合いません(T24)
- ブラウザ版のサーバは、If-None-Match を文字列の完全一致で見て、HEAD に 405 を返します(T32)
- 半角カナで入力すると通じません(T03・T06)
- 問い 2 つを読点でつなぐと、2 つ目が何も言われずに消えます(T12)
- 作品データの骨を起こす道具が、いまある企画の形式からは骨を起こせませんでした(T60)
うまくいっていた方の発見もあります。
Windows と Linux で焼いた埋め込みのベクトルが、バイトまで一致しました(T07)。
同じ入力の列を流すと、出力は毎回同じでした(T23)。
背景の 16 色は、今日同じ手順で作り直すと、6 枚とも完成の画像と一致しました(T61)。
測り直す前の文書には、古い数字が多く残っていました。
規模の数字が 8 月のまま、lint の表が規則の途中まで、核のヘッダの行数が半分、など。
原稿は全部、ソースと今日の実行結果の側に合わせて書いています(規約の原則 3)。
二つの開発 AI と、人#
作っているのは、作者 1 人と、二つの開発 AI です。
Anthropic の Claude Code と、OpenAI の Codex。
どちらもコードと文書を書きます。
記録の置き場は分けていて、Claude の記録は Docs/Reports/(今日 580 本)、Codex の記録は Docs/CodexReports/(285 本)です。
同じ対象を、二つが同時に編集しない、という決まりがあります。
役の分け方で、効いたと思うものが三つあります。
一つ目、作った本人に判定させない。
AI 初見プレイのプレイヤー役は、作品を知らない別の AI です(T48)。
通読の読み手も、声つき動画の画面と声の判定役も、作っていない別のエージェントに、何を直したかを渡さずに見せます(T49・T62)。
片方の AI が書いたものを、もう片方の AI が監査する、という使い方もしています(T56 で引いた 09-22 の監査など)。
ただし、判定役のモデルの系統を作り手と変える、までは決めていません(T49 の弱点)。
二つ目、合否を感想で上書きしない。
合否はスクリプトの測定で決め、判定の道具に不具合があれば、根拠を示して直してから測り直します。
出力に合わせて、ゲームや合格の条件を変えません。
条件を変えるのは、作者の方針に基づくときだけで、実測と理由を設定に残します(原則 4)。
これは、AI 初見プレイを 21 回まわしても終わらなかった 2 週間から来た決まりです(T56)。
三つ目、取り返しのつかないものだけ、先に人に聞く。
範囲の中で git で戻せる判断は、AI が自分で決めて進み、何を選んだかと戻し方を 1 行で書きます。
先に確かめるのは、削除・push・外への公開・起動中のゲームの停止・worktree の追加と削除だけです(原則 1)。
人の仕事は、決めることと、読むことです。
作者は、作品のファイルを自分では編集しません。
指示を書き、AI に書かせ、出てきたものを読んで採るか戻すかを決めます。
ネタバレの線を第一章までと決めたのも、プレイ動画を縦に切らず横長のまま作ると決めたのも、合格の基準を読了に絞ると決めたのも、作者です。
AI が決めないことの一覧が、規約の「守るもの」と、テスト計画の改定の手続きです。
開発の AI の失敗も、この連載では仕組みの穴として書いてきました。
手順書に自分で足した「10 項目」を完成と読んだ(T51)。
古い焼き物の上の緑を信じた(T52)。
緑の判定を感想で赤に戻し続けた(T56)。
どれも、誰かが不注意だったという話ではなく、正の文書が一か所に無い・成果物の新しさを検査に入れていない・終了基準を読む手順が無い、という穴でした。
穴を名前で引き、名前どおりの対処を入れる、を繰り返してきました。
地図(T01〜T63)#
本文の中で「T06」と指せるように、番号と題を並べます。
T01 全体の構造と、使っている技術と言語
T02 名前のある技術の一覧
T03 文字の正規化(NFKC を使わない norm/1)
T04 文字 n-gram と tf–idf
T05 文の埋め込み
T06 トークナイザ(SentencePiece の Unigram を C++ で)
T07 1 ビットも違わない埋め込み(ONNX Runtime)
T08 二つの点を混ぜる
T09 RRF を実装して測り、負けた
T10 固有名詞の辞書
T11 日付・時刻・時間帯
T12 複文を割る
T13 否定の掛かり先
T14 「前者で」は画面から探す
T15 意図の分類
T16 答えない判断(reject option)
T17 通じなかった会話を戻す
T18 返事は選ぶだけ
T19 段と旗
T20 推理の主張(造語)
T21 手帳は出所つき
T22 図から答えが漏れる
T23 同じ入力に同じ出力
T24 セーブとデータの指紋
T25 入力欄の中の IME
T26 音声入力でそのまま遊べる
T27 C++ の核を三つの外側で共有する
T28 画面は JSON で書く
T29 二つの描画器を同じに保つ
T30 状態を持たないゲームサーバ
T31 1 秒 2 手のレート制限(token bucket)
T32 静的ファイルの出し方(条件つき要求・範囲要求)
T33 更新は 1 コマンド(rsync・最小権限)
T34 台本を実行せずに検査する(lint)
T35 解ける道を逆算する(clearpath)
T36 全部の状態を探す(reach)
T37 台本の中に期待を書く(!expect)
T38 凍結した問い(golden)
T39 言い換えても着地するか(metamorphic testing)
T40 データを壊したら赤くなるか(mutation testing)
T41 判定の 4 値
T42 holdout を見た回数で数える
T43 答えの写し込みを見つける(w-shingling と Jaccard)
T44 二つの作品と二つの実装を突き合わせる(differential testing)
T45 手の台帳
T46 検査の目録を作品に置く
T47 合格の証拠を測った版に縛る
T48 AI に初見で遊ばせる
T49 AI に採点させる距離
T50 通じ率 23% が 100% になった日(Goodhart 則)
T51 代わりの指標を目的と取り違える(surrogation)
T52 古い焼き物が回帰を隠す
T53 変更に追いつかない検査(obsolete test)
T54 今の値に書き換える誘惑(Guru Checks Output)
T55 無関係な変更で落ちる検査(Fragile Test・over-invalidation)
T56 作り込みすぎと終わりの基準(gold plating・exit criteria)
T57 一つの契約は一か所で(single source of truth)
T58 通った台詞だけを採る(generate-and-test)
T59 企画が正(spec-driven development)
T60 骨を先に機械で起こす(sketch-based synthesis)
T61 背景を 16 色に落とす(color quantization・ordered dithering)
T62 声つきのプレイ動画を台本から作る(text-to-speech)
T63 並列のレーン(git worktree)
最後に — 64 回分の名前が付いている場所#
64 回分の名前は、どれも、入力された日本語 1 つを受け取ってから返事を 1 つ返すまでと、それが壊れていないことを確かめるまでの、どこかに付いています。
名前の多くは、ここで使っている範囲より広い意味を持っています。
うちが使っているのは、その狭い一部で、その一部がどこかを書くのが、この連載の仕事でした。
読んだ技術が本当にそう動くかは、第一章で確かめられます。
同じ問いを言い方を変えて入力する、問いを二つつなげる、わざと半角カナで入力する。
返事が変わるか、変わらないかを見てください。
『霧走町 流氷に眠る』の第一章はブラウザで無料で、入力して試せます。全三章の製品版は 2027年 発売予定です。どちらもプロフィールのリンクから。