自動更新サイトに「捏造セールを弾く」検証ゲートをビルドに入れる(実装コード付き)
セール情報サイトを日次で自動更新していると、機能追加よりも先に効いてくるのが「載せてはいけないものを載せない」仕組みだ。価格や割引率は生モノで、しかも自動生成の文章は平然ともっともらしい嘘を書く。運用している ocha.autoarticles.net(お茶)、menrui.autoarticles.net(麺類)、manga-deals(Kindleセール)では、この問題を「ビルドを止める」という一点に集約して解いている。
方針:レビューではなくビルドで落とす
原稿の内容を目視レビューで担保する運用は、1日2回の自動更新には乗らない。そこで、データ(data/articles.json)から静的HTMLを生成する build.js の入口に検証関数を置き、条件を満たさない記事があれば process.exit(1) する。デプロイはビルド成功が前提なので、検証に落ちたデータは本番に出ない。
掲載を許すのは次の2種類だけ、というのが設計の出発点だ。
- (A) 実在が確認できた具体セール — 確認日(
confirmed)と出典URL(source)が揃っているもの - (B) 恒常的な仕組みの解説 — 断定的な割引率・価格を書かないもの
つまり「断定表現を書くなら裏付けを出せ、出せないなら断定するな」という一本のルールに落ちる。
実装:断定表現を正規表現で検出する
判定は記事オブジェクト全体を JSON.stringify した文字列に対してかける。タイトルだけ、本文だけ、と対象を絞ると deal.detail や highlights の書き漏れを見逃すためだ。
1 | |
正規表現のいくつかは実際の事故から足したものだ。還元(?!率) の否定先読みがその例で、「ポイント還元率の仕組み」という一般解説(断定ではない)が毎回ゲートに引っかかっていたので、「還元率」という語だけ除外した。この手のゲートは、厳しすぎると正当な記事が通らず、運用者が検証そのものを外したくなる。誤検知を潰しながら締めるのが実務的な落としどころになる。
出力側にも同じ前提を通す
検証を通ったあとの生成側でも、確認日と出典を必ず可視化する。confirmed があれば「調査日:7月19日時点」と表示し、出典URLがあれば一覧としてレンダリングしたうえで、注記の文面を出典の有無で切り替える。
1 | |
読者から見た価値もここにある。「いつ時点の情報か」「どこで確認したか」が各ページに出ていれば、鮮度の判断を読者に委ねられる。逆にこれを書かないサイトは、正しい情報でも信用できない。
sitemap の lastmod も同じ値から引く
確認日を単一の真実にしておくと、副次的に SEO 側の整合も取れる。sitemap.xml の lastmod を a.confirmed || a.date から生成しておけば、記事の実際の確認日とサイトマップの更新日がずれない。未来日付の lastmod を作ってしまう事故も、確認日が実行日を超えない限り起きない。
1 | |
多層で守る
同じ考え方を、脆弱性まとめの cve.autoarticles.net では別の条件で実装している。あちらの掲載基準は「severity が High/Critical」「CVSS >= 7.0」「有効な source URL 必須」で、満たさなければ同じくビルドが止まる。扱うデータが違えばゲートの条件も違うが、「データの入口とビルドの2段で弾く」という構造は共通だ。
自動更新の運用でいちばん効いたのは、ルールを文章で書くことではなく、ルールを破ったらデプロイできない状態にすることだった。文章のルールは守られないことがあるが、process.exit(1) は必ず守られる。