[{"data":1,"prerenderedAt":494},["ShallowReactive",2],{"content-/2026-04-29-shelf-semilattice-tagging":3,"all-pages-for-dir":492,"og-image-/2026-04-29-shelf-semilattice-tagging":493},{"id":4,"title":5,"body":6,"category":473,"description":474,"extension":475,"meta":476,"navigation":436,"path":477,"project_name":478,"published":479,"publishedAt":480,"seo":481,"stem":482,"tags":483,"todo":490,"updatedAt":490,"__hash__":491},"pages/2026-04/2026-04-29/shelf-semilattice-tagging.md","蔵書841冊にセミラティス的タグを付ける：サブエージェント8並列＋Codex2回レビュー＋コンテンツ軸の追加",{"type":7,"value":8,"toc":461},"minimark",[9,13,17,22,30,41,44,135,138,142,145,148,151,155,158,190,214,221,225,232,235,239,242,270,276,279,304,307,311,322,325,332,336,343,346,369,372,379,383,390,393,396,410,413,419,422,425,457],[10,11,5],"h1",{"id":12},"蔵書841冊にセミラティス的タグを付けるサブエージェント8並列codex2回レビューコンテンツ軸の追加",[14,15,16],"p",{},"蔵書ナレッジベース（841冊）の整理を1日で進めた。Amazonからの商品メタ全件取得を完走させ、841冊をサブエージェント8並列で分類し、shelf UIにタグフィルタとコンテンツ軸（第3軸）を追加した。CAPTCHAで2回止まり、Codexに2回レビューを依頼し、エンコードエラーに引っかかりながら、夕方には全冊の二軸分類が一覧で見える状態になった。",[18,19,21],"h2",{"id":20},"amazon商品詳細メタの全件取得cp932エンコードエラーで肝が冷える","Amazon商品詳細メタの全件取得：cp932エンコードエラーで肝が冷える",[14,23,24,25,29],{},"朝イチでAmazonからの商品詳細メタ取得を再開した。残り177件をスクレイパーに流し、ログを眺めていたら ",[26,27,28],"code",{},"UnicodeEncodeError: 'cp932' codec can't encode character"," がコンソールに連発しはじめた。",[14,31,32,33,36,37,40],{},"DB書き込みは止まらず、レコードは入っている。ファイルの中身を ",[26,34,35],{},"select"," してみると正しいUTF-8で保存されている。原因は ",[26,38,39],{},"print()"," 経由の標準出力で、Windowsのデフォルトコードページ（cp932）が絵文字や一部の中点文字をエンコードできず、ターミナル出力時にだけ落ちていた。実害はゼロだったが、ログが赤で埋まると進捗が読めない。",[14,42,43],{},"スクレイパーの先頭で stdout / stderr を UTF-8 に切り替えた。",[45,46,51],"pre",{"className":47,"code":48,"language":49,"meta":50,"style":50},"language-python shiki shiki-themes vitesse-light vitesse-light","import sys\nsys.stdout.reconfigure(encoding=\"utf-8\")\nsys.stderr.reconfigure(encoding=\"utf-8\")\n","python","",[26,52,53,66,107],{"__ignoreMap":50},[54,55,58,62],"span",{"class":56,"line":57},"line",1,[54,59,61],{"class":60},"sHkkW","import",[54,63,65],{"class":64},"sG7-3"," sys\n",[54,67,69,72,76,79,81,84,87,91,94,98,102,104],{"class":56,"line":68},2,[54,70,71],{"class":64},"sys",[54,73,75],{"class":74},"shFtX",".",[54,77,78],{"class":64},"stdout",[54,80,75],{"class":74},[54,82,83],{"class":64},"reconfigure",[54,85,86],{"class":74},"(",[54,88,90],{"class":89},"s4oTP","encoding",[54,92,93],{"class":74},"=",[54,95,97],{"class":96},"sMJiu","\"",[54,99,101],{"class":100},"sdGka","utf-8",[54,103,97],{"class":96},[54,105,106],{"class":74},")\n",[54,108,110,112,114,117,119,121,123,125,127,129,131,133],{"class":56,"line":109},3,[54,111,71],{"class":64},[54,113,75],{"class":74},[54,115,116],{"class":64},"stderr",[54,118,75],{"class":74},[54,120,83],{"class":64},[54,122,86],{"class":74},[54,124,90],{"class":89},[54,126,93],{"class":74},[54,128,97],{"class":96},[54,130,101],{"class":100},[54,132,97],{"class":96},[54,134,106],{"class":74},[14,136,137],{},"これで赤いエラーが消え、進捗がそのまま読めるようになった。途中CAPTCHAが1回挟まり、ブラウザで通すと残りを完走した。177件すべてのメタが揃い、合計841冊分のタイトル・サブタイトル・カテゴリ情報がDBに乗った。",[18,139,141],{"id":140},"_841冊のセミラティス的タグ付けサブエージェント8並列で走らせる","841冊のセミラティス的タグ付け：サブエージェント8並列で走らせる",[14,143,144],{},"次は分類だ。蔵書ビューアの「棚」を整理するには、書籍に複数の軸（カテゴリ・難易度・対象読者など）を重ねて付ける必要がある。1冊が複数の親に属する=セミラティス構造で扱いたい。",[14,146,147],{},"最初は「Amazonのカテゴリツリーをそのまま流用するか」と考えたが、Amazonの分類はビジネス・経済 > 経営・キャリア > 起業 のような階層で、僕の蔵書（簿記・会計・ファイナンス・投資・エンジニアリングが混在）とは粒度が合わない。タイトルを目視しながらタグ辞書を手で設計することにした。",[14,149,150],{},"タグ辞書を作ったあと、841冊をサブエージェント8並列で分類した。1エージェントあたり約100冊を担当させ、JSONLでタグ候補を吐き出させる。並列化したのは速度のためというより、エージェントごとに「タイトルからタグを推論する基準」を独立に持たせて偏りを比較するためだった。結果として8並列で約20分で全件のタグ候補が揃った。",[18,152,154],{"id":153},"codexレビューv1キー設計の致命的バグを指摘される","Codexレビューv1：キー設計の致命的バグを指摘される",[14,156,157],{},"タグ辞書とDBスキーマができた段階でCodexにレビューを投げた。",[45,159,163],{"className":160,"code":161,"language":162,"meta":50,"style":50},"language-bash shiki shiki-themes vitesse-light vitesse-light","codex exec -m gpt-5.4 \"プランをレビューして。瑣末な点へのクソリプはしないで、致命的な点だけ指摘して: ...\"\n","bash",[26,164,165],{"__ignoreMap":50},[54,166,167,171,174,178,181,184,187],{"class":56,"line":57},[54,168,170],{"class":169},"senZ8","codex",[54,172,173],{"class":100}," exec",[54,175,177],{"class":176},"snbK4"," -m",[54,179,180],{"class":100}," gpt-5.4",[54,182,183],{"class":96}," \"",[54,185,186],{"class":100},"プランをレビューして。瑣末な点へのクソリプはしないで、致命的な点だけ指摘して: ...",[54,188,189],{"class":96},"\"\n",[14,191,192,193,197,198,201,202,205,206,209,210,213],{},"戻ってきた指摘で一番痛かったのが",[194,195,196],"strong",{},"キー設計のミス","だった。",[26,199,200],{},"book_tags"," テーブルの主キーを ",[26,203,204],{},"(file_no, category)"," で切っていたが、タグの出所を表す ",[26,207,208],{},"source"," カラムがキーに含まれていない。",[26,211,212],{},"INSERT OR REPLACE"," を使うと、自動付与（タイトルマッチ）で入れた行を、後から手動レビューの行が上書きしたり、その逆が起きたりする。既存行を破壊する事故が容易に起きる構造だった。",[14,215,216,217,220],{},"主キーを ",[26,218,219],{},"(file_no, category, source)"," に直し、自動付与・手動レビュー・Claude再走査の3系統の行が共存できるようにした。",[18,222,224],{"id":223},"baseline-60冊で目盛りを作り残り781冊を8バッチに分割","baseline 60冊で目盛りを作り、残り781冊を8バッチに分割",[14,226,227,228,231],{},"Codexのv1レビューでもう1つ大きな指摘があった。「",[194,229,230],{},"baselineを明文化しろ","」だ。サブエージェント並列で分類すると、エージェントごとに判定基準が微妙にズレる。バッチ間の整合性を担保するには、全エージェントが同じ判定基準を見られる「お手本」が要る。",[14,233,234],{},"代表的な60冊を選び、人間が手動でタグ付けした。簿記入門書、会計士テキスト、コーポレートファイナンス、投資の名著、エンジニアリングの定番——カバーしたい軸ごとにbaselineを置く。残りの781冊を8バッチに均等分割し、各サブエージェントには「baseline 60件＋自分の担当バッチ」を渡した。エージェントはbaselineをガイドにして担当バッチをタグ付けし、JSONLを出力する。",[18,236,238],{"id":237},"codexレビューv3検証ロジック強化と交差禁止ルール","Codexレビューv3：検証ロジック強化と交差禁止ルール",[14,240,241],{},"更新したプランを再度Codexに投げた。",[45,243,245],{"className":160,"code":244,"language":162,"meta":50,"style":50},"codex exec resume --last -m gpt-5.4 \"プランを更新したからレビューして。瑣末な点へのクソリプはしないで、致命的な点だけ指摘して: ...\"\n",[26,246,247],{"__ignoreMap":50},[54,248,249,251,253,256,259,261,263,265,268],{"class":56,"line":57},[54,250,170],{"class":169},[54,252,173],{"class":100},[54,254,255],{"class":100}," resume",[54,257,258],{"class":176}," --last",[54,260,177],{"class":176},[54,262,180],{"class":100},[54,264,183],{"class":96},[54,266,267],{"class":100},"プランを更新したからレビューして。瑣末な点へのクソリプはしないで、致命的な点だけ指摘して: ...",[54,269,189],{"class":96},[14,271,272,275],{},[26,273,274],{},"resume --last"," で前回の文脈を引き継がせるのがコツだ。これを忘れると毎回ゼロから説明し直すことになる。",[14,277,278],{},"v3のレビューで指摘されたのは検証ロジックの甘さだった。",[280,281,282,292,298],"ul",{},[283,284,285,288,289,291],"li",{},[194,286,287],{},"重複検出",": 同じ ",[26,290,219],{}," の組が2行以上入っていないか",[283,293,294,297],{},[194,295,296],{},"タグ個数チェック",": 1冊あたりのタグが上限・下限の範囲に収まっているか（多すぎる本は分類が雑、少なすぎる本は取りこぼし）",[283,299,300,303],{},[194,301,302],{},"交差禁止",": 「簿記3級」と「簿記2級」のような排他的タグが同一書籍に同時付与されていないか",[14,305,306],{},"検証スクリプトを追加し、DBに投入する前にJSONLを全件チェックするようにした。実際に走らせると、エージェントAとエージェントBで同じ本を取り違えていた重複が3件、タグ過多が12件、交差違反が1件出た。手で直してから投入した。",[18,308,310],{"id":309},"shelf-uiにタグフィルタを追加","shelf UIにタグフィルタを追加",[14,312,313,314,317,318,321],{},"DBに841冊×複数タグが入った。次はビューアでフィルタリングできるようにする。タグAPI（",[26,315,316],{},"/api/shelf/tags","）を新設し、library API（",[26,319,320],{},"/api/shelf/library","）にタグ絞り込みクエリを追加した。",[14,323,324],{},"UIではチップ式のフィルタを置き、複数タグをANDで重ねられるようにした。「簿記2級」かつ「過去問」を選ぶと該当の数冊だけが残る。",[14,326,327,328,331],{},"評価の表示も直した。元のUIは★4.0以上、4.5以上、5.0の3段階表示だったが、★4.0と★4.5が同じ列に並ぶと差が見えづらい。評価ごとに ",[194,329,330],{},"横線で区切り","、★5.0 / ★4.5以上 / ★4.0以上 のセクションを視覚的に分けた。フィルタで絞り込んだときに「全841冊 / 表示489冊」のように両方の数字を出すと、フィルタの強さが直感で分かるようになった。",[18,333,335],{"id":334},"ユーザー要望からコンテンツ軸第3軸を追加","ユーザー要望から「コンテンツ軸」（第3軸）を追加",[14,337,338,339,342],{},"shelf UIをユーザーに見せたら「カテゴリと難易度だけだと、特定のテーマで横断検索ができない」とフィードバックが返ってきた。たとえば「キャッシュフロー計算書」「簿記3級」「Excel」のような",[194,340,341],{},"横断テーマ","は、既存の2軸では拾えない。",[14,344,345],{},"第3軸として「コンテンツ軸」を追加した。緑系のチップで色分けし、既存の2軸（カテゴリ・難易度）と視覚的に区別する。初期セットは要望ベースで6つに絞った。",[280,347,348,351,354,357,360,363,366],{},[283,349,350],{},"キャッシュフロー計算書",[283,352,353],{},"簿記3級",[283,355,356],{},"簿記2級",[283,358,359],{},"Excel",[283,361,362],{},"連結",[283,364,365],{},"決算書を読む",[283,367,368],{},"財務3表",[14,370,371],{},"付与は二段構えにした。まずタイトルマッチで自動付与し、機械的に拾える本を埋める。次にClaudeで全841件を再走査し、タイトルだけでは判定できない本（副題やシリーズで判別する本）を拾い直す。",[14,373,374,375,378],{},"二段構えにした理由は、タイトルマッチだけだと取りこぼしが多いと予想したからだ。実際、自動付与で拾えたのは約50ペアだったが、Claudeの再走査で48ペア追加された。最終的に ",[194,376,377],{},"98ペア / 76冊"," がコンテンツ軸に紐づいた。1冊が複数のコンテンツに属するので、ペア数 > 冊数になる。",[18,380,382],{"id":381},"著者情報の追加取得captchaで再び中断","著者情報の追加取得：CAPTCHAで再び中断",[14,384,385,386,389],{},"shelf UIの一覧で「著者で並べたい」という要望も出た。Amazonページの ",[26,387,388],{},"#bylineInfo"," をスクレイパーに追加し、全841冊の著者を取り直す。",[14,391,392],{},"344件まで取得したところでCAPTCHAに引っかかった。今日はここで打ち切り、明日の朝にリトライする。CAPTCHAは時間帯と頻度の関数で、夜中の連続アクセスで発火しやすい印象がある。朝イチで残り497件を流す予定。",[18,394,395],{"id":395},"振り返り",[14,397,398,399,402,403,402,406,409],{},"今日の作業で効いたのは「",[194,400,401],{},"並列化の前にbaselineを置く","」「",[194,404,405],{},"Codexレビューを2回挟む",[194,407,408],{},"自動付与＋手動レビューの二段構え","」の3つだった。",[14,411,412],{},"並列サブエージェントは速度を稼げる一方、エージェント間の判定ブレを抑える仕組みが要る。baselineを全員に配ることで、出力のばらつきが目で見て減った。",[14,414,415,416,418],{},"Codexレビューはv1で構造の致命傷（キー設計）を、v3で検証ロジックの抜けを指摘してくれた。1回だけだと「直したつもり」で終わるが、2回挟むと「直したことで生まれた新しい穴」が見える。",[26,417,274],{}," で文脈を引き継ぐのが必須。",[14,420,421],{},"自動付与＋手動レビューの二段構えは、コンテンツ軸の精度を実測で2倍にした。タイトルマッチは速いが取りこぼす。Claudeの全件再走査は遅いが文脈で拾う。組み合わせると精度と速度の両取りができる。",[18,423,424],{"id":424},"明日やること",[280,426,429,439,445,451],{"className":427},[428],"contains-task-list",[283,430,433,438],{"className":431},[432],"task-list-item",[434,435],"input",{"disabled":436,"type":437},true,"checkbox"," 著者情報の残り497件を取得し、CAPTCHAが出たら時間を空けて再開する",[283,440,442,444],{"className":441},[432],[434,443],{"disabled":436,"type":437}," shelf UIで著者カラムを追加し、著者名でソートできるようにする",[283,446,448,450],{"className":447},[432],[434,449],{"disabled":436,"type":437}," コンテンツ軸を「税務」「IFRS」「ESG」など要望が来たテーマで拡張する",[283,452,454,456],{"className":453},[432],[434,455],{"disabled":436,"type":437}," 検証スクリプトをCIに組み込み、DBに新規行が入るたびに重複・交差・タグ個数チェックを自動で走らせる",[458,459,460],"style",{},"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 .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}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 .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}",{"title":50,"searchDepth":68,"depth":68,"links":462},[463,464,465,466,467,468,469,470,471,472],{"id":20,"depth":68,"text":21},{"id":140,"depth":68,"text":141},{"id":153,"depth":68,"text":154},{"id":223,"depth":68,"text":224},{"id":237,"depth":68,"text":238},{"id":309,"depth":68,"text":310},{"id":334,"depth":68,"text":335},{"id":381,"depth":68,"text":382},{"id":395,"depth":68,"text":395},{"id":424,"depth":68,"text":424},"diary","Amazonメタ全件取得でcp932エンコードエラーに遭遇しながら、841冊の蔵書をサブエージェント8並列でセミラティス的にタグ付けした。Codexにv1とv3の2回レビューを依頼してキー設計を直し、ユーザー要望からコンテンツ軸（第3軸）を追加。自動付与＋全件再走査の二段構えで98ペアを補正した。","md",{},"/2026-04-29-shelf-semilattice-tagging","book-knowledge-base",false,"2026-04-29T00:00:00.000Z",{"title":5,"description":474},"2026-04/2026-04-29/shelf-semilattice-tagging",[484,485,486,487,488,489],"書籍デジタル化","TursoDB","Vue","Codexレビュー","並列処理","セミラティス",null,"AQWrleFKXLum6Y5c_lZLkWjblGtpYRH2PIjirzO1GLk",[],"https://log.eurekapu.com/favicon.svg",1777533703603]