AI クローラーは HTML を読むのであって、あなたの Markdown 下書きを読むのではない。シャドウドキュメントの目標が「AI に正しく理解され引用される」ことであるなら、出力形式は Schema.org の意味論を備えた HTML であるべきであり、しかも顧客公式サイトの実コンテンツをミラーできるときは、決してゼロから書き直してはならない。
初期の AXP(参照:第 6 章 — AXP シャドウドキュメント)は各 page_type について LLM で Markdown を生成し、フロントエンドのレンダリング時に HTML へ変換していた。この設計は規模化後に 3 つの限界を露呈した:
/pricing や /faq があるのに、プラットフォームが LLM で書き直せば、かえって最も権威ある一次コンテンツを放棄することになる。<h2><p><ul> のフラットな構造であり、Schema.org microdata を欠くため、AI クローラーは「この段落は製品、この段落は FAQ」を判別しにくい。進化の方向は一つの総原則によって定礎された(ユーザーによる定礎):HTML 化できる旧ドキュメントも将来の新ドキュメントも、すべて HTML に切り替える。そして「HTML 化できる」ものの最良の供給源は、顧客公式サイト自身がすでに書き上げたその一枚である。
22+1 個の page_type の AXP ドキュメントは統一して意味論的 HTML fragment を通り、もはや二重路線を併存させない。content_md は archive カラムへ降格する。
一つ明確な境界がある:クローラー規約ドキュメントはこの原則の対象外である。sitemap.xml、robots.txt、llms.txt、schema.json など 12 個の endpoint は RFC / IANA / Google spec によってその原フォーマット(XML / plain text / JSON-LD)が強制されており、HTML に変えてはならない。Mirror-First は「AI に読ませるコンテンツページ」にのみ作用し、「AI にコンテンツを発見させるプロトコルファイル」には作用しない。
単一出口の利点は、フロントエンドにレンダリング経路が一つしかないことである:<article data-axp-source> が backend で sanitize 済みの HTML を包む。dangerouslySetInnerHTML はここでは安全である — なぜなら危険は backend の allowlist 段階ですでに除去されているからである(18.4 参照)。
各 page_type の HTML は 2 段階で決定され、origin のミラーを優先し、LLM へフォールバックする:
flowchart TD
A[generatePageHtml brand, pageType] --> B{Step 1: tryOriginMirror}
B -->|PAGE_TYPE_ORIGIN_PATHS で候補 path を検索| C[brand_content_pages substring match]
C -->|ヒット| D[isPublicHttpUrl SSRF ガード]
D --> E[fetch + main/article を抽出し nav/footer を除去]
E --> F[htmlSanitizer allowlist]
F --> G[enrichWithSchema で article itemtype を付与]
G --> H[content_source = mirror + mirror_origin_url]
B -->|origin に該当ページなし| I[Step 2: markdownToHtml fallback]
I --> J[LLM Markdown -> marked GFM で HTML 変換 LLM コストなし]
J --> K[enrichWithSchema で article を付与]
K --> L[content_source = llm]
Fig 18-1:AXP HTML 生成の 2 段階。Step 1 は顧客 origin の実ページをミラーし、Step 2 でようやく LLM markdown 変換へフォールバックする。
PAGE_TYPE_ORIGIN_PATHS は一組の SSOT 対照表であり、page_type を顧客公式サイトに存在しうるパス(pricing → /pricing、faq → /faq、overview → /about など)へマッピングする。パイプラインは brand_content_pages(公式サイト URL インデックス、参照:第 6 章)で substring 照合を行い、短い URL を優先する。ヒット後は origin HTML を取得し、<main> / <article> 本体を抽出(nav / footer を除去)、sanitizer を通し、Schema.org で包む。この経路が生成するコンテンツは content_source='mirror' となり mirror_origin_url を記録する。
プラットフォーム鉄則に沿う制約が一つある:PAGE_TYPE_ORIGIN_PATHS は顧客 origin に実在するパス種別のみを列挙でき、SEO のために顧客が持たない URL を捏造してはならない(「公開ファイル生成原則」に対応)。
origin に該当ページがない場合、LLM が生成した Markdown へフォールバックし、marked(GFM)で HTML へ変換する — このステップはLLM コストがない、単なるプログラム的変換である(Markdown はすでにパイプラインが生成し content_md に保存済み)。同様に enrichWithSchema を通し、content_source='llm' となる。
公式サイトを持つブランドでの実測では Mirror のヒット率は約 60〜80% である。すなわち大半の page_type は顧客の一次コンテンツをミラーでき、顧客公式サイトに確かに存在しないページ(競合比較、AXP 専用の派生ページなど)のみが LLM を通る。
外部 origin HTML をミラーすることは危険な操作であり、2 つのガードが必須である:
Mirror は顧客が提供する origin URL を fetch する必要があり、server-side でユーザー提供 URL を fetch する処理はすべて事前に isPublicHttpUrl を通さなければならない(ipaddr.js で RFC1918 プライベート網 / loopback / link-local / クラウド metadata IP をブロックし、DNS rebinding のシナリオでは IP を pin し、redirect 後に再検証する)。これはプラットフォームの SSRF カバレッジ鉄則であり、websiteCrawler / diagnose などすべての対外 fetch と同一の SSOT を共用する。
抽出した origin HTML は一層のallowlist sanitizer を通し、約 30 個の意味論的タグ + Schema.org microdata + ld+json のみを残す:
| 許可 | 禁止 |
|---|---|
h1–h6、p、ul/ol/li、table、article、section、img、picture/source |
script(ld+json 以外)、iframe、video、form |
Schema.org itemtype / itemprop microdata、<script type="application/ld+json"> |
inline style、onclick などのイベント属性、data: URI、javascript: |
OWASP HTML5 Security の allowlist の考え方に沿う — 「既知の危険を除去する」のではなく「既知の安全のみを残す」。<iframe> / <video> が禁止される理由は 第 13 章 — マルチモーダル GEO を参照:動画は inline 埋め込みを通らず、独立した VideoObject schema と sitemap video extension を通ることで、XSS 防御とマルチモーダル可視性を両立する。
enrichWithSchema はコンテンツを <article itemtype="https://schema.org/{schemaType}"> に包み、プレーンテキストを抽出して Schema.org Article.articleBody に埋め込む(Google Article 構造化データ規範に沿い、AI がタイトルだけでなく全文を取得できるようにする)。
ここにはプラットフォームが繰り返し踏んできた一貫性の落とし穴がある:AXP の Schema には2 つの並行レンダリング経路があり、どちらか一方の修正を漏らせば乖離する:
| 経路 | 対象 | ファイル |
|---|---|---|
| Path A — 公開ファイル | /c/{slug}/schema.json、一般クエリ |
generators/schemaJson.js |
| Path B — AXP renderer 埋め込み | AI bot が見るページ HTML の <script> |
activeStrategy/schemaGenerator.js |
鉄則:Article.articleBody / Organization フィールド / 画像 metadata のいかなる変更も、2 つの経路を必ず同時に変更しなければならない(参照:第 16 章 の SSOT 論述)。過去に Path A のみを変更した結果、公開クエリは正しいが AI bot が見る埋め込み schema に articleBody が欠ける、という事態が生じた。
axp_pages テーブルに 4 カラムを追加してこの仕組みを支える:
ALTER TABLE axp_pages
ADD COLUMN content_html TEXT,
ADD COLUMN content_source TEXT CHECK (content_source IN ('mirror','llm','manual')),
ADD COLUMN mirror_origin_url TEXT,
ADD COLUMN mirrored_at TIMESTAMPTZ;
3 つの付随機構:
content_md を純粋な marked 変換でバッチ的に content_html へ埋める(idempotent、LLM なし)、5000+ row で約 30 秒。ある DB trigger が空文字列の content_md を自動的に NULL へ設定し、「md はあるが html がない」という仕様違反を防ぐ。content_html 書き込み経路(hybridCoordinator / axpPageWriter)が axpUpsertLock(Redis SET NX EX 60、first-writer-wins)を共用し、LLM temperature に起因する高頻度の書き直しを防ぐ(かつて 12 秒で 56 バージョンを書き込む事例を実測)。content_source='mirror' のページについて origin を再取得して content_html を更新し(per-brand で 5 分の stagger)、完了後に L1/L3 キャッシュを能動的にクリアする(参照:第 19 章 — キャッシュ無効化の 5 層アーキテクチャ)。articleBody はプレーンテキストを抽出し、表 / リスト構造を失う。構造は HTML の <article> 本体に依然保持され、Schema は要約インデックスとしてのみ用いる。Mirror-First の核心的価値:「プラットフォームによるゼロからの生成」を fallback へ降格し、「顧客公式サイトの一次コンテンツ + Schema.org による付加価値」を主経路へ昇格する — AXP を「AI が読める書き直し版」から「AI が読める、公式サイトに忠実で、構造化された権威版」へと変える。
isPublicHttpUrl SSRF ガード + htmlSanitizer allowlist(約 30 個の意味論的タグのみを残し、script/iframe/video/inline style を禁止)。Article.articleBody は Path A 公開ファイルと Path B AXP renderer の 2 経路で同期する必要があり、さもなくば AI bot と公開クエリが乖離する。| 日付 | バージョン | 説明 |
|---|---|---|
| 2026-07-06 | v1.2 | 初稿。Mirror-First の 2 段階パイプライン、sanitizer allowlist、二重 Schema 同期、データモデルと resync cron を記録。 |
ナビゲーション:← 第 17 章: 中国クロスボーダー GEO · 📖 目次 · 第 19 章: キャッシュ無効化の 5 層アーキテクチャ →