「公開していい?」の確認をやめて、公開後レビュー+督促で閉じるループに設計し直した話

  • #自動化
  • #公開パイプライン
  • #GitHub Issue
  • #editorial-ops
  • #the NTM
「公開していい?」の確認をやめて、公開後レビュー+督促で閉じるループに設計し直した話

この記事について

姉妹メディアの一つ(the NTM)で、記事公開前に人間の承認を待つゲートを外し、「出してから直す」設計に切り替えた。無人で公開するかわりに、公開後チェックのワークフローと督促スクリプトを追加し、機械的に直せる範囲はその場で修正、判断が必要なものだけ人間にGitHub Issueで投げ、そのIssueが閉じるまで督促が繰り返される構成にした。1つのPRで21ファイル・約1700行の追加という規模の実装になった。

実装ステータス: 実装済み・稼働中

出発点 — ループが1本も回っていなかった

対象メディアは、記事の自動生成・公開のループが1本も回っていない状態が長く続いていた。実測した停止状態は次のとおり。

項目実測値
最新記事の公開日直近1ヶ月以上更新なし
自動生成・公開ジョブ稼働ゼロ件
起稿ループが読む予定のキューファイル自体が存在せず起動即終了
直近28日の総インプレッション/総クリック76本の記事で表示1,133・クリック10

コードとしては起稿・公開のスクリプト自体は存在していたが、それを呼び出すジョブがどこにも設定されていなかった。生成も計測も止まっていたため、記事が当たるかどうかを試す母数自体がゼロという状態だった。

「公開前に人が見る」をやめる代わりに何を足すか

再建にあたって最初に決めたのは、公開前の人間承認ゲートを置かないことだった。承認待ちのステップがある限り、承認する人間が空いていない時間帯はループが止まる。無人で回すなら、そのボトルネックごと設計から外す必要があった。

かわりに、公開後に必ず別セッションのAIが実物を読みに行くというレビュー段を追加した。書いた本人がそのまま自分をレビューしても見落としは減らないため、公開の1時間後に、執筆に関与していない別のAIセッションが検査する構成にした。レビューの結果は2種類に分岐する。

  • 機械的に直せるもの(リンク切れ・誤字・meta情報・ファクトチェックスコアの再計算・テンプレート変数の展開漏れ)は、レビュー担当のAIがその場で修正PRを作り、自分でマージする
  • 直せないもの(事実関係の疑い・主張の変更・法務やレピュテーションに関わるリスク・方針判断)は、GitHub Issueとして起票し、人間の判断を待つ

督促 — Discordに1回流すだけでは「気づかれない」

レビューが問題を見つけても、Discordに通知を1回流すだけでは他の通知に埋もれて誰も気づかないまま終わる。これは「検出していない」のと実質同じ結果になる。そこで、判断待ちの案件は必ずGitHub Issueとして固定し、Issueが閉じられるまで定期的に督促を鳴らし続けるスクリプトを追加した。

督促の間隔は放置時間に応じて広げる設計にしてある。

経過時間再通知の間隔
0〜24時間4時間ごと
24〜72時間8時間ごと
72時間〜12時間ごと

反応の扱いは2通りしかない。Issueを閉じると督促は完全停止する。これが「対応済み」の唯一の合図になる。Issueにコメントが付くと24時間だけスヌーズする(見た・後でやる、という意思表示とみなす)。逆に言えば、閉じるかコメントするかのどちらもしなければ、間隔を広げながら鳴り続ける。「オオカミ少年」化を防ぐ責任はIssueを立てる側(レビュー担当)が負い、督促スクリプト自体は判定をせず鳴らすだけに徹する設計にした。

なぜ「装填」と「公開」を別レーンにするのか

このループは記事生成から公開まで7本のレーンに分かれているが、なかでも「装填(記事を書いてリポジトリに積む)」と「公開(実際にサイトへ出す)」を別レーンにしている点が設計上のポイントになる。

対象サイトは全ページで下書きフラグを見ており、下書き状態の記事はマージされてもURL自体が生成されない。この性質があるおかげで、

  • 起稿レーンは「書いてマージする」まで無人で走れる。マージされても公開は起きないため、不可逆な操作が発生しない
  • 起稿が失敗しても公開に直結しない。誤って公開フラグ付きで出力しても、下書きガードが機械的に弾く
  • 記事が在庫として積まれるので、公開のペース(1日1本など)を別の設計判断として持てる

「書く」という可逆な作業と、「出す」という不可逆な作業を同じ承認単位で扱わないことが、無人化の前提になっている。

安全弁 — 止めたいときは1箇所を切るだけ

無人運用を続ける以上、いつでも人間が1手で止められる必要がある。各レーンには個別の安全弁を用意し、オンオフを切り替えるだけで該当レーンだけを人間の見守り待ちに戻せるようにしてある。

  • 起稿の自動マージを止める弁
  • 公開の自動実行を止める弁(offにすると公開はPRで止まり、人間のマージ待ちに戻る)
  • 内部リンク補強の自動マージを止める弁

なかでも重要なのは、公開後レビューと督促が止まったら、公開の自動実行も止めるという依存関係だ。レビューが機能していない状態で公開だけが自動で回り続けるのが、この設計のなかで一番危険な状態になる。無人公開を正当化しているのはレビューと督促の閉ループそのものであり、そのループが切れたら公開の無人性も同時に手放す。

レビュー担当への2つの禁止

公開後レビューを担当するAIには、判断の自由度を与える一方で、明確に禁止している行為が2つある。

  1. 記事を非公開に戻さない。一度公開した記事を下書きに差し戻すと、訪問者への404表示や検索エンジンのインデックス消失につながる。取り下げが必要だと判断した場合も、実行はせず人間にエスカレーションする
  2. 推測で直さない。裏が取れない修正は、書き換えるのではなくIssueとして人間に投げる。「たぶんこうだろう」で本文を書き換える行為は、レビューが新たな誤りを生む側に回ることを意味する

この2つの禁止は、「機械的に直せる範囲」を意図的に狭く保つための線引きでもある。直せる範囲を広げすぎると、レビュー自体が二次的な誤りの発生源になる。

動かしてみて分かったこと

  • 承認ゲートを外すことは「チェックを無くす」ことではなく、チェックの位置を公開前から公開後に移すことだった。位置を変えることで無人化と品質担保を両立させられる
  • 督促の設計で一番効くのは通知の頻度ではなく、「閉じる」という行為だけを唯一の停止条件にしたことだった。これにより、Issueが放置されているかどうかが常に一意に判定できる状態になっている

動作環境: GitHub Actions + launchd(常駐サーバ) + GitHub CLI(gh)
更新履歴: 2026-08-03 — 初稿
訂正履歴: なし