AIコーディングエージェントに本番サーバーを触らせる:効いたガードレール
AIエージェントが一晩で本番サイトとアプリのAPI 8つを移行した。エージェントのミス、それを捕まえたチェック、人間に残した作業の記録。
AIコーディングエージェントは、実際の運用作業ができる水準になりました。サーバーを調べ、移行スクリプトを書き、実行するところまでです。問われているのはもう「本番を触れるか」ではなく、「何が満たされていれば触らせてよいか」です。
2026年11月8日、AIコーディングエージェント(ターミナルで動く Claude Code)が、tlaboratory.net を WordPress から静的サイトへ移し、モバイルアプリのAPIフォルダ8つを /api/v1/ の下へ移しました。本番への各ステップは人間が承認しています。このサイトにはインストール済みのアプリ16本がつながり、ストア掲載24件がプライバシーページを指していますが、停止は1度もありませんでした。この記事はAIの賢さの話ではありません。ガードレールの話と、それがエージェントのミスを5回捕まえた話です。
構成を表で
| ガードレール | 内容 |
|---|---|
| まず読み取り専用で調査 | FTPの一覧、WordPressのREST API、curl、そしてアプリ20本のソースからサーバーURLを全部拾うサブエージェント |
| 書面の計画を承認してから編集 | フェーズ、ロールバック、触ってはいけないもの(広告設定API、スマートリンク) |
| 最初の書き込み前に全バックアップ | APIフォルダ・ストア用ページ・.htaccess の1,067ファイル(19MB) |
| レスポンスのベースライン | APIエンドポイント95件のステータス・ヘッダー・本文ハッシュ |
| 既定はドライラン | デプロイスクリプトは「何をするか」を表示するだけ。実行には --go が必要 |
| 許可リストと「他人のファイル」停止 | ブログ外のパスを拒否し、自分がアップロードしていないファイルは上書きしない |
| 本番サーバー上の使い捨てサンドボックス | リライトは一時サブフォルダで試し、finally で削除 |
| 段階的な切り替え | まずAPI1本、23分後に残り7本 |
| 人間だけが行う作業 | 文面の承認、切り替え時刻、CDN削除、Search Console、実機確認 |
どれもAI特有のものではなく、慎重な新人に求めることと同じです。違うのは、エージェントがこれらの道具の大半を危険な作業の前に自分で書き、それを通過しなければ先に進めなかったことです。
捕まえた5つのミス
1. コードブロックの空白が黙って変わった(31記事)
エージェントはWordPressの67記事をMarkdownに変換しました。変換器は行末の空白を削り、連続する空行をまとめていたのですが、それをコードブロックの中にも適用していました。画面上は何も変わって見えません。479個のコードブロックをWordPressの原文とバイト単位で比べる検証スクリプトが、次のように報告しました。
MISMATCH 1190 16 16
'using System;\nusing System.Collections.Generic;\n\n\nusing System.Linq;...'
'using System;\nusing System.Collections.Generic;\n\nusing System.Linq;...'
...
code blocks 479 posts mismatched 31
整形をコードフェンスの外だけに限定して再実行し、不一致は0件になりました。検証スクリプトはリポジトリに残しています。
2. リライトルールのスペースを二重エスケープ
ルール生成器はスペースを \ ではなく \\ にしていました。登録済みのストアURLを全部、生成したルールに当てるシミュレーションで発覚しました(シミュレーター自体もそのパターンで落ちました)。そのまま出していれば、あるアプリのiOSサポートURLが一致しなくなっていたところです。どの設定パーサーでも解釈が揺れない \s に変えました。
3. 表記ゆれの片方にルールがない
あるストア掲載はページを US Lottery Infomation(大文字・スペース)で登録し、WordPressは us-lottery-infomation を使っていました。生成器はこれを同じページと見なし、片方の形にしかルールを出していませんでした。WordPressの旧URL196件すべてについて「最初に一致するルールが正しい行き先か」を確かめるチェックが、この抜けを見つけました。スペースの位置を [\s-] にして解決しました。
4. 自己矛盾したプレビュービルド
ローカルのプレビューは全ページを noindex にする一方で、それらを載せたサイトマップを出力していました。コンテンツ検査が「noindexなのにサイトマップにある」を38件指摘しました。ローカルでは無害ですが、検索エンジンが嫌うシグナルそのものです。プレビューではサイトマップを出さないようにしました。
5. コメントをコードと誤認
101ファイルのPHPのincludeを書き換える途中で、lib/AppConfig.php の記述が残っているとして安全チェックが停止しました。中身はコメントでした。ガードレールが厳しすぎた例ですが、失敗するならこの方向が正解です。対象を実際の require/include 文に絞りました。
5つに共通するのは、ミスをしたのはエージェントで、それをサーバーより先に捕まえたのもエージェントが書いたチェックだったことです。検証の仕組みを先に作らせる理由はここにあります。
エージェント自身の権限機能が一度「ノー」と言った
途中でエージェントは設定を比べるため、別プロジェクトの .env を読もうとしました。そのファイルにはデータベースのパスワードが入っていました。ツールの権限機能はこれを認証情報の露出として拒否し、エージェントは方法を変えました。DB設定ファイル10個を読むのではなくハッシュで比較し、「これらは同一か」という本当の問いに、秘密を表示せずに答えたのです。
5ae45e5d7d2f3e0c15e99acf1b40d61c Converters/lib/AppConfig.php
5ae45e5d7d2f3e0c15e99acf1b40d61c DreamApp/lib/AppConfig.php
...(10個すべて同一)
本番を危険にさらさずに本番で試す
共有サーバーにステージング環境はありません。代わりにエージェントは rwtest.py を書きました。/_rwtest_YYYYMMDD/ を作り(すでにあれば中止)、そのフォルダ内だけに効く .htaccess を置いてリクエストを流し、finally で全部消します。実行は4回です。URL照合の挙動の確認で15/15、生成したルートファイル全体をサンドボックス用に書き換えた確認で12/12を3回。最後の確認によって、ドメイン配下のアプリAPIをすべて落としかねない構文エラーがないことを、本番に置く前に確かめられました。
人間が欠かせなかったところ
- 法的な重みのある文面。 プライバシーポリシーは16本のアプリを対象にしています。エージェントは、
pubspec.yamlのSDK、Info.plistとAndroidManifest.xmlの権限という各アプリの実際の中身から文面を組み立てました。それでもアップロード前には人間の承認が必要でした。アップロードした瞬間に、24件のストア掲載が表示する内容が変わるからです。 - タイミングと影響範囲。 切り替え時刻と、API1本を先に単独で移すという判断。
- 管理画面でしかできないこと。 CDNの削除、Search Consoleへのサイトマップ登録、スマホでアプリを開くこと。
- 個人情報。 エージェントが最初に作った「運営者情報」ページは、運営者を国籍と居住地で紹介していました。人間が削除を頼むと、エージェントは同じ情報が著者ボックス、トップページ、プライバシーポリシー、構造化データにもあることを見つけて、すべて取り除きました。
まとめ
- 変更より先に、ベースラインと検証スクリプトをエージェントに作らせる
- スクリプトの既定はドライランにし、危険な操作は明示的なフラグにする
- ステージングがなければ本番環境の中にサンドボックスを用意する。デコード後のURL照合やCDNのAPIキャッシュのような本番特有の癖は、そこでしか見えない
- 段階的に切り替え、ロールバックはコマンド1つにしておく
- 承認・タイミング・法的な判断は人間が持つ
作業自体は数時間で終わりました。その数時間を任せられたのはガードレールのおかげで、その大半は次の変更でも再利用できます。
よくある質問
AIエージェントはミスをした?
はい、本番に届きかねないミスが5つありました。31記事のコードブロック内の空白を変えた、リライトルールのスペースを二重エスケープした、URLの表記ゆれを1つ取りこぼした、矛盾したサイトマップを生成した、コメントを誤検知した、の5つです。どれも、エージェントが変更前に書いたチェックで捕まえました。
人間に残すべき作業は?
外部に影響する判断です。24件のストア掲載が指すプライバシーポリシー文面の承認、切り替え時刻、CDNのキャッシュ削除、Search Console、実機での確認。本番への変更は毎回エージェントが事前に確認を求めました。
いちばん役に立ったガードレールは?
変更前に取ったレスポンスのベースラインです。以後のすべての手順をそれと比べたので、「たぶん大丈夫」が基準になることはありませんでした。