コンテンツにスキップ

自社監査: LLMOリファレンスサイト2つで見つかった20件

対象: 同じプレイブック・同じレビュアーで構築された2サイトを併せて監査する。(propel-lab) ラベルは propel-lab.co.jp(kaoriq) ラベルは kaoriq.com に該当。両サイトに該当する発見もある。

このサイト上の他のケーススタディは結果を示している — 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. 第1段(自己レビュー): 元の開発者と同じセッション内の Claude アシスタントが、ソースコードと dist/ 出力を LLMO チェックリストに照合
  2. 第2段(独立AI): 別プロセスの codex CLI を --sandbox read-only で実行。修正後のリポジトリと構造化された監査プロンプトを与える

発見は重大度(P0 / P1 / P2)でトリアージし、各サイトで2コミット内で修正。両監査パスと修正を含む合計実時間: サイトあたり ~6時間。

これらは LLMO チェックリストを知っていれば慎重な自己レビューで発見できる類の問題:

#サイト発見第1段で捕捉できた理由
1kaoriqOG画像のフォールバックが本番で404OG URLに curl -I すれば見える
2kaoriqブログ記事で og:type が二重出力(website + article)view-source で発見可能
3kaoriq内部ブログリンクで末尾スラッシュ抜け → 301リダイレクト]( /blog/ のパターンを grep すれば明白
4kaoriq静的ページに hreflang 宣言なしページタイプ間で meta ブロックを比較すれば露見
5kaoriqJSON-LD BlogPostingimage / dateModified / publisher.logo が欠落Schema.org チェックリスト
6propel-lab英語ページでも Header/Footer が日本語ハードコード/en/ を訪問すれば即座に見える
7kaoriqComing Soon カードがリンク無しUX レビュー
8kaoriq空の public/ai/ ディレクトリがデプロイファイルシステム検査
9kaoriqllms.txt がサポート5言語のうち2言語のみ記載llms.txt と実際の /blog/ ディレクトリの比較
10kaoriqNav 言語スイッチャーが翻訳のないページでも常に6言語表示クリックテストで dead-end が露見
11kaoriqPT/ES 翻訳コンテンツの字音記号脱落(não → nao、você → voce)ネイティブ話者レビュー

パターン: これらは正しい場所を見れば露見する発見である。レビュアーは見ればよい。

これらは実装者のメンタルモデルを破壊した発見である:

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.mdllms-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スキーマを出力していた — OrganizationPersonService[] (×7)、MusicGroupBook[] (×2)、FAQPageWebSite。404 ページは音楽プロジェクトを広告していた。プライバシーページはすべての書籍を広告していた。/products と /yureru ページはそれぞれ無関係なエンティティを抱えていた。

これらをパースするモデルは、ページ主題に関するページ関連の主張として読む。404ページに MusicGroup を載せることは、404ページが音楽について書かれているとLLMにヒントを送る — 望む結果ではない。

LLMO の教訓: 構造化フォーマットにはスコープが必要である、単に「存在」するだけではダメだ。サイト全体エンティティは Organization / WebSite / Person。ページ別エンティティ(Service[]Book[]MusicGroupFAQPage)はそれらが実際に主題となるページに属する。

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つのパターンが現れる:

  1. silent failure が支配する。第1段のレビューは可視症状(壊れた画像、誤った言語)を生む問題を捕捉した。第2段が捕えたのはシステムは正常に動くが LLMO の結果は誤っている問題: スキーマが silently drop されている、本来1つであるべきエンティティが2つ存在する、数値がファイル間でドリフトする。症状は AI 引用品質においてのみ現れる — 数ヶ月後に、現れるかどうかも分からない

  2. 整合性は独立した問題クラスである。第2段の発見の半数近くが同じ事実が2箇所で異なって現れていることに関する。既存の LLMO フレームワークはこれを Authority や Structural Formatting の暗黙の一部として扱う。我々は整合性シグナルをフレームワークの第6コンポーネントとして明示的に追加した

  3. リファレンス実装も他と同じバグを抱える。サイトはLLMOを教える人々によって構築された。それでもこれらの問題でリリースされた。LLMOの実装と監査は別物であり、異なる注意モードを必要とする。監査ステップこそ、ほとんどのチームがスキップする部分だ

両サイトの修正後、第2段レビューは P0 と P1 の発見についてクリーンに再走行した。P2 項目(Google Fonts セルフホスト、EN サブページの拡張カバレッジ)は緊急ではないバックログとして残っている。

合計コミット: kaoriq に4コミット、propel-lab-website に2コミット。差分: ~600行追加、~550行削除(ほとんどがスキーマスコープのリファクタとデータ重複排除)。コンテンツの削除はゼロ。一部のコンテンツが単一ソースファイルに合理化された。

自分の LLMO 実装を監査するなら:

  1. そもそも監査をやる。実装ステップは監査ステップではない。別途レビューをスケジュールする
  2. 二段構造を使う: まず自分、次に read-only モードの独立エージェント。運用詳細は LLMO監査: 二段レビュー を参照
  3. ソースだけでなく dist/ を見る。LLMO を傷つけるバグは意図と出力のギャップに住む
  4. クロスファイルのドリフトを明示的に検索する。数値、住所、日付、カタログ — 複数回現れる事実主張はすべて divergence の候補だ
  5. スキーマスコープを検証する。共通レイアウトが Organization / WebSite / Person 以外を出力しているなら、ページ別エンティティは恐らく無関係なページに漏れている

発見、修正、判断の全セットは propel-lab-websitekaoriq リポジトリの2026年5月8日のコミット履歴に記録されている。