ADR-015: 書籍・漫画のmetadata正本をアプリから分離する

決定日: 2026-08-19 状態: 採用

背景

Grimmoryは、蔵書の検索・閲覧と読書状態を日常的に扱うUIとして受け入れた。Koboの取得経路や既存蔵書の整理も進み、実用上の土台はできている。

一方で、書誌、分類、所有・取得意図までGrimmory内部だけへ置くと、将来別のアプリへ移るときに、現在の分類や判断を再構築しなければならない。逆に、Grimmoryの便利なUIを避けて独自UIを先に作ると、管理対象と日常の手間が増える。

守りたい中心は、あなたの言葉では次の通り。

内部の形式を意識せず、かつ特定のアプリにロックインしないメディア管理にする

この原則はメディア全体へ広げられるものとして持つ。ただし今回の実装対象は書籍と漫画に限定する。

決定

正本を項目ごとに分ける

  • portableな書誌、identity、分類、所有、取得意図は、中央の人間可読JSON treeを正本にする。
  • JSONは直接編集を正式な操作経路にせず、schema検証を行うstrict CLIから更新する。
  • 電子ファイル隣接sidecarは必要なconsumer向けに生成できるようにするが、正本にはしない。
  • catalog本体のために新しいGit運用は増やさない。portable tree、追記型journal、既存backupで履歴と復旧境界を持つ。
  • Grimmoryはliveの読書状態と日常UIを担う。Grimmoryが保持する読書status、読了日、rating、進捗、bookmarkはportable catalogへ常時同期しない。
  • 読書メモは今回の決定対象外とし、このcatalogへ重複させない。正本は別途見直す。

Grimmoryはprojectionとして使う

  • portable metadataからGrimmoryの書誌、tag、Shelf、Magic Shelfへ投影する。
  • Grimmory UIでportable fieldが変更された場合は自動採用も自動上書きもしない。driftとして示し、明示的にportable側へ採用するか、Grimmoryを戻す。
  • live運用中は既存Grimmory Book IDを守る。空instanceからの再構築では、portable identityと内容が一致すればGrimmory IDの変更を許す。
  • 最初に現行Grimmory全件をportable treeへbootstrapする。正本切替前に、隔離した空のGrimmoryを原本+portable treeから再構築し、portable fieldを全件比較する。

欲しい本、所有本、読書状態を混ぜない

  • 「欲しい本」は購入・取得wishlistであり、読書queueや読書状態とは別にする。
  • 欲しい意図はwork単位でも登録できる。購入時に実際のeditionとformatへ解決する。
  • 取得後も元の意図をfulfilledとして残し、所有したeditionへリンクする。
  • 物理本のidentityがtitleしか分からない場合もGrimmoryへ登録できる。ただしportable側ではprovisionalとして保持し、解決までは「未整理」projectionに隔離する。

分類は一つの入口と複数facetに分ける

  • 一冊につき主分類を一つ持つ。重なりはsubject、format、audienceなどのfacetで表現する。
  • 初期の主分類は comicnovelpracticaltextbookmagazineother とする。
  • textbookは順番に学ぶ教材・演習本、practicalはそれ以外の技術・実用・一般ノンフィクションとする。
  • periodicalであることを優先し、漫画雑誌や技術雑誌もmagazineにする。
  • 決定論的ruleを主経路にし、LLMはfallbackに限定する。低確信だけ確認待ちにし、一度の判断を将来のruleへ反映する。検証されたruleだけを段階的に自動承認へ昇格する。
  • 最初のUIはGrimmoryのMagic Shelfとtag projectionで作る。実利用が悪いと確認できた場合だけ、portable treeを直接読む別UIを検討する。

外部metadataはidentityとprovenanceを先にする

  • ISBNなど強いIDが完全一致した場合だけ、自動enrichmentを許す。
  • 空欄補完と安全な表記正規化は自動反映できる。意味の衝突は候補として人間へ戻す。
  • 書影はexact ISBNに結びつく使用可能な画像を先に採用し、より良い画像は後から候補化する。
  • 新規登録時とidentity解決時は自動enrichmentを試す。catalog全体の再取得は明示commandにし、schedulerは必要性が見えてから検討する。

Hermesは自然言語の入口にする

  • 実処理の正本は独立した決定論的CLI/APIに置く。Hermesへ書籍固有のmutation logicを閉じ込めない。
  • 既存Kobo pipelineはprovider adapterとして温存し、その上に統一CLIを置く。
  • 最初はHermes skillからstrict CLIを呼ぶ。typed toolとしての価値が明確になったらMCP化を検討する。
  • 明確な命令はbounded approvalとして扱い、安全かつ一意な変更は工程ごとの再確認なしで完了する。identity衝突、意味の衝突、bulk scopeの曖昧さ、driftはfail closedにする。

理由

  • アプリを変えても書誌・分類・取得意図を再構築せずに済む。
  • 日常操作ではJSONや内部schemaを意識せず、GrimmoryとHermesの使いやすい入口を利用できる。
  • Koboなど既存の安全なpipelineを捨てず、provider固有処理と共通catalog操作を分離できる。
  • 読書中に頻繁に変わる状態まで二重管理せず、portableにする価値が高い情報へ絞れる。
  • 主分類とfacetを分けることで、安定した入口と横断検索を両立できる。

トレードオフ

  • portable treeとGrimmoryの間にprojection・drift検出が必要になる。
  • JSONを人間可読にしても、正式な更新をCLIへ限定するため、手編集の手軽さは取らない。
  • 読書状態はGrimmory依存として残る。完全なアプリ非依存ではなく、移行価値の高いmetadataから分離する判断になる。
  • title-onlyの即時登録は便利だが、provisional cohortを解消する運用が必要になる。
  • 一つの主分類はUIを安定させる一方、境界事例では人間判断またはrule改善が必要になる。

見直し条件

  • 隔離rebuildでportable fieldを全件再現できない。
  • projectionとdrift処理の負担が、Grimmory依存を受け入れる負担を継続的に上回る。
  • Magic Shelfとtag projectionでは、主分類のUIとして実用にならない。
  • 読書状態やannotationもアプリ間で移す必要が生まれる。
  • 書籍・漫画以外のメディアへ広げる際、今回のwork・edition・holding modelが適合しない。

関連