本物の抽選を、静かに捨てていた 4 つの実例:正規表現・年のない日付・まとめて聞く・null

English version

トレカダッシュ 開発の記録 / 2026年8月〜9月

iOS アプリ「トレカダッシュ」の集める処理には、「これは対象外」と判断して捨てる場所がたくさんあります。捨てる判定は、安全側に見えます。間違えても、画面にゴミが出ないだけで、誰も困らない、ように見えるからです。

ところが、この種の間違いは、気づくきっかけがありません。本物の抽選を捨てていても、画面には何も出ないからです。この記事では、そうやって本物を静かに捨てていた、または捨てかけた、4 つの実例を書きます。

数字と日付は、2026 年 8 月 28 日〜9 月 20 日の作業の記録から書いています。

1. 「x.com」が、「e-starbox.com」に一致していた(8 月 31 日)

応募のリンクが、SNS のリンクなら、お店のページではないので、採用しません。そのために、除外するサイトの名前を並べて、1 つの正規表現(文字列のパターン)にしていました。

new RegExp(["x\\.com", "note\\.com", ...].join("|"))

この書き方は、サイト名の途中にも一致します。x\.com は、e-starbox.com の後半に当たります。note\.com は mynote.com に当たります。

実害は、抽選販売のサービス「抽選ロトボックス」の応募ページ(shoplottery.e-starbox.com)で出ていました。このサービスの応募リンクは、「SNS だから店のリンクではない」と判断されて、一度も採用されていませんでした。

直し方は、ホスト名だけの項目は、「// の直後か、ドットの直後」から始まるときだけ一致させる((?:^|//|\.) を前に付ける)ことでした。足したあとは、通したい URL と、弾きたい URL の両方で、13 例を試しました。除外のリストは安全側に見えるので、間違っていても、誰も疑いませんでした。

2. 年の書いていない日付を、6 年前と読んだ(8 月 28 日)

まとめサイトや店の告知は、「8 月 30 日(日)」のように、年を書きません。この文字列を AI に読ませて、締切を取っていました。

入荷情報のサイトの取り込みで、ポケモンカードの案件が、軒並み2020 年 8 月 30 日(6 年前)として返ってきました。締切が過去だと、入口の関門が弾きます。その結果、このサイト経由のポケモンカードの案件が、まるごと取り込まれていませんでした。ワンピースやドラゴンボールは、たまたま 2026 年と読まれていたので、気づきにくい状態でした。

直し方は、AI に渡す指示に、今日の日付と、「今日より前の年を補ってはいけない」を入れることでした。読める案件は、0 件から 46 件になりました。「投稿日と矛盾しない年」とだけ書いても、投稿日が分からないときに、何年になるのかが決まらないので、足りません。

3. まとめて聞いた答えの、数がずれた(9 月 19 日)

AI への問い合わせは、1 件ずつ送ると、回数分の費用がかかります。そこで、複数の投稿の「販売の形式」を、まとめて 1 回で聞く仕組みを入れました。複数行の投稿の本文を、「1. 本文」「2. 本文」と番号をつけて、改行でつないで渡していました。

AI から見ると、投稿の中の改行と、投稿どうしの区切りが、区別できません。X の監視を再開した 1 日だけで、返ってきた答えの数が合わなかった回が 8 回ありました。数が合わないときは、その組を全部「対象外」にする作りだったので、その組の本物の抽選は、まとめて捨てられました。

もっと厄介なのは、数が合った組でも、別の投稿の答えが当たっていたことです。遊戯王カードの抽選が、対象外として捨てられていました。

直し方は、まとめて渡すときは、JSON の配列([{no, text}])か、本文に出てこない見出し(「【記事 N】」)で区切り、返事にも番号を含めさせることです。数が合わないときは、既定値の「対象外」に倒さず、1 件ずつ聞き直します。

4. 「決められない」を、「無い」と読んだ(9 月 20 日)

ある関数は、投稿の文章から、トレカのジャンルを推定して返します。2 つ以上のジャンルが書かれていると、「決められない」ので null を返します。

別の処理が、この関数を使って、「カードの語が無い(=玩具だけの告知)」を判定していました。!関数(text) という書き方です。ここで、「決められない(null)」が「無い」と読まれました。

ポケモンカード、ワンピース、遊戯王、ドラゴンボール、ガンプラ、と並べる、まとめの投稿は、複数のジャンルが書かれているので null になります。それが「カードの語ゼロ」と読まれ、さらに「ガンプラ」が見つかったので、玩具の告知と判定されました。

もし、このまま動いていたら、毎朝 5:15 に動く一括の非表示の処理が、表示中の本物の抽選 129 件(30th CELEBRATION や、世界最強の戦士など、9 つの商品)を、伏せるところでした。止められたのは、一括の処理を動かす前に、件数だけを数える下見(ドライラン)をしたからです。配備の前に、129 件という数字が出て、気づきました。

直し方は、「無い」を判定したいときは、見つかったジャンルを全部返す関数を使い、その長さが 0 かどうかで見ることでした。

分かったこと

捨てる判定の間違いは、苦情が出ない。だから自分で数える。

この話に出てくるもの

ほかの記録

コメント

感想や、記事の間違いの指摘は、ここへ。書くには、GitHub のアカウントが要ります。

押すと、giscus(giscus.app)と GitHub に接続します。押さなければ、接続しません。詳しくはあつかいに書いています。