自動投稿が止まっていることに、朝の通知が来ないことで気づいた日がありました。前夜に作業マシンを初期化し、翌朝には元通りに戻るはずでした。ところが戻ってきたのは生成パイプラインのコードだけで、認証もスケジュールも生成途中の状態も、どこにも残っていませんでした。
個人開発で4つのサイトを自動運用していると、止まること自体はいつか必ず起きます。問題は止まることではなく、止まったあと何分で元の状態に戻せるかです。Antigravity 2.0 でデスクトップアプリ・CLI・SDK と運用の面が増えたいま、戻す対象も同じだけ増えました。ここでは、復旧を「気合いで思い出す作業」から「手順で戻す作業」へ変えるための設計を書きます。
復旧対象を1つの塊で考えると必ず抜ける
最初の失敗は、自動運用を「ひとつのまとまり」として捉えていたことでした。コードは git にあるから大丈夫、という安心が、認証やスケジュール定義の存在を視界から消していました。
復旧は対象ごとに性質が違います。性質が違うものを同じ場所・同じ頻度で守ろうとすると、いちばん守りにくいものに引きずられて全体が脆くなります。そこで私は、守る対象を次の3層に分けました。
- 認証層: API キー、CLI のトークン、Google Play や AdMob の資格情報
- 定義層: スケジュール、エージェントへの指示文、品質ゲートの設定
- 状態層: 生成途中のチェックポイント、実行ログ、公開済みかどうかの記録
この3つは、失われたときの痛みも、戻すための手段も別物です。分けて初めて、それぞれに合った守り方を選べます。
層ごとに目標復旧時点を変える
すべてを同じ頻度でバックアップする必要はありません。私は層ごとに目標復旧時点(RPO)を変えています。RPO とは「どこまで遡ったデータなら許せるか」の指標です。
| 層 | RPO の目安 | 置き場所 |
| 認証層 | 0(常に最新) | 秘密管理サービス+紙の控え |
| 定義層 | 24時間 | git リポジトリ |
| 状態層 | 1時間 | オブジェクトストレージへ自動同期 |
認証層は遡りが効きません。古いトークンを復元しても再認証が要りますから、RPO という概念より「常に取り出せる場所に1つだけ正本を置く」発想が合います。私は秘密管理サービスを正本にしつつ、復旧の起点となる管理コンソールのログイン手段だけは、オフラインの控えにも残しています。ここが取り出せないと、他のすべてに手が届かなくなるからです。
定義層は git に置けば履歴ごと守れます。スケジュールの時刻表やエージェントへの指示文をリポジトリ管理にしておくと、壊れた瞬間ではなく「壊れる前の正しい状態」へ戻せます。
状態層は更新が速いので、短い間隔での同期が要ります。私は生成途中のチェックポイントと公開記録だけを1時間おきにオブジェクトストレージへ写しています。全部を1時間おきにすると重くなるので、速く変わるものだけを切り出すのがコツです。
バックアップがあっても戻せない3つの典型
ここからが本題です。バックアップは取れていたのに復元できなかった経験を、3つの型にまとめました。
- 復元したことがない: 取得は自動化されていても、戻す手順を一度も通していない。いざというとき初見の作業になり、時間を浪費します。
- 認証だけ手作業に逃げている: コードや定義は戻せても、再認証の経路が人の記憶頼みで、夜間や移動中に詰まります。
- 部分復旧で食い違う: コードは最新、定義は前日、状態は3日前、とバージョンがずれて、復旧したはずのパイプラインが過去のスケジュールで走り出します。
3つに共通するのは、どれも「バックアップの取得」ではなく「復元の検証」が抜けている点です。取得は静かに成功しますが、復元は実際にやってみるまで成功したことになりません。
月1回の復元訓練を手順にする
そこで私は、復元を年に一度の非常事態ではなく、月1回の定例作業にしました。空のディレクトリから自動運用を組み直し、最初の1本が正しく生成・公開されるところまでを通します。
# restore-drill.sh — 空の環境から自動運用を組み直す訓練
set -euo pipefail
DRILL_DIR="$HOME/restore-drill/$(TZ=Asia/Tokyo date +%Y%m%d)"
mkdir -p "$DRILL_DIR" && cd "$DRILL_DIR"
# 1) 定義層を git から取得
git clone --depth 1 "$DEFINITION_REPO" definitions
# 2) 状態層をストレージから取得(直近のチェックポイント)
mkdir -p state
rclone copy "remote:agent-state/latest" state --checkers 8
# 3) 認証層は秘密管理から注入(値は環境に展開するだけ・ファイルに残さない)
eval "$(secret-cli export --scope agent-automation)"
# 4) 最初の1本を実際に生成して公開直前まで通す
agy run definitions/pipeline.yaml --input state/next.json --dry-run
echo "✅ 復元検証 OK: $(TZ=Asia/Tokyo date +%H:%M)"
--dry-run を付けているのは、訓練で本番へ二重公開しないためです。生成と組み立てまでを本番同等で通し、最後の公開だけを止めます。ここを止め忘れると、訓練が事故になります。
訓練のたびに所要時間を記録すると、復旧設計の良し悪しが数字で見えます。私の初回は2時間かかりました。内訳は、再認証の経路探しに50分、定義のどれが正本か迷うのに40分、残りが実作業でした。経路を手順書に固定し、定義の正本をリポジトリ1つに集約したところ、3回目には25分まで縮みました。短縮幅のほとんどは、作業の速さではなく「迷いの除去」から来ています。
どこまで自動化し、どこを人に残すか
復旧を全自動にしたい気持ちは分かりますが、私は再認証だけは人の操作を残しています。資格情報を完全に無人で復元できる状態は、裏返せば、その仕組みを奪われたら無人で乗っ取れる状態でもあるからです。
判断の基準はシンプルです。失われても痛みが小さく頻繁に変わるもの(状態層)は全自動へ。失われると致命的で滅多に変わらないもの(認証層)は、最後のひと手間を人に残す。この線引きは、利便性と安全性のどちらかに倒すのではなく、層ごとに最適点が違うという前提から引いています。
個人開発で長くアプリを運用していると、AdMob の管理画面や App Store の配信設定など、止まると収益に直結する箇所がいくつもあります。そうした箇所ほど、戻し方を月1回触れておく価値があります。
復元できた、をどう判定するか
訓練を通すとき、最後に「戻った気がする」で終わらせると意味が薄れます。私は復元の成功を、感覚ではなく3つの確認で判定するようにしました。
第一に、最初の1本が品質ゲートを通過すること。第二に、スケジュールの次回実行時刻が正しく計算されていること。第三に、公開記録が状態層と食い違っていないこと。この3つが揃って初めて、復元成功とみなします。
特に三番目は見落としがちな注意点です。状態層を古い時点から戻すと、すでに公開済みの記事を「未公開」と誤認し、エージェントが二重投稿に向かう罠があります。私は一度これで同じ記事を2本出しかけ、公開直前のべき等チェックで止めました。それ以来、復元の最後には必ず公開記録と実体の突き合わせを入れています。
数字でも効果が出ました。この判定を入れる前は、訓練を通しても本番で2割ほど小さな食い違いが残っていました。3つの確認を必須にしてからは、本番投入後の手直しがほぼゼロになっています。判定を厳しくするほど、復元そのものより事後の手直しが減るのだと実感しています。私としては、戻す速さより先に、戻ったと言い切れる基準を決めることをお勧めします。
次の一歩
まずは自分の自動運用を3層に分けて書き出すところから始めてください。認証・定義・状態の3列に、いま何がどこにあるかを並べるだけで、守れていない層が浮かび上がります。私の場合は状態層がまるごと抜けていて、それが冒頭の朝につながっていました。書き出したら、次の週末に一度だけ、空のディレクトリから戻す訓練を通してみてください。初回の所要時間が、あなたの復旧設計の現在地です。