同じ記事を4週続けて公開していた — 自動化に「書かない」選択肢がなかった話
月曜の朝、「今日の更新内容を教えて」とClaude Codeに聞いた。返ってきた一覧の中に、見覚えのありすぎるタイトルがあった。
「3つ試して、2つ弾かれて、1つ入った週 — 2026-W32」
8月17日、8月24日、9月7日、そして今日。noteに自動投稿された記事が、4本ともこのタイトルだった。書き出しはそれぞれ違う。月曜の朝だったり、土曜の夜だったりする。でも中身はどれも、8月9日に動いたW32の実行ログの話だ。同じ週の出来事を、4回、別の顔で書いて公開していた。
今日はその原因を調べて直した。その記録を残しておく。
原因1:実装Botが月1回になったのに、記事側はそれを知らなかった
7月に、サイト改善Botの実行を毎週から月1回(第2月曜)に変えた。W33〜W36の4週間はBotがスキップされ、実行ログは作られていない。
一方、noteの記事を書くスクリプトは「実行ログの中で一番新しいもの」を無条件に拾う作りだった。新しいログがなければ、W32のログが「一番新しい」ままになる。しかも、記事ファイルができなければワークフローが失敗扱いになる設計だったので、スクリプトには「今週は書かない」という選択肢が構造的に存在しなかった。
書くネタがない週にも、書かなければならない。だから古いネタで書いた。機械としては忠実だ。
原因2:タイトルが自分を増幅していた
タイトルがハードコードされていたわけではない。記事を書くときに、過去のnote記事のタイトルを「文体のサンプル」としてAIに渡している。そして公開された記事は、1日数回の同期でサイト側の一覧に取り込まれる。
つまり、重複した記事が公開されるほど、サンプルの中に同じタイトルが並ぶ。同じ数字(3件試行・2件スキップ・1件採用)と同じサンプルを渡されれば、同じタイトルが返ってくる。小さなループが回っていた。
原因3:投稿が1週遅れていた
note投稿は、Macのlaunchdで月曜8時30分に動かしている。記事生成は7時30分の予定だが、GitHub Actionsのスケジュール実行は遅れることがあり、実際には9時台に終わっている週があった。投稿側はまだ新しい記事がない状態で起動し、先週の記事を拾っていた。
もう1つの勘違い:「消えた」と思った変更は、PRで待っていた
調べている途中で、もう1つおかしな点が見つかった。今週のBotの実行ログには「1件実装、ビルド成功」とあるのに、mainブランチに該当する変更が見当たらない。
最初は「変更が失われた」と判断した。実際は違った。手元のリポジトリがmainしか取得していなかったので、Botが作ったブランチが見えていなかっただけだ。変更はPRとして、レビュー待ちのまま置かれていた。
Botは、PRを作るところまでしかやらない。本番に出すには人間のマージが要る。そういう設計にしたのは自分だ。そしてPR一覧を見ると、Botが作ったPRが20件以上、開いたまま溜まっていた。W32の実装PRもその中にある。
W32の記事には「今週からCTAボタンの文言が変わった」と書いてあった。でもその変更は、一度も本番に出ていなかった。ログの buildPassed: true は「ビルドが通った」という意味で、「サイトに反映された」という意味ではない。記事を書くAIも、それを読んだ私も、そこを取り違えていた。
直したこと
記事生成: 最後に記事にした週を記録するファイルを置いた。新しい実行ログがない週は、書かずにスキップする。手動で強制生成するスイッチも付けた。
文体サンプル: 同じタイトルは1件にまとめてから渡す。
投稿側のガード: 投稿済みと同じタイトルの記事は投稿しない。日付が3日より古い記事も投稿しない。
投稿時刻: 月曜8時30分から10時30分に移した。
W37の変更: レビュー待ちだったPRをマージした。
生成側を直しても、何かの拍子にまた同じ記事ができるかもしれない。だから公開の直前にも、もう一段の関所を置いた。
自動化に要るのは「やらない」判断
今回の件は、どれか1つが壊れていたわけではない。Botは設定どおりにスキップし、記事スクリプトは設定どおりに最新ログで書き、投稿スクリプトは設定どおりに未投稿の最新記事を公開した。部品はすべて正しく動いていた。
足りなかったのは、「今週は何もない」を表現する方法だった。自動化を組むときは、何をするかばかり考える。でも、ネタがない週、前提が変わった週に黙って止まれるかどうかのほうが、公開まで自動でつながる仕組みでは効いてくる。
同じ記事を4本読ませてしまった方には、申し訳ない。
