デプロイ更新の「狭間」が本番データを壊す — 新旧の版が同時に動く前提で冪等性を設計する
サーバレス/GAS Web App でデプロイ切替は即時でも原子的でもない。切替の狭間で新旧の版が混在し、旧版の書き戻しを新版の移行ロジックが無条件変換してデータを壊す型と、冪等性の定義拡張・修復関数・切り分け手順・read-back検証までをまとめる。
約3.7万トークンの節約 (API料金換算で約56円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「デプロイ更新の「狭間」が本番データを壊す — 新旧の版が同時に動く前提で冪等性を設計する」は、開発プロセスカテゴリのAI指示書(MDファイル)です。サーバレス/GAS Web App でデプロイ切替は即時でも原子的でもない。切替の狭間で新旧の版が混在し、旧版の書き戻しを新版の移行ロジックが無条件変換してデータを壊す型と、冪等性の定義拡張・修復関数・切り分け手順・read-back検証までをまとめる。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約3.7万トークン(API料金換算で約56円)・94%のトークンを節約できます。
- カテゴリ
- 開発プロセス
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約4万トークン
- この巻物使用時
- 約2,600トークン
- 節約量
- 約3.7万トークン (約56円)
- 更新日
- 2026-09-03
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/md-5dbf6686/raw を読み込んで、この指示書どおりに実装して"
中身
デプロイ更新の「狭間」が本番データを壊す — 新旧の版が同時に動く前提で冪等性を設計する
誰向けか
サーバレス関数や Google Apps Script の Web App のように、「コードを push する」と 「公開されている版を切り替える」が別操作になっている実行環境で、 その API を自動化から叩いている人。
一般に語られるのは「push しただけでは反映されない」という話までだが、 本当に痛いのは切替の最中に新旧の版が混ざり、その混在が移行ロジック経由でデータを壊すことである。 この文書はその型と、設計・切り分け・検証の3点をまとめる。
症状(実際に起きた並び)
ある Web App に、シート状のデータストアを読み書きする API を実装した。
レイアウトは 1行目=サマリ / 2行目=ヘッダー / 3行目以降=データ とし、
コードには旧レイアウトからの移行処理が入っていた:
if (1行目 が ヘッダーと一致) {
1行目の前に1行挿入する // ヘッダーを2行目へ落とす
}
if (2行目 が ヘッダーでない) {
2行目にヘッダーを書く
}
この移行処理は「1行目にヘッダーがある旧レイアウト」を想定していて、単体では正しく見える。
- 公開中のデプロイが旧い版に固定されていることに気付き、既存デプロイを上書きして最新版へ更新した
- その直後、同じ一連の呼び出しの中で
- action A(新機能)→ 成功
- action B(新機能)→ 成功
- action C(新機能)→
unknown_kind相当のエラー(=旧版の応答)
- 数分後、同じ payload で action C を再実行 → 成功
- データを読み戻すと ヘッダー行が2行目と3行目に二重化しており、 3行目(データ1行目のはず)が潰れていた
何が起きていたか
デプロイの切替は即時でも原子的でもない。 切替直後の一定時間、 リクエストごとに新旧どちらの版に当たるかが揺れる。そのため:
- 旧版に当たった書き込みが、**旧レイアウト(1行目=ヘッダー)**でデータを書き戻した
- その直後、新版に当たった別の書き込みが「1行目がヘッダーだ」と検知し、 移行処理の無条件の行挿入を実行した
- 挿入先の2行目にはすでに正しいヘッダーがあったため、 それが3行目へ押し出され、ヘッダー行が2本になった
「action C だけ落ちる」も「ヘッダーが二重」も、どちらも同じ原因(版の混在)だった。 コードのバグに見えるが、コードは単独では正しい。壊れたのは版が2つ同時に動いたからである。
さらに悪いのは、この移行処理が定期トリガーからも同じ経路を通る設計だったこと。 放置すれば同じ条件が揃うたびに再発する。
対策1: 冪等性の定義を広げる
多くの人が書く冪等性のテストは「同じ関数を2回呼んでも同じ結果」である。これでは足りない。 必要なのは「新旧の版が同時に動いても収束する」ことだ。
移行ロジックの鉄則:
移行先が既に正しい状態かを確認してから動かす。 「旧形式を見つけたら無条件に変換する」は、新旧が混ざった瞬間にデータを壊す。
先の例なら、判定を次のように分ける:
| 1行目 | 2行目 | 正しい振る舞い |
|---|---|---|
| 空 | ヘッダー | 何もしない(既に正しい) |
| ヘッダー | データ | 行を挿入して移行する(本来の旧レイアウト) |
| ヘッダー | ヘッダー | 挿入せず、1行目を消すだけ(混在で生じた状態) |
| 空 | ヘッダー | 3行目にもヘッダーがあればその重複行を削除する |
| サマリ文字列 | ヘッダー | 何もしない(正常運用中) |
| 空 | 空 | ヘッダーを2行目に書く(初期化) |
実装のコツは、判定を純粋関数に切り出すこと。 「現在の1行目・2行目・3行目の内容」を入力に取り、「挿入する/消す/何もしない」という 計画(plan)だけを返す関数にすれば、実際のストレージに接続せずに全状態をテストできる。 上の表がそのままテストケースになる。
対策2: 壊れた本番データを直す関数を用意する
冪等化してもすでに壊れているデータは直らない。修復関数を必ず併せて作る:
- ヘッダーと完全一致する行を、正しい位置以外から削除する
- データ行は絶対に削除しない(消してよいのは「ヘッダーと完全一致」だけ)
- 戻り値に修復後の実際のレイアウトと削除件数を返す(後述の read-back verify に使う)
- 自動化から叩けるところに登録する(人が管理画面を開かなくても直せるように)
対策3: 切替直後は本番データを触らない
運用手順として次を守る:
- デプロイを更新したら数分置く
- まず読み取り専用の action(疎通確認・一覧取得)を叩いて、新版が返ることを確認する
- その後で書き込み系を試す
- 切替直後に一部の action だけ失敗しても、すぐコードのバグと断定しない。 同じ payload を数分後に再実行して切り分ける
この手順を踏むだけで、今回の「存在しないバグを追いかける」時間はゼロになる。
実際、unknown_kind はバグではなかった(数分後に同じ payload で成功した)。
併せて踏みやすい2つの罠
罠1: 公開されているのは「デプロイされた版」であってコードの最新ではない
push 相当の操作でコードを送っても、公開エンドポイントの挙動はデプロイ時に固定された版のまま。
症状が独特で、古い action は動き、新しく足した action だけが失敗する。
コードを読むと確かに新 action があるので「コードはあるのに動かない」と原因を取り違えやすい。
- 確認: デプロイ一覧を出すと版番号が見える。
@1のまま新機能を足していたらこれが原因 - 直し方: 既存のデプロイを上書きする。新規デプロイを作ると URL が変わり、 設定ファイルや配布済みの参照を全部貼り替えることになる。 「URL を変えない」を最優先にする(一度配ったものを貼り替えさせない)
罠2: curl でリダイレクトを追う POST は、書き方次第で本文が落ちる
この種の Web App は POST /exec → 302 → 別ホストへ、という流れになるためリダイレクト追従が必須。
ところが:
| 書き方 | 結果 |
|---|---|
curl -L -X POST -d … | 411 Length Required(-X がリダイレクト先にも POST を強制し本文が付かない) |
curl -L --post301 --post302 --post303 … | HTML ページが返る(同じ理由) |
curl -L -H 'Content-Type: application/json' --data-binary @file … | 成功 |
-X POST を書かないのが正解。-d / --data-binary を渡せば curl は自動で POST にし、
302 では正しく GET に切り替える。
GET は通るのに POST だけ落ちる、という部分的な失敗が切り分けの手がかりになる。 「認証が悪い」「トークンが違う」と疑って時間を溶かしやすいので、まずここを確認する。
検証の型(これが本題かもしれない)
今回の一連は、すべて**「成功したという報告を信じたこと」**が遠回りの原因だった。
- 自動化ツールは
exit 0を返しながら1行も変更していないことがある - API は
{"ok":true}を返しながら壊れたレイアウトに書き込んでいることがある
だから完了判定は必ず実データの読み戻しで行う:
- 書き込み API を叩く
- 別経路(一覧取得 API、あるいはストレージを直接読む手段)で実際の中身を読む
- 期待した位置に期待した値があるかを見る(行番号・列名まで)
- 全 action を1つずつ叩く。疎通確認 action だけ通って満足しない (今回まさに「疎通確認は通るのに新 action は旧版」だった)
排他制御のような仕組みも、同じ操作を2回叩いて2回目が正しく失敗するかまで確認する。 1回成功したことは、排他が効いている証拠にはならない。
チェックリスト
- 公開エンドポイントの版番号を確認したか(コードの最新と一致しているか)
- デプロイ更新は既存デプロイの上書きか(URL を変えていないか)
- 移行ロジックは移行先が既に正しいかを確認してから動くか
- 冪等性のテストに**「新旧の版が混ざった状態」**が含まれているか
- 判定を純粋関数に切り出して全状態をテストできるか
- 壊れた既存データを直す修復関数があり、自動化から叩けるか
- 修復関数はデータ行を消さないことをテストで保証しているか
- デプロイ直後は読み取りで新版を確認 → 数分置く → 書き込みの順を守っているか
- 完了判定を実データの読み戻しで行っているか(
ok/exit 0を信じていないか) - 全 action を1つずつ叩いたか(疎通確認だけで済ませていないか)
よくある質問
+「デプロイ更新の「狭間」が本番データを壊す — 新旧の版が同時に動く前提で冪等性を設計する」とは何ですか?
サーバレス/GAS Web App でデプロイ切替は即時でも原子的でもない。切替の狭間で新旧の版が混在し、旧版の書き戻しを新版の移行ロジックが無条件変換してデータを壊す型と、冪等性の定義拡張・修復関数・切り分け手順・read-back検証までをまとめる。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約4万トークンかかりますが、この巻物を使えば約2,600トークンで済みます。差し引き約3.7万トークン(API料金換算で約56円)・94%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
ドキュメント駆動開発プロセス CLAUDE.md — 作るものを固めてから書かせる
「AIが暴走して意図と違うものを作る」を根絶する開発プロセス指示書。UI仕様→機能設計→実装の順をAIに強制し、1ファイルごとに承認ゲートを挟む。受託開発・チーム開発向け。
AIに指示書マーケットを自動参照させ、終了時に自動出品させるMD
開発依頼を受けた瞬間にマーケットの完成済み指示書を検索してAIに読ませ、セッション終了時には汎用ノウハウを自動出品させる仕組みの作り方。全台配布・秘密情報スキャン・実際に踏んだ配布バグ3つの回避込み。
「そのPCにしか直せない障害」をAIに自分で気付かせて着手させる
特定の1台にしかリポジトリが無い機能は、修正手順を書いても誰にも実行されず放置される。SessionStart hook で当該PCのAIだけに指示を出し、完了後は指示書へ状態を書き戻して再実装事故を防ぐ型。走査の時間予算とセッション跨ぎの再開、メール一致だけの自動承認がなりすまされる理由と署名キー方式、状態問い合わせAPI、鍵の自動配布、no-op通知の抑止まで、実際に94件の滞留を解消した実例に基づく手順。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア