# pixelstomotors.com 計測・分析の敵対的検証

検証日：2026-11-12。対象 HEAD：`1e04e85`（写しの `code/HEAD.txt`）。

## 検証の範囲と結論

依頼書、`data_snapshot.md`、`code/` の全ファイルを対象に静的検証した。ネット接続、本番への送信、本番設定の照会は行っていない。Playwright・curl・チャット履歴の確認は、提供された記述であり、今回独立に再現した事実ではない。行番号はこのフォルダの写しに対応する。

**確認できたのは「h に分類されて届いた表示が急減した」ことまで。実際の来訪減と計測欠損は切り分けられていない。** 外部の人による Claude 利用という帰属も確定できない。コードには日跨ぎ再送の重複・集計範囲の不一致があり、スマホ 0% には整数丸めという別の落とし穴がある。ただし、これらが11/11の急減を引き起こした証拠はない。

補助検証はファイルを作らず Node.js のメモリ内で実施した。実際の `kpi.js` の `computeKpiDay` を模擬 R2 に対して実行し、同じ v の日跨ぎ記録が各日に1件ずつ数えられることを確認した。割合の丸め・週合計も再計算した。コード・元データは変更していない。

## 1. 人の表示の急減

### 1a. 人だけが落ちる経路 — ⚠️ 要注意

次の経路をコードから排除できない。いずれも「存在する経路」であり、今回発生したという意味ではない。

| 段階 | 人の表示が欠ける条件・影響 | 根拠 |
|---|---|---|
| 記録を開始しない | DNT=1、GPC=true、localStorage の notrack=1。実際の人でも ev 全体が送られない。共有された notrack 付きリンクでも設定される | SiteMeasure.astro:29–37,50 |
| JS が起動しない | 計測スクリプト未配置、ビルド・配信不一致、JS無効、ブロッカー、CSP、古いHTMLとアセットの不整合、ロード失敗・構文/API実行エラー | SiteMeasure.astro:23以降、wrangler.jsonc の assets 設定。生成物・ヘッダーは未提供 |
| 送信契機が来ない | 初回ロード時には送らず hidden/pagehide 待ち。読んだままのタブ、プロセス強制終了、通信断などは未記録または遅延 | SiteMeasure.astro:203–220 |
| 送信失敗を回収しない | Beacon の true はサーバー保存の確認ではない。403/429/ネット失敗でも n を増やし dirty=false。例外時も同様。fetch はステータス未確認で、Beacon が例外を投げた場合は fallback 自体を実行しない | SiteMeasure.astro:209–214 |
| sameSite 拒否 | Origin が文字列 `null` なら URL 解析失敗で403。Origin欠落かつ Sec-Fetch-Site が same-origin 以外・欠落でも403。Origin が存在すれば Fetch-Site による救済なし | index.js:130–139 |
| 制限 | IP 単位で RL_EVENT を共有し ev と hk-event が競合。携帯・組織の共有IP、多数タブ等で429。cf-connecting-ip欠落なら unknown に集中 | index.js:110–111,140–145、wrangler.jsonc の60回/60秒 |
| 人を b に分類 | CF判定がtruthy、UA空、広い正規表現、wd/hl=1 のいずれかで u=1 より優先 | index.js:365–372 |
| 人を x に分類 | 操作なし閲覧、計測起動前の操作、iframe 内だけの操作、支援技術等で列挙イベントが親documentに届かない | SiteMeasure.astro:79–85,165–178 |
| サーバー・集計 | R2 put失敗、古いKPI、一覧打ち切り・期間差でも見かけが変わる | index.js:405,425–435、kpi.js:96–107 |

通常の同一オリジン送信が常に Origin=null になる、Safariやアプリ内ブラウザが一般に失敗する、とまでは言えない。対象ブラウザの実際のリクエストヘッダーが必要。`sameSite` は scheme を比較せず host のみを比較する点でも「同一origin」の厳密判定ではない。修正時は許可 origin を明示し、null を無条件許可しない。

CFの verified 判定が普通の人で真になる頻度や仕様上の保証は資料にない。真なら人の操作より優先して b になることは確実だが、実際の誤判定は判断できない。判定理由別の件数を確認する必要がある。

UA の `LinkedIn`、`Twitter`、`GSA` という文字列だけでは該当しない。一方 `preview` は境界なし、`bot;`・独立語bot・`okhttp`等は利用者向けアプリのUAに含まれれば該当する。SNSプレビュー自体は機械なので妥当であり、人のアプリ内閲覧と混同しない。実UAとヒットした規則を短期診断しなければ誤分類の有無は決められない。

機械の ev が継続しても、実ユーザー固有の送信経路・プライバシー設定・分類を保証しない。cr はJSもsameSiteもRL_EVENTも通らない別経路なので、cr正常はさらに弱い根拠である。x が2件しかないことは大量の h→x だけで説明する説には不利だが、未送信や h→b は否定しない。

### 1b. 645件のスマホ幅 0% — ⚠️ 要注意

**0% は0件を意味しない。** `index.js:475–480` は `Math.round(sp/views*100)`。分母645なら sp が1、2、3件でも0%。原数またはhumanだけの sp/views を取る必要がある。さらに `spPct` は who で絞った母集団だが humanViews/botViews は絞る前（index.js:460–482）。同じ行に出ても分母が違うことがある。期間・who・truncated の実レスポンスが未提供なので、645と割合が同一母集団かも再確認が必要。

仮に人5表示すべてが本当にpcでも、従来のsp比率21%を固定し独立と仮定すると、5件でspが0件の確率は `0.79^5 ≈ 30.8%`。珍しい証拠ではない。表示は同一人で相関しうるため、これは参考計算である。機械638表示に人の21%を適用してはいけない。

また sp は初期 innerWidth<600 の意味で端末種別ではない（SiteMeasure.astro:76）。viewport設定欠落ならスマホでもpcになりうるが、HTMLは未提供。スマホ消失・故障の証拠にも、故障否定の証拠にも現状では足りない。

### 1c. Playwrightの204 — ⚠️ 要注意

204は、その環境・その送信について Worker が R2 put を await して終了した証拠になる（index.js:403–406）。ただし集計への反映と h 判定は別。webdriver により b なので、h の経路の成功を直接確認していない。iPhoneエミュレーションは実Safari/WebKitや実携帯回線の検証ではない。

決着には、日本の家庭回線と携帯回線で、実Safariおよび代表的なアプリ内ブラウザから自然な操作を行い、HTML・計測JSの取得、例外、Origin/Fetch-Site、POST応答、対応する v のR2保存、k=h・w・n、集計反映まで一続きで確認する。テスト記録は識別可能にして通常分析から区別する。notrack/DNT/GPC状態も記録する。

### 1d. Cloudflare等のコード外変更 — ⚠️ 要注意

資料から否定できるのは全面停止だけ。WAF・チャレンジ・Bot対策はUA/IP/地域/パス等で差が生じうるし、ページGETが成功してもJSアセットやPOSTが失敗しうる。クラウドからの200は日本の実ユーザーへの配信を代表しない。

`measurement_git_log.txt` は関連変更の抜粋で、11/8の見た目変更と11/12の統計・説明変更を含む。履歴の記述は計測の主要部分が変わっていないという補助証拠にとどまり、デプロイ済み成果物・CF管理画面・ルート・ヘッダー等の不変性を証明しない。11/10〜12の全差分もここにはない。本番の変更履歴と11/10前後の応答・配信物比較が必要であり、現時点では判断できない。

## 2. 流入元の減少

### 2a. 期間・曜日・途中日の比較 — ⚠️ 要注意

| 指標 | 11/2〜8：7日 | 11/9〜12：3日＋16時間 | 後半を単純に4日で割った値 |
|---|---:|---:|---:|
| 人の表示 | 136（19.43/日） | 53 | 13.25/日 |
| Google | 37（5.29/日） | 19 | 4.75/日 |
| 直接・不明 | 67（9.57/日） | 15 | 3.75/日 |
| サイト内 | 17（2.43/日） | 14 | 3.50/日 |

53/136 だけで減少率を語れない。後半は平日のみ、前半は週末を含む。経過時間3.667日で割れば人14.45/日、Google5.18/日、直接4.09/日だが、時刻別流量が一定ではないので機械的外挿も推奨しない。Googleの期間平均は大幅減を示していない。

差分では11/9はGoogle5件、11/10は11件、11/11〜12は計3件。11/11〜12は合計5件が Google3・t.co1・chatgpt1で尽きるため、その範囲の直接・不明0件は資料上整合する。11/9〜10の直接・不明は計15件。『11/11以降、記録されたGoogleと直接・不明が少ない』とは言えるが、同じ長さ・曜日・締め時刻で再比較する必要がある。

### 2b. 同時に落ちた意味 — ⚠️ 要注意

記録上、複数の流入元にまたがる減少とは言える。Googleだけの検索順位変化では直接・不明まで落ちた理由を自動的には説明できない。しかし共通するJS・送信・分類の障害も、実際の需要減も説明候補であり、同時減でどちらかには決められない。

『直接・不明』はアプリ・referrer抑制・ブックマーク等が混ざる残余区分で、固定した読者層ではない（SiteMeasure.astro:55–70、index.js:495–497）。日単位の原数・端末別・ページ別を確認し、Search Consoleクリックやページ配信数と照合する。Search Consoleも表示回数と同義ではなく時差・確定遅れに注意する。

## 3. Claude-Userの帰属

### 3a. WebFetchの一般化と外部利用の断定 — ❌ NG

11/8にClaude-Userが0件だったことから、全Claude Code/WebFetchが将来も含めてClaude-Userに入らず、Claude-Userはclaude.aiだけ、と一般化できない。`code/mcp.js:28` は根拠より強い断定で、削除して『11/8の当該観察では記録を対応付けられなかった。経路と利用者は未確定』とする。

キャッシュ、別UA、リダイレクト先・別ドメイン、実アクセス未発生、取得失敗、cr保存失敗、集計打ち切り、タイムゾーンの取り違え等が未排除。`notrack` はブラウザのev設定であり、AI側のcrを除外しない。本人の『自分ならもっと読む』も帰属を決める証拠ではない。

11/3の12件はチャット出典一致という強い自己試行の根拠が報告されているが、こちらで履歴を独立確認していない。残る7つの時刻のまとまり・非robots10リクエストは**帰属未確認**とする。時刻のまとまりは7人・7依頼を意味しない。既知の各クライアントから一意なテストURLで取得し、キャッシュ有無・リダイレクト・生アクセス記録と対応させても、そのテスト条件内での確認にとどまる。

### 3b. ok=0と偽装 — ⚠️ 要注意

UAは自己申告であり偽装可能。ok=0は本物でないと確定した意味でも、Claudeが原理的に検証対象外と証明する意味でもない。コードはCF一般のbot判定を記録するだけ（index.js:571–580）で、Claudeという名乗りと検証済み主体の一致を検査しない。疑わしいリクエストもClaudeはKPIに入る（kpi.js:63–66）。

時刻・読んだページ・robotsの順序だけでは真正性も外部利用も確定しない。追加調査ではサービスが提供する真正性確認手段があるかを別途確認し、利用可能なら送信元等と照合する。短期ログ等の設計とプライバシー配慮は必要。現存のcrメタデータにはUA/IPがなく、過去分をこの資料だけで確証に変えることはできない。

### 3c. crawlerOfの順序・includes — ⚠️ 要注意

一覧の各正式名だけなら、Claude-UserとClaudeBot、ChatGPT-UserとGPTBot、Perplexity-UserとPerplexityBotは相互の部分文字列ではない。通常の単一トークンが順序だけで別名になる直接の衝突は見つからない（index.js:549–568）。

ただし複数トークンを含むUAは先勝ち。たとえば `GPTBot ChatGPT-User` はGPTBot、`ClaudeBot Claude-User` はClaudeBotとなり、依頼読みから外れる。`FakeClaude-UserExtra` もClaude-Userに一致する。逆方向の偽装・別主体混入も可能。製品トークンの境界を定めて一致を取り、複数一致は曖昧として別集計し、真正性と分離する。UA判定だけでサービスや依頼主体を保証しない。

## 4. AIの依頼読みの横ばい

### 4a. 数える単位と傾向 — ⚠️ 要注意

週合計55→61→24は日別表の加算と一致する。日平均は7.86→8.71→6.00（最後は途中日込み4日割り）。ただし11/2〜5の同曜日は37件、11/9〜12は24件であり、『横ばいが確認できた』という強さには足りない。自己試行12件の除外有無でも評価が変わる。

**実装は1ページ1件ではなく1リクエスト1件。** 同じ / を2回取得すると2件。HEAD、再試行、リダイレクト元・先、404/500も非robotsなら入る（index.js:43,61,564、kpi.js:61–67）。`robots.txt` 以外の llms.txt 等は含む。資料の11/12の / 2件もその例。依頼数・利用者数・ユニークページ数には変換できない。

ChatGPT除外も `ok === '0'` だけで、`?`/欠落は含める（kpi.js:65）。『確かめられなかったものを全て除外』という `mcp.js:21` の説明と異なる。さらにCFの検証済みbot判定はChatGPTという主体の検証と同義ではない。検証方式・取得ページ数・UA構成・自己試行が変われば合計だけでも上下する。『この定義で観測された非robotsリクエスト数は55・61・今週途中24件。利用の横ばいは未確定』へ弱める。

### 4b. 永続日次集計・遅延・再送 — ❌ NG

`kpi.js:97–107` は同版の過去日JSONを返し続ける。`kpiCron:154–157` は前日ファイルがあれば終了し、5分ごとに更新するわけではない。日付直後の初回生成中に届いた前日分の保存等は後から反映されない。cron停止で空いた古い日はcron自体では埋めず、kpiRangeで作成上限つきの埋め戻し（123–134）となる。cronは保存済みの旧版・破損をheadで飛ばし、呼び出し時のgetKpiDayとは挙動も異なる。

より明確な誤りは日跨ぎの同じ v。evは**受信日**のprefixに保存（index.js:403–405）、KPIは日内だけで重複排除（kpi.js:70–75）。前日にn=0、翌日にn=1ならKPIでは1+1、期間全体のevStatsでは1件となる。実際のcomputeKpiDayを模擬R2で実行し再現した。翌日だけに初送信された表示は前日のページ閲覧でも翌日になる。これは『過去日の遅着で抜ける』とは別の日時帰属問題。

修正は安定した表示日・IDを定義して保存/集計を共通化し、閉じた日も一定猶予後に再集計、遅延更新を可能にすること。受信時刻と表示時刻は区別する。n最大での置換は加算ではないため、同日内で再計算するだけなら通常は二重計上しない。ただしこれらのバグが今回の20〜30→3を説明する規模かは未検証。

## 5. 計測の作り

### 5a. hは人が読んだ数か — ⚠️ 要注意

hは『bot条件に該当せず、列挙された操作の申告があった表示』である。人の読了や人数を表さない。静かに読む人・設定で記録しない人・送信できなかった人には過小になる一方、pointermoveだけで即離脱した人もhとなり、自動操作・合成イベント・u=1の偽装POSTでも増やせる（isTrusted等は未確認。index.js:372、SiteMeasure.astro:84–85）。人としての読書に対する総合的な偏り方向・大きさは判断できない。

名前を『操作あり表示』とし、xも別に示すのが妥当。見えた時間や深度を添えても読書の証明にはならない。フォーム・AIリンク等の指標も同じ選別バイアスを受ける。

### 5b. 再送の重ね方は両方同じか — ❌ NG

同一の読み込まれた集合では、双方とも v ごと n 最大、同値なら後から列挙された記録を採用する点は同じ（kpi.js:70–75、index.js:421–435）。ただしKPIは日ごと、evStatsはsince以降の全期間で同じvをまとめ、最大nを持つ記録の受信日に帰属させる。したがって前日件数が再送で別日へ移ることもある。両者は期間合計・日付帰属が一致しない（4bの再現）。evStatsには4万件の上限もある。

nはWorkerで50に丸める（index.js:391）。51回以降はnの大小が順序保証にならず、同値の後勝ちに依存する。安定した日付・重複排除範囲と同値時の時刻による採用規則を共通化し、上限の意味も定義する。BFCache復帰はfreshで別vにする設計（SiteMeasure.astro:221–223）なので、『タブに戻る再送』と『戻るボタンによる別表示』も分けて説明する。

### 5c. crStats打ち切りとhits — ❌ NG（打ち切り時の「最新200件」）

時刻はキーのepoch msから取り出してJST化し、降順ソートするため、**全件を読み切れた範囲では**最新200件の処理に明白な誤りはない（index.js:596,649以降）。同秒内の表示は秒単位に丸められ、別リクエストが同時刻に見える。robotsも含む。

問題は `index.js:590–599` で全botのcrを先に最大40ページ読んでから `625` でbot絞り込み、`649` でソートすること。キー順の古い側で打ち切られれば新しい記録を読んでいないため、返すのは**読めた範囲内の最新200件**であり、対象期間の最新200件ではない。bot指定でも他botが予算を使い切る。truncated=trueは出るが、hits独自の200件省略件数・継続カーソルはなく、truncated=falseでもそのbotが201件あれば全訪問履歴ではない。byBot/byWeek/errorsはbot指定でも全botを集計するので混同しない。

修正は日付prefixを新しい日から走査するかbot別の索引を設け、継続ページを返すこと。hitsの完全性・省略件数と集計対象を明示する。今回のhits取得でtruncated=falseだったかが資料にないため、『他に訪問がなかった』の根拠にはまだ使えない。sinceにuntilがなく、スナップショット時刻以降も再取得値は変わる点にも注意。

### 5d. 優先度評価 — ⚠️ 要注意

1. **最優先の未確定事項：実ユーザーだけの未送信・誤分類。** 原因の証拠はまだないが、結論1を支える検証がbの成功しか確認していない。実機でGET→JS→POST→h保存を確認し、拒否/分類の理由別件数とCF変更履歴を見る。
2. **確定した整合性不良：日跨ぎ再送、日次キャッシュ固定、範囲差。** 4b/5bの修正が必要。今回の原因と断定しない。
3. **分析に直結する表示・説明問題：0%の丸め、latest hitsの範囲、未確認ChatGPTの扱い、WebFetchの断定。** 生の分子/分母・完全性を返し、mcpの説明を修正する。
4. **送信の耐障害性と除外設定の例外処理。** SiteMeasure.astro:29–34 はlocalStorageが例外になるとq=1でもoffがfalseのままになりうる。『毎回の判定』というコメントどおりに除外できない。q=1を永続化の成否と独立に適用する。これは自身の閲覧混入による過大側の別バグで、今回の急減の証拠ではない。送信失敗の回収・稼働中のチェックポイントも設計する。
5. **指標の意味：AIは取得試行、hは操作あり表示。** 成功レスポンス/HEAD/重複/自己試行/未検証を分けないと利用人数や利用増減へ誤変換される。

## 最終サマリ

### 結論1〜4の扱い

| 結論 | 判定と採用すべき言い方 |
|---|---|
| 1：故障ではなく本当の減少 | **故障を否定した部分は撤回。** 『記録された操作あり表示は11/11に3件、11/12途中に2件。実減か選択的欠損かは未確定』 |
| 2：直接・不明とGoogleが減った | **記録上の11/11以降の減少に限定すれば可。** 週全体のGoogle大幅減や直接流入の実減とする言い方は弱める。異なる長さ・曜日・途中日の合計比較は避ける |
| 3：残り7回10ページは外部の人 | **外部帰属の断定を撤回。** 『自己試行と確認された11/3分を除き、7つの時刻群・非robots10取得は帰属未確認』。7依頼/7人とも確定しない |
| 4：AI依頼読みは横ばい | **55→61→途中24の観測値はそのまま可、横ばいは弱める。** 同期間・自己試行・取得単位・真正性を揃えるまでは傾向未確定 |

### 急減を決着させる次の確認（優先順、3つ）

1. **日本の実回線・実機で1件を端から端まで追う。** Safariと代表的アプリ内ブラウザで操作し、計測JS取得・例外・送信ヘッダー・応答・同じvのR2保存・k=h・幅・集計を対応させる。bで成功した確認だけでは終えない。
2. **11/10前後の本番設定/配信/拒否の変化を照合する。** CFのWAF・Bot・challenge・route・デプロイ/アセット/ヘッダー変更と、ページGET・JS取得・ev POSTの403/429/5xx・分類理由を時刻/端末等で確認。既存ログで足りなければ短期診断を設計する。一般ユーザーGETは現crに残らないのでcrだけでは代用できない。
3. **原記録を日付・範囲を固定して再集計し、独立指標と比較する。** 11/2〜12のev/cr原件数、h/b/x、sp実数、最大n、日跨ぎv、truncated、KPI madeAt/版を確認。同曜日・同締め時刻の比較と、確定後のSearch Consoleクリック/利用可能な配信ログを照合する。これでも『人数』の直接観測にはならない。

### コードで直すべきもの（優先順）

1. 日付帰属・重複排除をKPI/evStatsで共通化し、遅延分を取り込む再集計を設ける（kpi.js:70–107,154–157、index.js:403–405,421–435）。
2. 送信失敗を成功扱いする状態更新とfallbackを見直し、終了時だけに依存する欠損を減らす（SiteMeasure.astro:203–220）。同じv/nでの回収を設計し、単純な再送加算にしない。
3. hitsの最新性/完全性を保証または明示し、全bot先行打ち切りを解消する（index.js:590–599,625,649以降）。割合には分子/分母も返す（475–480）。
4. ChatGPTの未確認値の採否を定義と一致させ、成功取得と試行を区分する（kpi.js:63–66）。UAの境界・複数一致、CF検証と主体名の関係も明示する。
5. notrackのlocalStorage例外時の漏れを直し（SiteMeasure.astro:29–34）、WebFetch断定・『数え漏れがない』を修正する（mcp.js:21,28,48）。

本報告は原因確定の報告ではない。確定した実装上の不整合と、現資料で否定できない故障経路を区別した。コード・データへの修正は実施していない。
