ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-07-09上級

エージェントが直した .proto がバイナリ互換を壊す前に — buf breaking で wire 互換を門番する

エージェントに .proto を編集させると、テキストとしては正しくても wire 互換を静かに壊すことがあります。フィールド番号の再利用と型変更をどう機械で止めるか、buf breaking と reserved を組み合わせたゲートを動くコードで示します。

antigravity425protobufgrpc2bufapp-dev46

プレミアム記事

エージェントに「この使っていないフィールドを整理しておいてください」と頼んだ翌週、App Store と Google Play で配布している古いバージョンのアプリを使う一部のユーザーからだけ、届く数値がずれているという報告が来ます。個人開発で小さな API を Protocol Buffers で定義していると、これは十分に起こりうる事故です。

diff を見ても、エディタ上では何も間違っていません。フィールドがひとつ消えて、別のフィールドがひとつ増えています。テキストとしては完璧に整理されています。壊れているのは、テキストではなく wire フォーマット、つまりバイト列の互換性のほうです。

Antigravity の 6 月末以降の更新で、マークダウンや diff の描画が C++/Python/Protobuf の構文ハイライトに対応しました。エージェントが提案する .proto の差分が読みやすくなったことは歓迎すべきことです。ただ、読みやすさは互換性の保証ではありません。人間の目で proto の diff を眺めて「大丈夫そう」と判断するのは、最も壊れやすい部分を最も曖昧な方法で守っていることになります。

ここでは、その判断を機械へ肩代わりさせていきます。

エージェントは .proto を「テキストとして」正しく直す

大規模言語モデルは、.proto を構文的に正しく編集することは得意です。使われていないフィールドを消し、命名を整え、コメントを付け直す。ここまでは信頼できます。

問題は、Protocol Buffers の互換性がソースコードのテキストではなく、シリアライズされたバイト列で決まる点にあります。各フィールドはワイヤ上で名前ではなくフィールド番号で識別されます。つまり、フィールド名を変えても互換性は保たれますが、フィールド番号を変えたり再利用したりすると、既存のバイナリは別の意味でそのバイトを解釈します。

エージェントはソースの見た目を最適化しようとします。そのとき、削除して空いた番号を新しいフィールドにあてがうのは、テキスト上はむしろ「きれいな」変更に見えます。しかしこれは、まだ更新していないクライアントに対して、古いフィールドの値を新しいフィールドとして読ませる指示になります。この落とし穴は本番でだけ表面化し、回避するには番号の意味を変えないことが要点になります。

私自身、この線引きを何度か肌で確かめてきました。エージェントに任せてよいのは「意味を変えない整形」までで、「番号の意味を変える操作」は必ず人間か機械の関門を通す。ここを曖昧にすると、テストが通ったまま本番でだけ壊れます。

wire 互換が壊れる典型パターン

事故のかたちはおおむね三つに集約されます。

  1. フィールド番号の再利用
  2. 同じ番号のままの型変更
  3. カーディナリティ(optional/repeated/required)の変更

ひとつめは、フィールド番号の再利用です。フィールド 3 を削除し、あとから別の型のフィールド 3 を足すと、旧クライアントが送ってきた「かつての 3」を新サーバは「新しい 3」として解釈します。

ふたつめは、型の変更です。同じ番号のまま型を変えると、その二つの型がワイヤ上で同じエンコードを共有していない限り、値は静かに壊れます。varint 系(int32/int64/uint32/uint64/bool/enum)は互いに読み替え可能ですが、sint32/sint64 は zigzag エンコードのため int32 とは互換がありません。

みっつめは、optional/repeated のカーディナリティ変更や、required の付け外し(proto2)です。これはメッセージ全体のパースを不安定にします。

型を変えたときにワイヤが壊れるかどうかは、次の対応表で判断できます。

元の型互換のある変更先wire type
int32, uint32, int64, uint64, bool, enum相互に変更可(値域に注意)varint
sint32, sint64相互のみ(varint 系とは非互換)varint (zigzag)
string, bytes相互可(bytes が妥当な UTF-8 のときのみ)length-delimited
fixed32, sfixed32, float相互に変更可32-bit
fixed64, sfixed64, double相互に変更可64-bit

この表を毎回頭に浮かべて diff を審査するのは現実的ではありません。だから機械に持たせます。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
エージェントに .proto を任せたいが、フィールド番号の再利用や型変更で古いクライアントを壊さないか不安だった人が、push 前に自動で門番できるようになります
buf breaking・reserved 宣言・フィールド番号の再利用検出を組み合わせた wire 互換ゲートを、自分の CI とフックに組み込めます
スキーマ変更という壊れやすい領域で「どこまでエージェントに任せ、どこを機械で検証するか」の線引きを具体化できます
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

アプリ開発2026-07-03
ダウンロードサイズの逆行に提出直前で気づかないために — AAB/IPA のサイズ予算をエージェントの週次ゲートで守る
メディエーションSDKやアセットの追加で静かに膨らむダウンロードサイズに、bundletool と App Thinning レポートを使ったサイズ台帳・予算ゲート・増分の内訳特定で歯止めをかける設計をまとめます。
アプリ開発2026-07-02
エージェントにテストを任せる前に決めておく — fixture とシードデータの持ち方
エージェントがテストデータを都合よく書き換えて「通るテスト」を作ってしまう問題への対策として、fixture の所有権・決定的シード・匿名化サブセットの3点を実装例つきで整理します。
アプリ開発2026-06-30
Antigravity が書いたテストが全部グリーンなのに同じバグが再発するとき — 空回りするアサーションを計測する運用メモ
AI に書かせたテストがすべて通り、カバレッジも高いのに本番で同じ不具合が戻ってくる。原因はモック過多とトートロジー的なアサーションです。ミューテーションテストを正解とし、テストが実際に何を守っているかを実測して運用で立て直すメモです。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →