
AIクローラーのUAは名乗るだけ — 検証済みだけ数えたら本物468件・偽装991件だった
GPTBot や ChatGPT-User を名乗るリクエストは、その UA を書けば誰でも作れる。Cloudflare の verifiedBotCategory とサイトマップ実在パスの2軸で分けたら、8日間で本物の記事取得は468件、認証情報スキャンは991件だった。同じ UA が検証済みと未検証に割れる実測と、集計スクリプトの実装。
01 — Category
Notes from the workbench.
Build では、Aulvem で作っているサービスの設計・実装・公開・改善の過程、その中で使った技術メモやコーディング基礎を記録しています。詰まった点や採用した技術、改善のきっかけを中心にまとめます。

GPTBot や ChatGPT-User を名乗るリクエストは、その UA を書けば誰でも作れる。Cloudflare の verifiedBotCategory とサイトマップ実在パスの2軸で分けたら、8日間で本物の記事取得は468件、認証情報スキャンは991件だった。同じ UA が検証済みと未検証に割れる実測と、集計スクリプトの実装。

Zenn / Qiita / dev.to へのクロス投稿を重複コンテンツと疑って外部記事を消しかけたが、行単位で測ったら一致795行のうち762行はコードブロックで、散文の一致は393行中3行だった。測り方と、canonical を指定できるプラットフォームとできないプラットフォームの整理。

Googleスプレッドシートから .xlsx で書き出すと、ARRAYFORMULA / FILTER / SORTN / QUERY が Excel に存在しないまま残る。しかも外側の IFERROR が例外を握りつぶすので、画面にはエラーではなく「該当なし」が出る。openpyxl で壊れたセルを数え、ヘルパー列+INDEX/MATCH に書き直して Excel 2016 でも動くようにした記録。

「条件を検知した瞬間に通知を送る」と、検知から送信までの間に在庫や条件が変わって誤報になる。検知は outbox に積むだけにして、送信直前に再照会・再判定し、崩れていたら送らず落とす。冪等な投入・送信直前の再確認・指数バックオフの再送を、Cloudflare D1 上の状態機械として組んだ設計を共有する。

Cloudflare Workers の無料プランは cron トリガーがアカウント単位で5本まで。複数サービスを同居させると足りなくなる。cron を毎分1本に集約し、tick 内で UTC 時刻を見て巡回・送信・日次保守などへ振り分ける設計と、1 実行50サブリクエストの無料枠にバッチを収める方法を共有する。

アカウントもメールも作らせずに Web Push を届けるには、誰に送るかを何で持つかを先に決める必要がある。匿名の device_token を cookie で発行し、Cloudflare Workers + VAPID(webcrypto) で送る構成を、購読の保存・失効管理・iOS と FCM の実機ハマりどころまで含めて共有する。

楽天商品検索APIはレスポンスにJANを返さず、Yahoo!はjan_codeで正引きできる。この非対称を前提に、同一商品を複数モール横断で比較するための『JAN突合 → 名前ファジー一致 → マッチ不能』の3段階を、確証スコアの配点と閾値、誤名寄せを避ける通知設計まで含めて共有する。

個人で価格ウォッチャーを作るとき、表示価格からポイント還元を引いた実質価格の計算でいちばん詰まった。確定・条件付き・仮定の3層に分け、層ごとに floor してから合算し、ランキングには確定層だけを使う。還元率の単位差・上限・送料の扱いまで、実装で決めた設計ポイントを共有する。

llms.txt と llms-full.txt を Astro の API ルートで動的生成し、Content Collections を単一情報源にして英日 2 言語に分けて出す実装記録。filterLang と docLang の 2 軸で 3 エンドポイントを 1 つのレンダラから出す構成と、robots.txt との役割分担まで扱う。

Astro 標準 i18n では hreflang が無条件に全 locale 分出てしまう問題を、Content Collections の実体存在判定ヘルパで両言語にある記事だけ alternate を出す形に直した記録。リシプロカル要件と x-default の扱いまでセットで扱う。

Astro 公式 @astrojs/sitemap が MDX の updatedDate を読まない問題を、astro.config.mjs で fs.readdir + frontmatter regex でマップを作り serialize で差し込む実装で解決した記録。paginated noindex の filter 除外もセットで扱う。

Aulvem サイトの運用ルールを Zod schema でビルドに落としている設計。reviews ⇔ affiliate の連動、howto/faq の構造化データ、本文との文字列一致まで含めて、何を schema で縛り何を諦めたかを書いた。