[{"data":1,"prerenderedAt":582},["ShallowReactive",2],{"content-/colophon-extraction-pipeline-plan":3,"all-pages-for-dir":580,"og-image-/colophon-extraction-pipeline-plan":581},{"id":4,"title":5,"body":6,"category":562,"description":563,"extension":564,"meta":565,"navigation":504,"ogImage":566,"path":567,"project_name":19,"published":568,"publishedAt":569,"seo":570,"stem":571,"tags":572,"todo":578,"unpublished":568,"updatedAt":566,"__hash__":579},"pages/2026-05/2026-05-10/colophon-extraction-pipeline-plan.md","蔵書957件の奥付情報を一括でDBに入れる抽出パイプラインの計画策定",{"type":7,"value":8,"toc":549},"minimark",[9,13,21,24,35,38,41,44,48,55,58,97,100,149,152,156,177,298,305,308,336,348,351,355,358,364,370,373,395,398,402,405,412,416,419,447,450,453,477,480,487,490,493,545],[10,11,12],"h2",{"id":12},"やったこと",[14,15,16,20],"p",{},[17,18,19],"code",{},"book-knowledge-base"," プロジェクトで、Dropbox 配下の「00連番フォルダ」に積み上がっている書籍PDF 957件から、奥付（巻末の書誌情報）を一括抽出して Turso DB に流し込むパイプラインの計画書を書き上げた。手は動かさず、設計と検証だけで一日を使い切った。実装は明日に積み残す。",[10,22,23],{"id":23},"背景",[14,25,26,27,30,31,34],{},"蔵書PDFは Dropbox の ",[17,28,29],{},"00_books/"," 配下に連番で積み上がっていて、ファイル数を数えたら 957件あった。ファイル名は ",[17,32,33],{},"/rename-pdf"," スキルで書名に正規化済みだが、出版社・初版発行日・ISBN・定価・著者複数名などは file system に乗っていない。書籍ビューアから「2010年以前の会計実務書だけ拾いたい」と思っても、ファイル名だけでは絞り込めない。奥付に書かれた書誌情報を構造化して DB に入れれば、Claude Code 経由の蔵書検索で論点 × 出版年 × 出版社の三軸が効くようになる。",[10,36,37],{"id":37},"蔵書の棚卸し",[14,39,40],{},"最初に蔵書フォルダ 842件を Amazon レビューの星評価 × レビュー数でランキング表示してもらった。漫画が上位に大量に出てきたので、漫画を除外して、会計・ファイナンス・ドキュメント設計系のコンテンツ関連書籍に絞り込んだ。リストを眺めながら「これだけ持っていて、内容が DB に入っていないのは勿体ない」と腹落ちした。",[14,42,43],{},"そのまま Claude Code に「全書籍の奥付情報を DB に入れたい。リネームPDFスキルに近いことをやる」と投げた。",[10,45,47],{"id":46},"計画書-v1-と-codex-の致命指摘4件","計画書 v1 と Codex の致命指摘4件",[14,49,50,51,54],{},"Claude Code が ",[17,52,53],{},"memo/2026-05-10/colophon-extraction-plan.md"," に v1 を書いた。22項目（タイトル、サブタイトル、版表示、版番号、刷表示、刷番号、初版発行日、刷発行日、著者、編者、訳者、発行所、印刷所、ISBN、定価数値、定価表示、奥付生テキスト、抽出ページ番号、抽出ステータス、エラー、抽出日時、使用モデル）を Anthropic API を直接叩いて抽出する設計だった。",[14,56,57],{},"ルールに従って Codex レビューに回した。",[59,60,65],"pre",{"className":61,"code":62,"language":63,"meta":64,"style":64},"language-bash shiki shiki-themes vitesse-light vitesse-light","codex exec -m gpt-5.5 \"このプランをレビューして。瑣末な点へのクソリプはしないで。致命的な点だけ指摘して: memo/2026-05-10/colophon-extraction-plan.md\"\n","bash","",[17,66,67],{"__ignoreMap":64},[68,69,72,76,80,84,87,91,94],"span",{"class":70,"line":71},"line",1,[68,73,75],{"class":74},"senZ8","codex",[68,77,79],{"class":78},"sdGka"," exec",[68,81,83],{"class":82},"snbK4"," -m",[68,85,86],{"class":78}," gpt-5.5",[68,88,90],{"class":89},"sMJiu"," \"",[68,92,93],{"class":78},"このプランをレビューして。瑣末な点へのクソリプはしないで。致命的な点だけ指摘して: memo/2026-05-10/colophon-extraction-plan.md",[68,95,96],{"class":89},"\"\n",[14,98,99],{},"「瑣末な点へのクソリプはしないで」を入れたおかげで、Codex は最初から太い指摘だけを返した。4件あった。",[101,102,103,123,137,143],"ol",{},[104,105,106,110,111,114,115,118,119,122],"li",{},[107,108,109],"strong",{},"既存スキーマ番号と衝突している"," — ",[17,112,113],{},"migrations/"," の連番を確認せずに ",[17,116,117],{},"005_"," を振っていた。実際は ",[17,120,121],{},"008_"," まで埋まっていた",[104,124,125,128,129,132,133,136],{},[107,126,127],{},"Turso 接続コードを新規に書こうとしている"," — 既に ",[17,130,131],{},"src/db.py"," に Embedded Replica パターンが書いてあり、",[17,134,135],{},"amazon_metadata"," テーブルで file_no を PK にした接続が動いている",[104,138,139,142],{},[107,140,141],{},"file_no の連携設計が抜けている"," — Amazon メタデータと奥付情報は file_no で 1:1 で紐付くべきだが、計画書には独立した surrogate key が振られていた",[104,144,145,148],{},[107,146,147],{},"Vision の実行方法が不明"," — 「Claude Sonnet で Vision を叩く」とだけ書いてあって、どこから何のクライアントで叩くのかが宙に浮いていた",[14,150,151],{},"どれも実装に入る前に潰しておかないと、Phase 1 で全部詰む類の指摘だった。",[10,153,155],{"id":154},"v2-で既存資産に直結させる","v2 で既存資産に直結させる",[14,157,158,159,162,163,166,167,169,170,172,173,176],{},"計画書を v2 に巻き直した。マイグレーション番号を ",[17,160,161],{},"008_book_colophons.sql"," に直し、",[17,164,165],{},"file_no"," を PK にして ",[17,168,135],{}," と FK で結ぶ設計に変えた。Turso 接続は ",[17,171,131],{}," の ",[17,174,175],{},"get_db()"," を再利用する形に直し、新規にクライアントを書き起こさない方針を明記した。",[59,178,182],{"className":179,"code":180,"language":181,"meta":64,"style":64},"language-sql shiki shiki-themes vitesse-light vitesse-light","CREATE TABLE IF NOT EXISTS book_colophons (\n  file_no TEXT PRIMARY KEY REFERENCES amazon_metadata(file_no),\n  title TEXT,\n  isbn TEXT,\n  -- ... 22項目\n  raw_text TEXT,\n  extraction_status TEXT,\n  extracted_at TEXT,\n  model_used TEXT\n);\n","sql",[17,183,184,206,225,236,246,253,263,273,283,292],{"__ignoreMap":64},[68,185,186,190,193,196,199,202],{"class":70,"line":71},[68,187,189],{"class":188},"sHkkW","CREATE",[68,191,192],{"class":188}," TABLE",[68,194,195],{"class":74}," IF",[68,197,198],{"class":188}," NOT",[68,200,201],{"class":188}," EXISTS",[68,203,205],{"class":204},"sG7-3"," book_colophons (\n",[68,207,209,212,216,219,222],{"class":70,"line":208},2,[68,210,211],{"class":204},"  file_no ",[68,213,215],{"class":214},"stQ0i","TEXT",[68,217,218],{"class":214}," PRIMARY KEY",[68,220,221],{"class":214}," REFERENCES",[68,223,224],{"class":204}," amazon_metadata(file_no),\n",[68,226,228,231,233],{"class":70,"line":227},3,[68,229,230],{"class":204},"  title ",[68,232,215],{"class":214},[68,234,235],{"class":204},",\n",[68,237,239,242,244],{"class":70,"line":238},4,[68,240,241],{"class":204},"  isbn ",[68,243,215],{"class":214},[68,245,235],{"class":204},[68,247,249],{"class":70,"line":248},5,[68,250,252],{"class":251},"sxvE3","  -- ... 22項目\n",[68,254,256,259,261],{"class":70,"line":255},6,[68,257,258],{"class":204},"  raw_text ",[68,260,215],{"class":214},[68,262,235],{"class":204},[68,264,266,269,271],{"class":70,"line":265},7,[68,267,268],{"class":204},"  extraction_status ",[68,270,215],{"class":214},[68,272,235],{"class":204},[68,274,276,279,281],{"class":70,"line":275},8,[68,277,278],{"class":204},"  extracted_at ",[68,280,215],{"class":214},[68,282,235],{"class":204},[68,284,286,289],{"class":70,"line":285},9,[68,287,288],{"class":204},"  model_used ",[68,290,291],{"class":214},"TEXT\n",[68,293,295],{"class":70,"line":294},10,[68,296,297],{"class":204},");\n",[14,299,300,301,304],{},"これで ",[17,302,303],{},"JOIN amazon_metadata USING (file_no)"," だけで Amazon の評価 × 奥付の出版年 × ISBN が同じ行に並ぶ。",[14,306,307],{},"再レビューに回した。今度は3件、追加で致命点が返ってきた。",[59,309,311],{"className":61,"code":310,"language":63,"meta":64,"style":64},"codex exec resume --last -m gpt-5.5 \"プランを更新したからレビューして。瑣末な点へのクソリプはしないで。致命的な点だけ指摘して\"\n",[17,312,313],{"__ignoreMap":64},[68,314,315,317,319,322,325,327,329,331,334],{"class":70,"line":71},[68,316,75],{"class":74},[68,318,79],{"class":78},[68,320,321],{"class":78}," resume",[68,323,324],{"class":82}," --last",[68,326,83],{"class":82},[68,328,86],{"class":78},[68,330,90],{"class":89},[68,332,333],{"class":78},"プランを更新したからレビューして。瑣末な点へのクソリプはしないで。致命的な点だけ指摘して",[68,335,96],{"class":89},[337,338,339,342,345],"ul",{},[104,340,341],{},"並列度の上限指定が抜けている（957件を全部同時に投げる設計に見える）",[104,343,344],{},"エラー時のリトライ条件が「失敗したら止める」しか書いていない",[104,346,347],{},"中間ステートの保存粒度が file_no 単位ではなくバッチ単位になっている（部分失敗で全件やり直しになる）",[14,349,350],{},"ここまでで設計は実装可能な形に近づいた。",[10,352,354],{"id":353},"筆者からのコスト指摘で-v3-に書き換える","筆者からのコスト指摘で v3 に書き換える",[14,356,357],{},"Codex のレビューは通り抜けつつあったが、計画書を読み返したらコスト見積もりの欄が妙に膨らんでいた。957件 × 5ページ × Vision API 単価で「概算 $XX」と書かれていて、桁感が腹落ちしない。Claude Code に投げた。",[359,360,361],"blockquote",{},[14,362,363],{},"コストの見込みが意味わかんないんですけど、このクロードコードの中でやればコストそんなかかんないですよね",[14,365,366,367,369],{},"Anthropic API を直叩きする前提で計算していた、と Claude Code が返してきた。",[17,368,33],{}," スキルは Claude Code の中で完結していて追加課金ゼロで回っているのに、なぜか奥付抽出だけ外部APIを呼ぶ設計になっていた。サブエージェントを並列起動すれば haiku で 10並列回せるし、Claude Code のサブスクリプション内で完結する。",[14,371,372],{},"v3 に書き換えた。",[337,374,375,382,385,392],{},[104,376,377,378,381],{},"PDFの末尾5ページを ",[17,379,380],{},"pymupdf"," で dpi=200 のPNGに書き出す",[104,383,384],{},"Claude Code のサブエージェントを 10並列で起動して、各エージェントが画像から22項目をJSONで返す",[104,386,387,388,391],{},"メインが JSON を集約して ",[17,389,390],{},"INSERT OR REPLACE INTO book_colophons"," で書き込む",[104,393,394],{},"追加API課金ゼロ",[14,396,397],{},"3周目の Codex レビューに回したら、今度は OK が返ってきた。",[10,399,401],{"id":400},"codex-のクソリプ防止指示に救われた話","Codex のクソリプ防止指示に救われた話",[14,403,404],{},"3周のレビューを通じて、「瑣末な点へのクソリプはしないで」の一文がずっと効いていた。これを入れないと Codex は「変数名の命名規則」「コメントの語尾」「マイグレーションファイルの著作権ヘッダ」みたいな表面の話で行を埋めてくる。致命点だけに絞らせると、出てくる指摘が全部「実装前に潰さないと Phase 1 で詰む」レベルに揃う。",[14,406,407,408,411],{},"計画レビューにおいては、Codex に何を言わせるかではなく、",[107,409,410],{},"何を言わせないか","で精度が決まる。",[10,413,415],{"id":414},"v3-で実装に手を付けた範囲","v3 で実装に手を付けた範囲",[14,417,418],{},"計画が固まったので、明日すぐ Phase 0 が走るところまでだけ手を入れた。",[337,420,421,428,440],{},[104,422,423,424,427],{},"DBスキーマ ",[17,425,426],{},"migrations/008_book_colophons.sql"," を書いた",[104,429,430,431,434,435,172,437,439],{},"スキーマ適用スクリプト ",[17,432,433],{},"scripts/apply_colophon_schema.py"," を書いた（既存の ",[17,436,131],{},[17,438,175],{}," を呼び出すだけの薄いラッパー）",[104,441,442,443,446],{},"Phase 1 対象10件のリストを ",[17,444,445],{},"memo/2026-05-10/phase1-targets.md"," に確定した",[14,448,449],{},"Phase 1 の10件は、奥付フォーマットが標準的な技術書・実務書・教科書から選んだ。スキャン品質のばらつきが少ない順に並べてある。",[10,451,452],{"id":452},"設計のポイント",[337,454,455,468,471,474],{},[104,456,457,458,461,462,464,465,467],{},"DBスキーマ: ",[17,459,460],{},"book_colophons"," テーブル（",[17,463,165],{}," を PK で ",[17,466,135],{}," と1:1紐付け）",[104,469,470],{},"抽出フロー: PDF末尾5ページを dpi=200 でPNG化 → Claude Code 内でサブエージェント並列起動（haiku想定、10並列）→ JSON返却を集約 → Turso へ INSERT OR REPLACE",[104,472,473],{},"追加API課金ゼロ: Claude Code サブスクリプション内で完結",[104,475,476],{},"漸進的: Phase 1（10件）→ 結果確認 → Phase 2（100件）→ Phase 3（全件）",[10,478,479],{"id":479},"学び",[14,481,482,483,486],{},"AI レビュアー（Codex）は構造的な指摘は鋭いが、",[107,484,485],{},"ビジネス的に意味のある指摘は人間の方が鋭い","。「コスト見積もりの桁感がおかしい」を Codex は最後まで指摘しなかった。Anthropic API を呼ぶ前提のコード断面を見せても「妥当な単価です」と返してくる。一方、筆者が「Claude Code 内でやればコストかからないですよね」と一言投げただけで、設計が根本から書き直しになった。",[14,488,489],{},"計画策定は Codex レビュー → 人間チェック → Codex 再レビュー の3点測量が一番効く。AI 同士のレビュー往復だけで閉じると、ビジネスの臭いが取れない。",[10,491,492],{"id":492},"明日やること",[337,494,497,514,524,530,539],{"className":495},[496],"contains-task-list",[104,498,501,506,507,510,511,513],{"className":499},[500],"task-list-item",[502,503],"input",{"disabled":504,"type":505},true,"checkbox"," Phase 0: ",[17,508,509],{},"python scripts/apply_colophon_schema.py"," で ",[17,512,460],{}," テーブルを Turso に作成する",[104,515,517,519,520,523],{"className":516},[500],[502,518],{"disabled":504,"type":505}," Phase 1: 対象10件のPDF末尾5ページを dpi=200 でPNG化して ",[17,521,522],{},"tmp/colophon-images/{file_no}/"," に書き出す",[104,525,527,529],{"className":526},[500],[502,528],{"disabled":504,"type":505}," Phase 1: サブエージェント10並列を起動して22項目を JSON で抽出させる",[104,531,533,535,536,538],{"className":532},[500],[502,534],{"disabled":504,"type":505}," Phase 1: 集約した JSON を ",[17,537,390],{}," で Turso に書き込む",[104,540,542,544],{"className":541},[500],[502,543],{"disabled":504,"type":505}," Phase 1: 10件の抽出結果を目視確認して、フィールド欠損・誤抽出のパターンを記録する",[546,547,548],"style",{},"html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html pre.shiki code .sG7-3, html code.shiki .sG7-3{--shiki-default:#393A34;--shiki-dark:#393A34}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}",{"title":64,"searchDepth":208,"depth":208,"links":550},[551,552,553,554,555,556,557,558,559,560,561],{"id":12,"depth":208,"text":12},{"id":23,"depth":208,"text":23},{"id":37,"depth":208,"text":37},{"id":46,"depth":208,"text":47},{"id":154,"depth":208,"text":155},{"id":353,"depth":208,"text":354},{"id":400,"depth":208,"text":401},{"id":414,"depth":208,"text":415},{"id":452,"depth":208,"text":452},{"id":479,"depth":208,"text":479},{"id":492,"depth":208,"text":492},"dev","Dropbox配下に積み上がった蔵書PDF 957件から、巻末の奥付（書誌情報）22項目を抽出してTurso DBに格納するパイプラインの計画を立てた。Codexレビューを2周回した上に、筆者からのコスト指摘で設計が3回書き換わった実装前ログ。","md",{},null,"/colophon-extraction-pipeline-plan",false,"2026-05-10T00:00:00.000Z",{"title":5,"description":563},"2026-05/2026-05-10/colophon-extraction-pipeline-plan",[573,574,575,576,577],"蔵書管理","Turso","Claude Code","Codex","計画策定","active","E9u6O3ytItWloH5rRkTIrWymbSrtkiGPGGP0jqDuSWs",[],"https://log.eurekapu.com/og/blog/colophon-extraction-pipeline-plan.png?v=2026-05-10T00%3A00%3A00.000Z&title=%E8%94%B5%E6%9B%B8957%E4%BB%B6%E3%81%AE%E5%A5%A5%E4%BB%98%E6%83%85%E5%A0%B1%E3%82%92%E4%B8%80%E6%8B%AC%E3%81%A7DB%E3%81%AB%E5%85%A5%E3%82%8C%E3%82%8B%E6%8A%BD%E5%87%BA%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3%E3%81%AE%E8%A8%88%E7%94%BB%E7%AD%96%E5%AE%9A&author=Kei%20Komatsu&sig=4375477194966f14",1782528834667]