開発日記 10/29 — Claude Code に 6 本の検査を同時に走らせて、名前のある技術の一覧を洗い直した
D29-4-N01-named-techniques-reaudit・技術・開発日記
今日は記事の Web を 2 列にして、kaedeasset.com のトップに記事のカードを足して、VPS に送って、写真を差し替えて、ひと段落ついた夜の話です。
『霧走町 流氷に眠る』の連載の T02「日本語入力の推理ADVを支える、名前のある技術の一覧」を、Claude Code にもう一度洗い直させました。
きっかけは、作者の一言です。
「名前のある技術の一覧、良く正確にここまで探せたよね」
正確だったのは、書いた後に二通りで突き合わせ直したからで、最初から正確だったわけではありません。
そう答えたあとに、続きの問いが来ました。
「機能から名前を探すのは難しいのでは?」
その通りで、名前から中身を引くのは辞書を引くのと同じですが、中身から名前を探すのは逆引きです。
逆引きの辞書は無いので、分野を変えて 2〜3 回引く、候補が出たら定義の条件を 1 つずつ実装と照らす、という手順でやってきました。
それでも、取りこぼしはあるはずです。
「時間があるので、再確認と再調査、採用しているものの再確認と、採用していなくてよさそうな名前のある技術を探してみて。時間をかけていい。類似のプロダクトから探してくるとか、コールセンター用のものとか、幅広く自然言語処理から」
この指示で、夜の作業が始まりました。
この日記は、Claude Code がそこで何をして、結果どうなったか、の記録です。
6 本に分けて、同時に走らせた#
T02 の表は 91 行あります。
1 本のセッションで上から順に読んでいくと、読む側の文脈が途中で薄くなります。
そこで、Claude Code のサブエージェント(親とは別の文脈で動く子のセッション)を 6 本、同時に走らせました。
- 検査 A: T03〜T24 の 37 行(入力を解いて返すまで)を、核の C++ と設定とデータに突き合わせる
- 検査 B: T25〜T49 の 32 行(画面・配る仕組み・確かめ方)を、MomijiUI・サーバ・検査の道具に突き合わせる
- 検査 C: T50〜T64 の 21 行(失敗の名前・作り方)を、対照表と報告書と git の履歴に突き合わせる
- 調査 D: 表で初出が「—」になっている 41 件を、検索語を変えて引き直す。前回「確かめていない」と注記した書誌 8 件も確かめる
- 調査 E: コールセンター向けの対話基盤(Rasa・Dialogflow CX・watsonx Assistant・Azure CLU・Amazon Lex など)が使っている名前のある技術を集め、うちに当たるものがあるかを付ける
- 調査 F: 自然言語で入力するアドベンチャー(Infocom・Inform 7・Façade・80 年代の日本のコマンド入力 ADV)と、日本語の短文照合の一般技術(形態素解析・BM25・再順位付け・OOD 検出・校正・ゼロ照応など)から、同じことを集める
それぞれに渡したのは、読む場所(ファイルと節)、確かめ方の決まり、報告の形(表 1 つ・ファイル名と行番号つき)、それと禁止事項です。
禁止事項は 3 つ。ファイルを変えない。bake・holdout・AI 初見プレイは回さない。推測で「合っている」と書かない。
見つけられなかったものは「確かめられず: 理由」と書く、も付けました。
走っている間、親のセッションは待つだけです。
10 分ほどで、順に報告が返ってきました。
検査役は何をしたか#
報告の「確かめた所」の欄を見ると、やったことが分かります。
検査 A は、意図の JSON 31 ファイルを node で読んで、意図 248・言い換え 2,845・意図あたり 11.47 を数え直しました。
閾値は thresholds.json を開いて、acceptB 0.33・confirmFloor 0.27・entityBonus 0.15・embedFloor 0.82・embedWeight 0.7 を読みました。
FNV-1a の offset basis は AdvInput.hpp の行を読んで、1469598103934665603(標準の 14695981039346656037 の末尾の 7 が落ちた値)であることを確かめました。
UE に同梱の onnxruntime.dll は、エンジンのフォルダの実物を開いて、ファイルの版 1.24.20260304、中の文字列 1.24.3、ライセンスの札 1.24.1 を突き合わせました。
RRF を実装して負けた話は、commit d8e58921(k=60 で実装・golden 100.0 → 98.9%)と 5416f478(削除)を git で引きました。
検査 B は、core/ を wc -l して 20 ファイル 9,766 行、lint の printf を数えて L1〜L48 で L11 が欠番=47 種、台本 46 本の !expect を数えて 342 行、golden/dev の行頭 { を数えて 176 件、probe-mut の 18 ファイルで 747 件、holdout の使用記録 225 行(actedOn は全部 false)、ledger.tsv の見出し 5 列、を実物で出しました。
サーバの server.mjs は、token bucket の容量 2・毎秒 2・429 と retry-after 1・待ち行列 32、弱い ETag と If-None-Match の完全一致、Range の 1 区間と 416、HEAD が 405、を行番号つきで読みました。
sudo の設定は「引数なしの固定スクリプト 1 本だけ」であることを確かめて、ホスト名や置き場は報告に写さない、という指示も守っていました。
検査 C は、失敗の話の裏を取る係です。
通じ率 23% → 100% は、8 月 4 日の報告の「7/30」と 8 月 5 日の報告の「28/28」。
「10 項目 PASS」は、8 月 17 日 21:54 の commit 73660ebf の手順書の 18 行目と、adv-verify-work.ps1 の Check 名 10 個。
6 日待ち続けた検査は、8 月 11 日の 9ad8f87c から 8 月 17 日の 4cf9a0cb まで。
21 回の探索的テストは、PlayLogs の wave.json を 4 日分数えて 7+1+10+3。
減色の「K-means 8」は、Pillow の Quant.c を WebFetch で読んで、8 が色数ではなく「属する色が変わった画素が 7 以下で止まる」閾値であることを、ソースの行で確かめました。
網の割合 23.7〜26.2% は、6 枚の manifest の changed/eligible を割り算して、最小と最大が一致しました。
ここまでで、数値は全部合っていました。
ずれは数値ではなく、言い方の方にありました。
ずれ 11 行#
3 本の検査で、90 行中 79 行は「合っている」、11 行が「ずれ」でした。
重い順に書きます。
- 否定の扱い(T13 の行)。表は「否定・疑問・引用・反語で、推理の主張の向きを反転させる」と書いていました。ソース(AdvClaims.hpp:315-325)は、根拠の後ろに否定があると Supported を Ambiguous に落として聞き返すだけで、反対の主張として扱う経路はありません。疑問は確認待ち、引用の中の語は数えない、反語は否定に数えない、と 4 つとも「反転」ではなかった。
- approval testing(T38 の行)。「この作品で何に使っているか」の欄が用語の定義になっていて、使い所が書かれていない。実際にはこの作品では使っていません。golden/dev が出力を写していないことは、1 行上の golden master の △ の根拠そのものでした。◎ を「使っていない(T54 で踏みかけた)」に直しました。
- adv-scaffold の工程数(T60 の行)。「9 段」と書いていましたが、実物の見出しは 1・2・3・4・5・6・6b・7・7b・8・8b・8c・9 の 13 工程で、-Compare で 14。10 月 9 日に 7b が入ってから、文書の「9 段」が 3 か所で古いままでした。
- gazetteer(T10 の行)。「抜き出して型を付けるのではなく」は半分違う。辞書の語の出現は抜き出していて(型は人物かどうかだけ)、使い先は加点と段の条件のほかに、主張の材料と手帳の欄にもある。
- norm/1 と NFKC(T03 の行)。「NFKC の部分集合に足した」は不正確で、NFKC 由来は全角 ASCII → 半角だけ。約物・空白・長音の除去、小文字化、カタカナ → ひらがな、敬体 → 常体はどれも NFKC に無い操作。部分集合ではない。
- verdict の 4 値(T41 の行)。「ANSWERED=正答」は言い過ぎ。ソースの定義は「正解表なし・上記以外」で、MISS も正しい棄却を含む。T41 の原稿の checked が同じ指摘を既にしていて、表だけが短かった。
- Fragile Test(T55 の行)。◎ にしていましたが、T55 の結論は「落ちたのは個々の検査ではなく、測定の結果の有効期限(NOT-RUN)」で、Fragile Test より over-invalidation の方が名前として合う。対照表 §3 の行を写したままの ◎ でした。
- 減色の手直し(T61 の行)。「絵ごとに色と形を手で直す」は制作の手引きの決まりであって、第一章の 6 枚の project.json は修復 0・仕上げ 0・領域指定 0。T61 の本文自身がそう書いていて、表だけが手引きの文を写していた。
- reach(T36 の行)。「到達状態を全部歩く」は、9 月 9 日から章ごとで、次の章の出発点は入った状態の積。手数で切っていない点は正しい。
- embedcheck(T07 の行)。「全件で確かめる」の全件は「言い換えの全件」で、焼いたベクトルが持つ検査入力は見ない。
- T64 の引用 3 か所。T64 は「T02 では ◎ にしましたが」と 3 回書いていましたが、T02 は同じ commit で既に ○・△・2×2 の Bayer に直してありました。T64 が引いていたのは直す前の版。
11 のうち、1・4・5・7・8・9・10 は、計画書の側は前に直してあって、記事の表だけが古い、という形でした。
「一つの契約は一か所で」と言いながら、計画書と記事の表に同じことを二度書いていたので、片方だけ直っていた。
これは今日いちばん大きな教訓で、commit の本文に 1 行で書いておきました。
「計画書を直しても表は古いままだった。一か所で直したつもりの記述が、記事の表に写しで残る」。
11 行は全部その場で直して、対照表と手引きに残っていた「9 段」も一緒に直しました。
初出の引き直し#
調査 D は、表で初出が「—」だった 41 件を、名前ごとに 2〜3 通りの検索語で引き直す係です。
前回は 1 回の検索で出なかったものを「—」にしていたので、今回は "coined"・"origin of the term"・分野名を添えて引く、本文を読めたものと書誌だけのものを分けて書く、と指示しました。
結果、10 件が埋まりました。
conformance testing は ISO/IEC 9646-1(初版 1991)。reachability analysis は Bochmann 1978(通信プロトコルの検証に導入)。precision と recall は Kent, Berry, Luehrs & Perry 1955(American Documentation。precision の語は後から)。Jaccard は 1901(仏語)と 1912(英語)。assurance case の記法 GSN は Kelly 1998 の博士論文。saturation effect は Mathur 2008 の教科書。shotgun surgery は Fowler 1999 の第 3 章。generator-verifier gap は Song ほか 2024(論文の語は generation-verification gap)。ordered dithering は Bayer 1973。
Guru Checks Output は、James Carr の 2006 年の TDD アンチパターンの一覧には無く、出所は c2.com の WikiWikiWeb の頁(定義は John Farrell、年は頁に無い)でした。前の表の注は「Carr の一覧にあるかも確かめられなかった」で、これは訂正です。
4 件は「代表」をより早い用例に替えました。
character n-gram は Damashek 1995 から Suen 1979(IEEE Trans. PAMI)へ。int8 の推論は Jacob 2018 から Vanhoucke, Senior & Mao 2011 へ。検索型の応答選択は Ji 2014 から Jafarpour & Burges 2010 へ。anaphora resolution は Hobbs 1978 から、その元になった Hobbs 1976 の報告へ。
前回「確かめていない」と注記した 8 件は、全部確かめられました。
Bruch ほかは TOIS 42(1): 1–35(冊子は 2024、online は 2023)。Dagan ほかは著者 3 名で頁 177–190。Dwork ほかは Science 349(6248): 636–638。
この 3 件は Crossref の API で書誌のメタデータを直接引いています。
Broder は SEQUENCES '97。Meszaros の本に Fragile Test の項はあって、4 つの sensitivity に分かれている。Hunt & Thomas は Addison-Wesley の 1999 年 10 月。Feathers は刊行 2004-09-22 で © 2005。Goodhart は 1975 年 7 月の RBA の会議で、論文集の刊行年は 1975 と 1976 で資料が割れる。
17 件は、名付けの初出が見つからず「—」のままです。
L2 normalization・header-only・declarative UI・golden master・approval testing・single source of truth・spec-driven development(普及は 2025 年の Kiro と Spec Kit)など。
推測で埋めない、という決まりなので、引いた検索語を添えて「見つからず」と書いてあります。
採っていない名前を 115 件集めた#
調査 E と F は、うちの外を見る係です。
E はコールセンター向けの対話基盤から 60 件、F は自然言語入力のアドベンチャーから 20 件と日本語の短文照合の一般技術から 35 件。
各行に、正式名・出典・何をするか・うちに当たるもの(T02 のどの名前か)・無ければ要らない理由の候補、を書かせました。
まとめると、三つに分かれました。
一つ目は、同じ役目のものがうちにある(形が違うだけ)。
Rasa の FallbackClassifier、Lex の fallback intent、Dialogflow の classificationThreshold は、どれも閾値による棄却で、うちの 0.33/0.27 の線と同じ役目です。
two-stage fallback と Lex の confirmation prompt は F1 の聞き返し。Dialogflow の sys.no-match-1〜6(外すたびに違う handler)は F4 → F5。lookup tables と synonyms は entities.json。
Kore.ai の Ranking and Resolver は、複数の照合エンジンの結果を統合して 95% 以上を definitive、0.3 以上を possible と 2 段に分ける仕組みで、うちの max(表層, 0.3×表層 + 0.7×埋め込み) と採用線・聞き返し線の 2 本が、製品でほぼ同じ形で動いていました。
Inform 7 の scope(今の部屋と手持ちの物だけを名詞の候補にする)は、現在地と話者で意図を絞るのと同じ向き。pronoun resolution は前者/後者。Event[0] の Kaizen(作者が書いた 1 万語のタグで入力を当てて台本の返事を選ぶ。LLM ではない)は、辞書+台本の選択という線が同じ。
二つ目は、無いが、方針から要らない。
学習しない・生成しない・決定論・日本語だけ・相手は作者の台詞・人へ渡す先が無い・候補が 2,845 文、のどれかから直接出るものです。
DIET や CLU の学習型分類器、interactive learning、active learning、intent discovery、data augmentation、generative fallback、RAG、webhook、spell correction(IBM 自身も日本語には出していない。IME の誤りは綴りの誤りと型が違う)、sentiment、human handoff、containment rate、A/B experiments、temperature scaling(確率を出す分類器が無い)、MeCab・Sudachi・係り受け(形態素解析をしない設計)、SPLADE、ColBERT、cross-encoder、learning to rank、HNSW・FAISS(2,845 件の全探索が 1 ms 台)、ゼロ照応(話者は @ で固定)、two-word parser と「知らない語を名指しする」lexical fallback(呪文探しを誘う)、menu・quip・topic suggestion、LLM 生成。
三つ目は、測ってから決めるもの。
BM25(短文では文書長の正規化が効きにくいはず)と、日本語特化の文埋め込み(ruri・GLuCoSE。精度が上でも焼き直し・閾値・ゴールデン全件の再確認が要る)の 2 つ。
RRF のときと同じ扱いで、実装して測って負けたら消す、までが一組です。
採った方がよさそうなものは、6 つが候補に挙がりました。
閾値を ROC 曲線で決め直す。言い換えの leave-one-out の lint。DBDC の三値の語彙。digression の 1 行。Sudachi の表記ゆれの表。2 候補の聞き返し。
ただ、10 月 29 日の時点で「もう機能は足さない、このままリリースする」と決めているので、どれも作りません。
報告書に「未採用の改善」として残しました。
依頼の前提の訂正も、2 つ出た#
調査役は、こちらの指示の間違いも拾ってきます。
一つ。『オホーツクに消ゆ』『軽井沢誘拐案内』は、調べた範囲では PC 版も選択式で、二語入力(「ゲンバ イケ」)は『ポートピア連続殺人事件』の PC 版だけでした。
指示には「PC 版の動詞+名詞のパーサー」と 3 作を並べて書いていたので、これは訂正です。
二つ。Guru Checks Output は James Carr の一覧には無い(上に書いたとおり)。
指示の前提が間違っていても、調査役がその前提に合わせて答えを作らなかったのは、よかったことです。
「推測で埋めない」「見つからなかったものは見つからなかったと書く」を先に決めておいたのが効いています。
新発見は 3 つ#
115 件のうち、名前としても中身としても新しく、こちらに関係するものは 3 つでした。
一つ目。Dialogue breakdown detection(DBDC・東中ら 2016)。
対話システムの返事が「破綻/破綻かも/破綻でない」の三値かを見る共通課題で、日本語の雑談対話から始まったもの。
うちの LEAK/MISS/DRIFT/ANSWERED の 4 値と同じ役目で、「Margin が小さい ACCEPT(通じたように見えて違う話が返る事故)」を名前なしで数えていた所に、借りられる語彙がありました。
二つ目。k-NN OOD detection(Sun, Ming, Zhu & Li 2022, ICML)。
分布外の入力を、特徴空間での k 番目の近傍までの距離で見分ける方法。
うちの「k=1 の最近傍の点に閾値を置いて答えるか決める」は、まさにこの骨でした。
T16 は Chow 1970 の棄却つき分類で書いていましたが、「閾値つきの最近傍」そのものに 2022 年の名前があると分かった。
三つ目。Kore.ai の Ranking and Resolver。
上に書いたとおり、点の統合と 2 段の線が製品で同じ形で動いている。
「寄せ集めは他にもあるか」という問いへの一つの答えで、記事 T08・T16 で「同型の製品がある」と書けます。
「実装できるぐらいの情報を集めた?」#
作者の次の問いはこれでした。
答えは「いいえ」です。
集めたのは名前・出典・何をするものか・うちに当たるものがあるか、までで、論文の本文は読んでいない(書誌と要旨まで)。
3 つのうち、DBDC は名前を借りるだけなので足りない情報は無い。Ranking and Resolver は製品の仕組みで、細部は公開されていない可能性がある。k-NN OOD は論文を読めば 1 日で済むが、読んでいない。
「2 の論文を読んで T16 に段落を足して」
そこで、論文を読みました。
arXiv の PDF を WebFetch で取ると、圧縮されたバイナリが返ってきて、要約の道具は「本文として読める形になっていない」と正直に言いました。
保存された PDF を Read で開こうとすると、PDF をページの絵にする部品が無くて開けない。
pypdf は入っていたので、それで 14 ページを文字にして、方法・実験・理論の節を、原文の英語で確かめました。
ar5iv(arXiv の HTML 版)も並行して引いて、同じ数字が出ることを見ました。
書誌は PMLR の頁で、ICML 2022, PMLR 162, pp. 20827–20840。
読んで分かったことを、T16 に「2022 年の名前で言い直す」という節として足しました。
論文の方法は 4 行です。特徴を L2 正規化、学習データとの距離を近い順に、k 番目までの距離 r_k、判定は 1{−r_k ≥ λ}。
λ は分布内のデータの 95% が通る点に置き、分布外のデータは使わない。
実験で効いたのは、L2 正規化が決定的で FPR95 を 61.05% 改善したこと、k は CIFAR-10 で 50・ImageNet で 1,000 を検証で選んだこと、学習データを 1% に間引くと最適な k が 10 になって性能はほぼ同じだったこと。
うちに当てはめると、学習データは言い換え 2,845 文、特徴は e5 の 384 次元の L2 正規化。
コサインで比べているのは、論文の「正規化が決定的」と同じことを言っています(正規化後のユークリッド距離はコサインの単調な関数)。
k は 1。論文の「間引くと最適な k は小さくなる」と筋は合うが、外れ値にいちばん弱い設定で、L18 と golden で外から見張っている。
閾値は手置きの 0.33 と 0.27。golden/dev で測ると 0.33 は正解の 100% が通る点で、論文の流儀では TPR 100% の点。
論文は分布内のデータから λ を決める、うちは決めた後で通り率を測る、と向きが逆です。
名前の対応として、考え方は Chow 1970、方法は Sun 2022 の k=1 の形、閾値の決め方はどちらでもない手置き、になりました。
T16 は 6,489 字から 8,857 字に。T02 の reject option の行と計画書の名前の列にも、1 行添えました。
「実装時に再度調べればいい?」#
次の問いはこれで、答えは「この論文については要らない」です。
方法が 4 行で、コードも公開されていて、λ と k の決め方も本文に書いてある。
足りないのは論文の側ではなく、うちの側で決めることです。
どの点に線を引くか(判断の点か、埋め込みの距離だけか)。k(3〜5 にすると外れ値に強くなるが、言い換えが数本の意図では本数を超える)。λ をどのデータで決めるか(言い換え自身なら自分を除いた最近傍で)。三段の帯(λ を 2 本)。決定論は崩れない(全探索のまま)。
一緒にやるなら、閾値を ROC 曲線で決め直す話と一組。
「残としてわかるようにしておいて」
報告書に §6「残」を足して、上のことを調べ直さなくて済む所まで書きました。
作業中に参照する正は対照表なので、対照表の §5-C(閾値が校正されていない、の項)に「残」の 1 行を足して、報告書へ引けるようにしてあります。
BACKLOG には積みません。この作品の規約は「途中で止めて積まない。未採用の改善は報告書に 1 行」です。
Claude Code の側でうまくいかなかったこと#
日記なので、これも書いておきます。
- 直す手順を Bash のヒアドキュメントで流すと、バックスラッシュが潰れて Python の文字列が壊れました(改行の
\nが本物の改行になる)。この罠は前にも踏んでいて、記憶には「バックスラッシュを含む内容は Write でファイルに書いてから実行」とあります。今日も同じ所で 2 回つまずいて、3 回目に Write で書き直しました - 原稿の一部が CRLF で、LF の文字列で探すと見つからない。改行の種類を見てから置き換える形に直しました
- PDF を開く部品が無い。pypdf で文字にする迂回で済みました
- 夕方には、手元のサーバーを 2 つ同時に立てていて、PC のメモリが足りなくなって両方とも止められました。それ以降は 1 つだけ立てて、見終わったら止める、にしています
どれも、手順書か記憶に 1 行ずつ残してあります。
今日の数字 — サブエージェント 6 本・ずれ 11 行・115 件#
- 走らせたサブエージェント 6 本。使った道具の回数は 51・49・42・113・83・75、時間は 6〜11 分ずつ、トークンは合計およそ 128 万
- T02 の表 91 行のうち、ずれ 11 行を直した。数値のずれは 0
- 初出「—」41 件のうち 10 件を埋め、4 件を早い用例に替え、8 件の未確認を確かめ、17 件は「—」のまま
- 採っていない名前 115 件を集め、新発見 3 つ、未採用の改善 6 つ
- 論文 1 本を本文まで読み、T16 に約 2,400 字の節を足した
- commit は 5 本。VPS に送って、外から T16 の新しい節と T02 の直しが出ていることを確かめた
何が分かったか#
一覧を「正確に探せた」のは、探し方よりも、書いた後に突き合わせる手順の方が効いていました。
今日はその突き合わせを 3 本に分けて同時に走らせ、ファイル名と行番号で根拠を出させ、推測で「合っている」と書くことを禁じた。
それで見つかったずれ 11 行は、全部「言い方」のずれで、数値のずれは 0 でした。
数値は実物を数える手順が最初からあったからで、言い方は、計画書を直したときに記事の表が置き去りになっていたからです。
名前の取りこぼしは、幅広く探しても、ほとんどありませんでした。
代わりに分かったのは「同じことを別の名前でやっている製品がある」ことで、それは記事に書く材料になります。
逆引きの辞書は無いけれど、外の製品を一つずつ読んで「うちのどれに当たるか」を付けていけば、逆引きの表が自分の手元にできる。
今日の 115 行がそれです。