GEO スコアが反映するのは「AI 認識におけるブランドの状態」であって、「データパイプラインの健全性」ではない。両者を混同すれば、スコアはその本来の意味を失う。
外部 AI サービスに依存するシステムは、いかなる時点でも部分的または全面的な失敗に遭遇しうる。失敗の原因は多岐にわたる:
これらの失敗はエンジニアリング上の日常イベントであって「異常例外」ではない。問題は:これらの失敗がスキャンパイプラインで発生したとき、GEO スコアを汚染させてはならないことである。
シナリオを想像されたい。ブランド X の Citation Rate は過去 30 日間安定して 55 点を維持している。ある日未明、X をスキャンする 6 つの AI プラットフォームのうち 3 つが同時に失敗する。もし「失敗即 0」で当日のスコアに組み入れれば、X は 55 点から 27.5 点に落ちる。ユーザーはダッシュボードを見て「ブランドが急に失寵した」と誤認しパニックに陥る。だが実際には AI の X への認識は一切変わっていない——変わったのはデータパイプラインだけである。
これが第一の誤りである:パイプライン障害をブランド変化と取り違える。
上記問題への第一反応は通常以下の 3 種のいずれかである。3 つすべてに問題がある。
発想:成功したプラットフォームだけを計算に入れ、失敗はスキップする。
問題:分母の変動がスコアを鋸歯状に震動させる。今日は 10 プラットフォーム全成功でスコア 60、明日は 6 つ成功でスコア 62(たまたま失敗したのが低スコアのプラットフォームだった)、明後日は再び 10 全成功でスコア 60 に戻る。トレンド図は完全に読めなくなり、ユーザーは「本当に改善したのか分母が変わっただけか」を判断できない。
発想:失敗プラットフォームの当日スコアを 0 に記録し、分母を安定させる。
問題:これはアルゴリズムに「このブランドは今日このプラットフォームに完全に存在しない」と告げることになるが、実態は「今日の状態を我々は知らない」である。「言及されなかった」と「スキャンできなかった」は根本的に異なる状態であり、混同すれば後続のトレンド分析・ハルシネーション検出・競合比較がすべて狂う。
発想:スキャン失敗時はこの時間帯を存在しなかったものとする。
問題:時系列データベースに断層が発生し、「週末でスキャンなし」「スキャン失敗」「スキャンしたが変化なし」の 3 状態を区別できなくなる。後付けのロジックでカバーするコストは高く、保守性も低い。
3 つの解は共通の根本問題を抱える:いずれも「データ欠損」と「データゼロ」という根本的に異なる状態を区別していない。
我々の採用する方式は履歴から直近の成功値をキャリーフォワードし、明示的に「停滞」フラグを立てることである:
%%{init: {'theme':'base'}}%%
xychart-beta
title "Score under Mid-Scan Platform Outage (Illustrative)"
x-axis ["Day 1", "Day 2", "Day 3 (outage)", "Day 4", "Day 5"]
y-axis "GEO Score" 0 --> 80
line [55, 56, 27, 28, 56]
line [55, 56, 55, 55, 56]
図 4-1:上の折れ線 = 案 B「失敗即 0」による偽暴落。下の折れ線 = Stale Carry-Forward が連続性を維持し、UI 上で isStale を明示する。
isStale = truelastSuccessAt = <historical_timestamp>stateDiagram-v2
[*] --> Fresh
Fresh --> Stale: 当日スキャン 100% 失敗
Stale --> Fresh: 次回スキャン成功
Stale --> Expired: 停滞が閾値超(例:72h)
Expired --> Fresh: スキャン成功
Expired --> Reset: 30 日経っても未回復
Reset --> Fresh: ベースライン再構築
図 4-2:Fresh → Stale は通常の回復パス、Expired と Reset は例外処理で長期障害シーンのために予約されている。
理由:稀な状況で期限切れデータを引用するのを避けるため。あるプラットフォームが長期にわたり応答しない場合、最も古い履歴は数ヶ月前まで遡りうる。その時点のスコアは現在のブランド状態と乖離している。200 行(毎日スキャンなら約 6〜7 ヶ月)をソフト上限として、「連続性の維持」と「データの関連性保持」の間で均衡を取る。上限を超えればキャリーフォワードせず null を記録し、UI に「データ再構築待ち」を明示する。
戦略:初回スキャンのブランドがプラットフォーム失敗に遭遇した場合、キャリーフォワードしない。履歴ベースラインがないから、0 や平均を強引に持ち込むのは偽データになる。フロント側は「初回スキャン — データ構築中」を表示し、「履歴不在」と「履歴あるが停滞」を明確に区別する。
Phase ベースラインテスト(第 10 章)は独立したデータ経路を歩み、Stale Carry-Forward の影響を受けない。ベースラインテストの目的は縦断的な真の変化を追跡することにあり、いかなるキャリーフォワードもこの目的を汚染する。ベースラインテストがプラットフォーム失敗に遭えば、その Phase 結果は直接 status = incomplete とマークし、回復後に再実行する。
Stale マーク自体は警告ではない。しかし同一プラットフォームが 72 時間を超えて停滞したら、システムは通知をエスカレートする:
7 日を超えても未回復なら、さらに Expired 状態に進み、UI で「データ期限切れ、現採点には含めず」を明示、同時にキャリーフォワードを停止する。
キャリーフォワードの正当性はある前提に立つ:AI 認識の変化は週単位である。モデル再訓練、ナレッジグラフ更新、外部ニュースイベントの影響はいずれも時間単位の変動ではない。したがってデータ欠損時に昨日の値で今日を代替するのは統計的に合理的である。
しかしこの前提には境界がある:
本プラットフォームはキャリーフォワードを AI シテーション率関連の次元(Citation、Position、Sentiment)に限定し、構造化データ状態、フィンガープリント照合等の他指標には適用しない。
// Simplified illustration — actual implementation handles multi-platform fanout,
// lookback tuning, and emits observability events.
async function enrichWithStaleCarryForward(platform, brandId, currentResult) {
const currentFailed = currentResult.successCount === 0;
if (!currentFailed) {
return { ...currentResult, isStale: false };
}
const lastSuccess = await db.query(`
SELECT sov_score, position_quality, sentiment, scanned_at
FROM scan_results
WHERE brand_id = $1 AND platform = $2
AND sov_score IS NOT NULL AND sov_score > 0
ORDER BY scanned_at DESC
LIMIT 1
OFFSET 0
`, [brandId, platform]);
if (!lastSuccess.rows.length) {
return { ...currentResult, isStale: false, reason: 'no_baseline' };
}
const historical = lastSuccess.rows[0];
const ageHours = (Date.now() - historical.scanned_at.getTime()) / 3_600_000;
if (ageHours > MAX_CARRY_FORWARD_HOURS) {
return { ...currentResult, isStale: true, expired: true };
}
return {
sov_score: historical.sov_score,
position_quality: historical.position_quality,
sentiment: historical.sentiment,
isStale: true,
lastSuccessAt: historical.scanned_at,
staleAgeHours: ageHours,
};
}
┌──────────────────────────────────────────────┐
│ OpenAI GPT-4o 55 点 🔴 14 時間音信不通 │
│ Anthropic Claude 62 点 │
│ Google Gemini 48 点 🔴 14 時間音信不通 │
└──────────────────────────────────────────────┘
図 4-3:赤い丸とツールチップが明示する——「このスコアは前回成功値で、現在の値ではない」。ユーザーは誤認しえない。
Stale Carry-Forward は GEO 固有のパターンではない。「高頻度サンプリング、不安定ソース、時系列連続性が必要」な信号系に応用できる:
| 分野 | 応用シーン | 調整すべきパラメータ |
|---|---|---|
| IoT センシング | センサー間欠断絶 | lookback ウィンドウを「分単位」に |
| 金融レート | 取引所の短期断絶 | 不適用(金融のリアルタイム性は妥協できない) |
| ソーシャルモニタリング | API クオータ枯渇 | lookback を短く、変動性が高いため |
| 広告アトリビューション | Pixel 一時ロス | probabilistic matching と組み合わせ必要 |
| サプライチェーン可視化 | EDI 転送中断 | キャリーフォワード期間を長めに(数日) |
共通の前提は:変化速度 « サンプリング速度。この前提が崩れる領域(金融等)ではキャリーフォワードは成立しない。
ナビゲーション:← 第 3 章:7 次元採点 · 📖 目次 · 第 5 章:複数プロバイダ AI ルーティング →