「後から掃除するから大丈夫」が、入口の不具合を隠していた:商品が毎日 400 件そっくり作り直されていた

English version

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

iOS アプリ「トレカダッシュ」の商品のデータには、毎日夜に、重複した商品をまとめる掃除の処理があります。「後から掃除するから、大丈夫」。そう思っていた場所に、毎日、そっくりな商品が作り直されている入口の不具合が、隠れていました。

2026 年 8 月 27 日の総点検で、「この日だけで商品が 437 件、作られていて、そのうち 410 件は、記事が 1 件も付いていない」と分かりました。

数字は、2026 年 8 月 27 日の作業の記録から書いています。

原因:「名前の完全一致」でしか、探していなかった

公式のカタログから、商品を登録する処理は、「同じ商品が、すでにあるか」を、名前の完全一致だけで判定していました。

既存「拡張パック「古代の咆哮」」  ↔  カタログ「拡張パック 古代の咆哮」
既存「Vスタートデッキ草(全角空白)フシギバナ」  ↔  カタログ「Vスタートデッキ草 フシギバナ」

括弧、空白、全角と半角の違いだけで、「まだ無い」と判定され、毎日、そっくりな商品が作り直されていました。

作られた重複は、後から、週 1 回と毎日の統合の処理が片付けていました。だから、気づけませんでした。ただ、その間は、利用者に同じ商品が 2 つ見え、記事の紐付け先も割れます。

直し方は、統合の処理が使っているのと同じ正規化(括弧、空白、全角と半角を吸収する)で比べることでした。カタログ側にも、表記ゆれの重複があるので、同じ実行の中では、同じキーを 1 つに絞ります。

教訓は、「後から掃除するジョブがある」仕組みは、入口の不具合を隠してしまうことです。掃除の件数が、毎回同じくらい出ているなら、片付いているのではなく、毎日、作られ続けています。

もう 1 つ:6 つの商品が、1 つに吸い込まれていた

マジック:ザ・ギャザリングの「FINAL FANTASY」の統率者デッキ 6 種(サイオンズ・スペル、リミットブレイク、カウンター・ブリッツ、トランス・リアニメイト、ほか)が、すべて 1 つの商品に吸い込まれていました。

という、自己増殖の形でした。別表記を掃除するだけでは、直りませんでした。AI が、同じ商品を選び続けるからです。そこで、括弧の中の固有名が違う商品を、照合の候補から外す判定(namesDifferentQuotedVariant)を、候補のフィルタにも入れました。候補から消えると、AI は「新しい商品」と答えられるので、正しい商品が作られます。

誤検知を潰すために、括弧の中が、総称、地名、店名、数量、状態のときは、固有名として扱いません。実データで確かめると、この条件を入れる前は、12 件のうち 6 件が誤検知でした。

また、採用しなかった案もあります。「商品名の固有名が、別表記に含まれないなら、消す」という強い規則も試しました。43 件のうち 6 件が誤検知(型番が同じ別の弾、「+(プラス)」の付く名前など)だったので、見送りました。

自分の修復で、先着に締切を付けてしまった

同じ告知のページの記事から、日付を引き継ぐ修復の処理(inheritDatesFromSameAnnouncement)を流しました。すると、先着(無くなり次第終了)の記事に、同じページの抽選記事の締切を、渡してしまいました。先着には、締切という概念がありません。利用者に、「その日まで買える」という嘘の期限を見せることになります。

引き継ぐ側の 2 か所(保存のときの処理と、修復の処理)の両方で、先着には、締切を渡さないようにしました。付けてしまった 1 件は、消しました。

教訓は、修復の処理を流したら、流す前と流した後で、監査を比べることです。「直った件数」だけを見ていると、自分が増やした異常に、気づけません。

分かったこと

後から掃除する仕組みは、入口の不具合を隠す。

この話に出てくるもの

ほかの記録

コメント

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

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