語源英単語4000語をどう一覧化するか — Codex実装の停滞からナビゲーション統合まで

開発eurekapu-nuxt4

語源英単語4000語をどう一覧化するか — Codex実装の停滞からナビゲーション統合まで

語源英単語講座の「今日の復習」ページは、その日出す単語をトレーナーが自動で選んでくれる。

便利だが、裏を返せば「今、自分がどの単語を見たいか」を選べない。

「今日の復習」だけでは辿り着けない語

朝の積み残し処理(typecheck修正コミット分のクイズ回答、ローカルブランチの棚卸し)を終えたあとの06:57、新しい依頼を出した。仕分けの練習問題ページには全範囲・商品売買といったカテゴリー別選択があり、あれと同じ発想で4000語ぶんの一覧を持たせたい。スクリーンショットを添えて、そう伝えた。

計画を立てる前に、アトラス3,859語のetymologyフィールドの中身を数えさせた。ここで最初のつまずきが見つかる。

語根メモとして機能しているデータと、単なる暗記法のメモに過ぎないデータが混在していた。「語根ファミリーで全語をきれいに分類できる」という前提自体、まだ検証されていなかったわけだ。

Planエージェントを2並列(データ設計・UX設計)で走らせ、計画書を作らせた。仕分け練習問題ページの選択肢をそのまま真似ると、140〜160件のフラットな<select>になって選べなくなる——というUX側の指摘が特に効いた。

カバー率を機械的な合格基準にすると「既知の613語だけ高精度で処理して終わり」という本末転倒が起きるリスクも、Codexの再レビューで拾ってもらった。カバー率50%割れを、機械的なブロッカーではなく「人が立ち止まって判断するトリガー」として設計し直させた。

セッションを分け、実装をCodexに任せることにした

ここでセッションを分けることにした。調査とPlanエージェント2件とレビュー3往復でコンテキストがかなり厚くなっていたし、これから始まる3,246語のタグ付けフェーズは性質の異なる長丁場になる。

もう一点、この日決めたことがある。実装の担当をChatGPTではなく、OpenAIのCodex(5.6-SOL)に任せることにした。承認済みの計画書をmemo/2026-07-21/へ移し、次のセッションへ引き継いだ。

Codexに投げて3時間、進まなかった

09:14からのセッション、タグ付けフェーズ(Step 1〜7)をCodexへ委譲した。3,859語をバッチ処理しながら適合率90%ゲートをかけていく大きな処理なので、時間はかかるだろうと踏んでいた。

想定より長く止まった。最初の試みは、指示文に入れた「前回のレビューセッションをresumeできたら引き継いで」という一文が原因だった。Codexセッションの中からさらに別のCodexプロセスを呼ぼうとする「ネストした呼び出し」を誘発し、Windowsの権限設定に弾かれて自壊していた。

指示のミスだと分かって書き直させると、今度は動き出した。次に当たったのは~/.codex/tmpへの書き込み不可というWindows環境の壁だった。ファイル書き込みが失敗し、C:\tmpへの一時領域リダイレクトという回避策を試みるところまでは自力で辿り着いていたが、それでも止まる。

3時間近く、同じ種類の壁で足止めが続いた。

「これね、やっぱりSonnet 5で実装して、OpenAI codex 5.6-SOLにレビューをさせましょうか。その方が多分早いですよね」

その方針に決め、担当を入れ替えさせた。Codexに実装を任せる体制そのものをやめたわけではなく、役割を実装からレビューへ移しただけだ。動いているCodexジョブを片付けさせてからStep 8を任せると、あとは一直線に進んだ。この切り替えは正しい判断だった。

引き取らせてわかったバグ2つ

カバー率を再計算させると、計画書の報告値(21.10%)と実装結果(16.32%)が食い違った。原因は、アトラス語が既存の章由来語根(duct-duceなど)にも分類されていて、それをスクリプトが取りこぼしていたことだった。修正させて数字を合わせた。

一覧ページの語数表示「846語」も、wordCountを単純合計していたために2語が二重計上されていた。計画全体で使っている「ユニークwordId基準」に揃え直させて844語に修正した。

どちらも、Codexに投げずに直接実装させたからこそ、途中で拾えた不整合だった。

Step 8〜17を実装させ、テスト205件・型チェック・lintを確認させたあと、Chrome DevToolsでモバイル・デスクトップの実機を確認した。ファミリー限定セッションで無関係な復習語が混ざらないことも、実際にセッションを開始して出題語を目で追って確かめた。

仕上げにCodexへレビューを依頼すると、index.vueの紹介文が実データ(844語)と矛盾する「4,000語を一覧」という誇張表現になっている、という指摘が返ってきた。計画書のスニペットをそのまま流用した箇所で、これも直させた。

全語を割り振れなかった理由

最終的な語根ファミリーは90件・844語、4000語に対するカバー率21.10%にとどまった。「なぜ全語を割り振れなかったのか」を計画書に残してほしいと頼み、実施結果セクションを追記させた。

要点は、アトラス3,859語のうち語根メモとして使えるetymologyが613語しかなかったことにある。適合率90%ゲートを通過できた範囲も、実質そこにとどまった。

無理に閾値を緩めて分類を水増しすれば数字は伸びる。ただ、それは「語源で単語を理解する」という講座の目的そのものを裏切る。844語という結果は、精度を優先した結果としての数字だ。

パンくずが1つしかなかった

/lessons/gogen-eitango/roots/spectを見ていて、パンくずリストがないことに気づいた。他ページとレイアウトを揃えてほしいと頼むと、原因はすぐに判明した。bookkeeping-miller.vueの分岐リストにgogen-eitangoだけが含まれていなかった。

1行追加で直る話だったが、直したあとに別の違和感が出てきた。詳説章・単語リスト・語根ファミリーという3種類のコンテンツが、同じパンくずで表示されていた。

「これ重複してない並列のコンテンツだとしたら、それで分かるようにしてほしい」と伝え、パンくずを3種類に分けさせ、講義ノートのトップページにも語根ファミリーへの独立したカードを追加させた。

PART1〜5で4000語を矢印キーだけで辿れるようにする

午後のセッション(13:42)では、詳説18章・単語リスト59モジュール・語根ファミリー90件という3系統が、それぞれ独立したミラーカラムページのままだった構造に手を入れさせた。左カラムのセクション列に「PART」見出しを挿入する機能を新規に作らせ、1本の統合TOCを3ページが共有する形に組み替えさせた。

ここでもCodexレビューで致命的な指摘を拾ってもらった。計画書で「章のスライド数は既存の値を転記する」としていた数字が、実は簿記3級講座のスライド数だった。IDが1〜18で衝突している既存バグの上に計画を積んでいたことになる。

実測し直すと詳説18章の本当の合計は177で、転記しようとしていた値(1,337)とは別物だった。ここを直させてから実装に入らせた。

単語リストと語根ファミリーで同じ単語が二重に出てくる問題も、「矢印キーで4000語を重複なく辿れるようにしたい」という本質的な要求に立ち返って解消させた。単語リスト側が語根ファミリーで拾えた語を除外する形にし、PART1〜5合計で重複ゼロを確認した。

デプロイしたら本番だけ壊れていた

コミット・デプロイまで進めたところで、本番の語根ファミリー詳細ページだけ単語が空になる不具合に当たった。dev環境では起きていない。

原因は、SSR実行時に生の$fetchが内部API呼び出しを解決できないという典型的な罠だった。useRequestFetch()に置き換えさせて直させた。

厄介だったのは、この修正をコミットする前に一度デプロイが走っていたことだ。デプロイログの成功表示を見て安心しかけたが、実際にビルドされていたのはバグ入りのコミットだった。

修正をコミットし直させ、再度ビルド・デプロイさせて、本番で単語が表示されることを確認してから作業を終えた。カバー率21.10%という数字だけは、まだ次に何か手を入れる余地として残っている。

学び

  • 実装委任は「詰まったら早めに撤退する」判断が要る。Windows環境の壁で3時間止まったとき、粘り続けるのではなく担当をSonnet 5に戻したことで、そこから一直線に進んだ
  • カバー率のような単一数値は、報告値を鵜呑みにせず自分でも再計算させる。21.10%と16.32%の食い違いは、実装を引き取らせたからこそ拾えた
  • 「重複してない並列コンテンツ」はナビゲーションでも区別する。同じパンくずに3種類の性質が混ざっていると、コンテンツの構造そのものが伝わらない