自社監査: LLMOリファレンスサイト2つで見つかった20件
対象: 同じプレイブック・同じレビュアーで構築された2サイトを併せて監査する。(propel-lab) ラベルは propel-lab.co.jp、(kaoriq) ラベルは kaoriq.com に該当。両サイトに該当する発見もある。
このケーススタディの目的
Section titled “このケーススタディの目的”このサイト上の他のケーススタディは結果を示している — TRM Labs の AI 経由トラフィック +8,337% 成長、Go Fish Digital のコンバージョン25倍。LLMO がうまく実装されたとき何が可能になるかを示すものだ。
このケースは違う。LLMO のインフラを意図的に構築していたとしても、何が間違うかを示す。
Propel-Lab は本フレームワークを運営する会社である。サイトはリファレンス実装として明示的に構築された: JSON-LD 11 スキーマ、llms.txt + llms-full.txt + llms-ja.txt、/ai/ Markdown ディレクトリ、URL.md エンドポイント(/company.md、/products.md)、すべての LLMO 面をアサートする Playwright テスト。外部の評価指標で測れば、サイトは完成して見えていた。
2026年5月の二段監査 — まず実装者本人、次に独立AIエージェント(codex CLI の --sandbox read-only モード)— が20件の独立した問題を発見した。本ケーススタディに記録するのは、第2段が第1段では構造的に見えないパターンを捕捉したためであり、それらのパターンは一般化可能だからである。
監査対象は、同じチームが構築した2つの本番サイト:
- propel-lab.co.jp — 法人サイト、本フレームワークのリファレンス実装
- kaoriq.com — 同じプレイブックで構築された多言語コンテンツサイト(5言語)
各サイトに対して二段レビューを実行:
- 第1段(自己レビュー): 元の開発者と同じセッション内の Claude アシスタントが、ソースコードと
dist/出力を LLMO チェックリストに照合 - 第2段(独立AI): 別プロセスの codex CLI を
--sandbox read-onlyで実行。修正後のリポジトリと構造化された監査プロンプトを与える
発見は重大度(P0 / P1 / P2)でトリアージし、各サイトで2コミット内で修正。両監査パスと修正を含む合計実時間: サイトあたり ~6時間。
第1段で捕捉できた発見(n=11)
Section titled “第1段で捕捉できた発見(n=11)”これらは LLMO チェックリストを知っていれば慎重な自己レビューで発見できる類の問題:
| # | サイト | 発見 | 第1段で捕捉できた理由 |
|---|---|---|---|
| 1 | kaoriq | OG画像のフォールバックが本番で404 | OG URLに curl -I すれば見える |
| 2 | kaoriq | ブログ記事で og:type が二重出力(website + article) | view-source で発見可能 |
| 3 | kaoriq | 内部ブログリンクで末尾スラッシュ抜け → 301リダイレクト | ]( /blog/ のパターンを grep すれば明白 |
| 4 | kaoriq | 静的ページに hreflang 宣言なし | ページタイプ間で meta ブロックを比較すれば露見 |
| 5 | kaoriq | JSON-LD BlogPosting に image / dateModified / publisher.logo が欠落 | Schema.org チェックリスト |
| 6 | propel-lab | 英語ページでも Header/Footer が日本語ハードコード | /en/ を訪問すれば即座に見える |
| 7 | kaoriq | Coming Soon カードがリンク無し | UX レビュー |
| 8 | kaoriq | 空の public/ai/ ディレクトリがデプロイ | ファイルシステム検査 |
| 9 | kaoriq | llms.txt がサポート5言語のうち2言語のみ記載 | llms.txt と実際の /blog/ ディレクトリの比較 |
| 10 | kaoriq | Nav 言語スイッチャーが翻訳のないページでも常に6言語表示 | クリックテストで dead-end が露見 |
| 11 | kaoriq | PT/ES 翻訳コンテンツの字音記号脱落(não → nao、você → voce) | ネイティブ話者レビュー |
パターン: これらは正しい場所を見れば露見する発見である。レビュアーは見ればよい。
第2段で捕捉された発見(n=9)
Section titled “第2段で捕捉された発見(n=9)”これらは実装者のメンタルモデルを破壊した発見である:
F12. <slot name="head" /> の欠落による silent JSON-LD drop (propel-lab)
Section titled “F12. <slot name="head" /> の欠落による silent JSON-LD drop (propel-lab)”Astro レイアウトの <head> 内に <slot name="head" /> 宣言が無かった。ページ別スキーマのために <script slot="head" type="application/ld+json"> を書いたページは、警告無くドロップされていた — フレームワークがスクリプトを破棄しても何も知らせない。
サイトはこの状態で数ヶ月デプロイされていた。実装者はソースにスキーマを書いていた。スキーマは dist/ HTML に届いていなかった。実装者は「JSON-LDを追加した」と満足していた。実装は: それは出力されていなかった、と告げた。
LLMO の教訓: 出力検証は独立したフレームワーク上の関心事である。JSON-LDを「書く」ことと「出力する」ことは別の事象だ。ビルドパイプラインは、リリースごとに、すべてのJSON-LDブロックが配信されるHTMLに到達することを検証しなければならない。
F13. 住所が矛盾する2つの Organization エンティティ (propel-lab)
Section titled “F13. 住所が矛盾する2つの Organization エンティティ (propel-lab)”共通レイアウトが住所「天神4丁目6-28 天神ファーストビル7階」の Organization を出力していた。ページ別スニペット(レイアウトを上書きする意図だったが、そう書かれていなかった)が「天神4-6-28 天神第一ビル7F」の2つ目の Organization を追加 — 同じビルだが転記が違う。両方が HTML に残った。
@id のない同じエンティティに対する2つの矛盾した住所文字列を、クローラはパースする。一部のAIリランカーは構造化データの自己整合性を明示的に確認する。ここでの矛盾は信頼度を下げる。
LLMO の教訓: エンティティ重複宣言は構造の問題ではなく整合性の問題である。各宣言が個々に well-formed であるため JSON-LD バリデータでは捕捉できない。修正は、すべての主要エンティティに安定した @id 値を割り当て、他のすべての場所で @id 参照を使うこと。
F14. ファイル間の数値ドリフト(4冊 vs 14冊) (propel-lab)
Section titled “F14. ファイル間の数値ドリフト(4冊 vs 14冊) (propel-lab)”著者プロフィールが以下を主張していた:
- 4冊、Qiita 39,000+ PV(
/ai/founder.md、llms-full.txt) - 14冊、Qiita 80,000+ PV(トップページの Profile コンポーネント)
両方の面が AI クローラに配信されていた。/ai/founder.md を引用するAIは古い数値を返し、HTMLを引用するAIは現在の数値を返した。Person JSON-LD には数値統計が含まれておらず、矛盾解決の助けにならなかった。
LLMO の教訓: 整合性シグナルは実在する。すべての数値・事実主張に対して、単一の正規ソースファイルが必要である。すべての面(HTML、Markdown、JSON-LD、llms.txt)はそこから生成される。
F15. 全ページへのJSON-LD過剰注入 (propel-lab)
Section titled “F15. 全ページへのJSON-LD過剰注入 (propel-lab)”共通レイアウトはすべてのページに11スキーマを出力していた — Organization、Person、Service[] (×7)、MusicGroup、Book[] (×2)、FAQPage、WebSite。404 ページは音楽プロジェクトを広告していた。プライバシーページはすべての書籍を広告していた。/products と /yureru ページはそれぞれ無関係なエンティティを抱えていた。
これらをパースするモデルは、ページ主題に関するページ関連の主張として読む。404ページに MusicGroup を載せることは、404ページが音楽について書かれているとLLMにヒントを送る — 望む結果ではない。
LLMO の教訓: 構造化フォーマットにはスコープが必要である、単に「存在」するだけではダメだ。サイト全体エンティティは Organization / WebSite / Person。ページ別エンティティ(Service[]、Book[]、MusicGroup、FAQPage)はそれらが実際に主題となるページに属する。
F16. 英語ページでも og:locale が ja_JP に固定 (propel-lab)
Section titled “F16. 英語ページでも og:locale が ja_JP に固定 (propel-lab)”/en/ ページが og:locale = ja_JP を宣言していた。レイアウトがハードコードしていたためだ。OG メタデータを言語検出に使うソーシャルプラットフォームと AI 統合は、英語の読者に配信する際に日本語ページを見ていた。
LLMO の教訓: OG メタデータは多言語 LLMO の一部である。言語シグナルはエンドツーエンドで lang-aware であるべきだ: HTML lang、JSON-LD inLanguage、OG og:locale、hreflang、content-language ヘッダ。
F17. /ai/ ファイルで www. と apex ドメインの混在 (propel-lab)
Section titled “F17. /ai/ ファイルで www. と apex ドメインの混在 (propel-lab)”正規ドメインは https://propel-lab.co.jp だった。5つの /ai/*.md ファイルが代わりに https://www.propel-lab.co.jp を参照していた。これらの Markdown 面をクロールする AI エージェントは非正規 URL を受け取り、301 を追う(コスト)か、別エンティティとして扱う(より悪い)。
LLMO の教訓: 正規ドメインの徹底はHTMLのみの関心事ではない。すべての Markdown 面、すべての llms.txt リンク、すべての内部参照URLが同じ正規ホストを使う必要がある。
F18. 404ページの canonical が /404.html ではなく /404/ を指していた (両サイト)
Section titled “F18. 404ページの canonical が /404.html ではなく /404/ を指していた (両サイト)”Astroが(GitHub Pagesの慣習に従って)dist/404.html を生成していた。ページは og:url = https://propel-lab.co.jp/404/ を出力していた — Astroが推論したルートのため。GitHub Pages はあらゆる404 で 404.html を直接配信する。/404/ URLは実際には404ページを返さない。
結果: 共有された404 URLが誤った先を指す。canonical 宣言は内部的に整合していたが、デプロイメントと一致していなかった。
LLMO の教訓: canonical URL はフレームワークが推論するものではなく、ホストが配信するものに一致させる必要がある。404ページに関しては、解決しない URL を宣言するより canonical と OG を完全に抑制する方がクリーンだ。
F19. 不正なHTML出力(<table> 内の <a> adoption-agency バグ) (propel-lab)
Section titled “F19. 不正なHTML出力(<table> 内の <a> adoption-agency バグ) (propel-lab)”<dt> 風の会社情報テーブルが最後の <td> 内で <a> を使っていた。Astroの HTML 出力が空の <a></a> プラス次のセクション全体を wrap する開いた <a> を生成 — ブラウザ(とクローラ)が異なるやり方で auto-correct する不正なHTML。空のアンカーと wrap するアンカーの両方が mailto:info@propel-lab.co.jp を指していた。
修正は構造化された key/value レイアウトを <table> から <dl> へ切り替えること。バグは再現しなくなった。
LLMO の教訓: 出力検証は JSON-LD 以外のHTMLでも重要である。dist/ の不正なマークアップは AI クローラに到達する — そして、各クローラがどう修正するかは非決定的だ。少なくともメジャーリリース時点で、実配信HTMLを W3C バリデータに当てる。
F20. EN下層が無いサブページから /en/ を hreflang alternate と宣言 (propel-lab)
Section titled “F20. EN下層が無いサブページから /en/ を hreflang alternate と宣言 (propel-lab)”日本語の /company/、/products/、/yureru/ ページが hreflang="en" href="https://propel-lab.co.jp/en/" を宣言していた。しかし /en/ は英語サイト全体を集約した1ページ — 英語の company ページでも、英語の products ページでも、英語の yureru ページでもない。hreflang は4対1の等価性を主張していたが、それは事実ではなかった。
LLMO の教訓: hreflang はコンテンツ等価性に関する精度の高い主張である。サブページから汎用ランディングページへ hreflang en を宣言するのは技術的に誤用であり、多言語シグナルを劣化させる。クリーンな解: hreflang は真の代替を持つページにのみ宣言、それ以外では抑制する。
発見が LLMO 実践について語ること
Section titled “発見が LLMO 実践について語ること”第2段の発見セットから3つのパターンが現れる:
-
silent failure が支配する。第1段のレビューは可視症状(壊れた画像、誤った言語)を生む問題を捕捉した。第2段が捕えたのはシステムは正常に動くが LLMO の結果は誤っている問題: スキーマが silently drop されている、本来1つであるべきエンティティが2つ存在する、数値がファイル間でドリフトする。症状は AI 引用品質においてのみ現れる — 数ヶ月後に、現れるかどうかも分からない
-
整合性は独立した問題クラスである。第2段の発見の半数近くが同じ事実が2箇所で異なって現れていることに関する。既存の LLMO フレームワークはこれを Authority や Structural Formatting の暗黙の一部として扱う。我々は整合性シグナルをフレームワークの第6コンポーネントとして明示的に追加した
-
リファレンス実装も他と同じバグを抱える。サイトはLLMOを教える人々によって構築された。それでもこれらの問題でリリースされた。LLMOの実装と監査は別物であり、異なる注意モードを必要とする。監査ステップこそ、ほとんどのチームがスキップする部分だ
両サイトの修正後、第2段レビューは P0 と P1 の発見についてクリーンに再走行した。P2 項目(Google Fonts セルフホスト、EN サブページの拡張カバレッジ)は緊急ではないバックログとして残っている。
合計コミット: kaoriq に4コミット、propel-lab-website に2コミット。差分: ~600行追加、~550行削除(ほとんどがスキーマスコープのリファクタとデータ重複排除)。コンテンツの削除はゼロ。一部のコンテンツが単一ソースファイルに合理化された。
持ち帰るもの
Section titled “持ち帰るもの”自分の LLMO 実装を監査するなら:
- そもそも監査をやる。実装ステップは監査ステップではない。別途レビューをスケジュールする
- 二段構造を使う: まず自分、次に read-only モードの独立エージェント。運用詳細は LLMO監査: 二段レビュー を参照
- ソースだけでなく
dist/を見る。LLMO を傷つけるバグは意図と出力のギャップに住む - クロスファイルのドリフトを明示的に検索する。数値、住所、日付、カタログ — 複数回現れる事実主張はすべて divergence の候補だ
- スキーマスコープを検証する。共通レイアウトが
Organization/WebSite/Person以外を出力しているなら、ページ別エンティティは恐らく無関係なページに漏れている
発見、修正、判断の全セットは propel-lab-website と kaoriq リポジトリの2026年5月8日のコミット履歴に記録されている。
- LLMO監査: 二段レビュー — 方法論
- 整合性シグナル — 本監査で最も多く違反が検出されたフレームワーク原則
- 構造化フォーマット — JSON-LD のスコープと出力検証