マージ時点の並列エージェント:意図の競合とCIの壁(2026)
- ワークツリーによる分離を生き延びる3つの失敗モードを挙げ、gitのマージがきれいに通ることが2つのエージェントの計画が両立する証拠にならない理由を説明する
- 調整プロトコルの実際のルールを読む:セマンティックスコープ、保存的な操作と非保存的な操作、そしてForemergeが備える5つの競合ルール
- 検出経路があえて決定論的でモデルを含まない理由と、クレームがロックではなく助言的なリースである理由を理解する
- Linearが実測した前後の数字を使って、自分のCIの本当のクリティカルパスを見つける:長いテストシャードではなく、短いゲートジョブである
- シャーディング税を知る:シャード数を倍にしても実時間が半分にならない理由と、先に安くしなければならないもの
2026年9月21〜22日、2つの記事が1日違いでHacker Newsのトップページに載った。1つはLinearのエンジニアリング記事で、タイトルは*「AI coding has made CI a bottleneck, so we reworked ours to keep up」*。もう1つはForemergeのShow HNで、売り文句は「コードの競合の前に、意図の競合を捕まえる」だ。
両者は同じことを反対側の端から描いている。エージェントによって、diffを作ることはほぼ無料になった。diffより下流のすべて、つまりそれが正しいと証明すること、そして他のエージェントがいままさに書いている4つの他のdiffと両立すると証明することは、相変わらず従来どおりのコストがかかる。だから行列ができるのはそこだ。
AILmanacはこの問題の人間側の半分をすでに検証のボトルネックで、ファイル単位の分離をGitワークツリーで扱っている。このページはその間にある仕組みを扱う。複数のエージェントが1つのリポジトリで同時に作業すると何が壊れるのか、そして実際に何をすべきか。
Part 1 — Gitはdiffを比較する。計画は比較できない。
ワークツリーは、各セッションに専用のディレクトリと専用のブランチを与える。それが解決するのはちょうど1つの問題、つまり2つのプロセスが同時に同じファイルに書き込むことだ。より高くつく失敗、すなわち同時には成り立たない2つの計画には何の役にも立たない。
Foremergeの作者が挙げる典型例はこうだ。あるセッションがPaymentServiceをStripe専用の実装に置き換え、別のセッションが元の抽象化の上にPayPalのサポートを追加した。Gitは両方のブランチをきれいにマージした。ところが2つ目の変更は、1つ目が削除した拡張ポイントに依存することになった。
マージの仕組みのなかに、これを捕まえられるものはなかった。マージの仕組みは、どちらのエージェントが何をしようとしていたのかを知らないからだ。
| 失敗モード | 見え方 | 分離が役に立たない理由 |
|---|---|---|
| 破壊的 vs 追加的 | エージェントAが、エージェントBが拡張しているものを置き換えるか削除する | 両方のdiffは異なる行、場合によっては異なるファイルに触れている。マージはきれいだが、設計は壊れている |
| 重複作業 | 2つのエージェントが同じ問題を別の角度から解く | どちらのブランチも競合しない。二重に支払い、さらにそれを調整するために再び支払う |
| 契約のドリフト | 1つのエージェントがAPI、スキーマ、設定を変更し、別のエージェントが古い形に対してコードを書く | コンパイルは通る。出荷もされる。実行時に失敗する |
作者は、2つのジョブが「同じマッチングスキーマを反対側から並べ替え始めた」本番での事例を報告しており、データ損失が表面化したのは3日後の本番だったという。これがこのバグクラスの形だ。マージ時には静かで、後になって高くつく。
- ワークツリーはファイルを分離する。マージキューは統合を直列化する。どちらのレイヤーにも意図の表現がないため、2つの計画の間にだけ存在する競合を検出できない。
Part 2 — 調整レイヤーは実際に何をするのか
**Foremerge**は、検討する価値のある具体例だ。採用すべきだからではなく、その設計判断が、チームがこの問題を社内で解こうとすれば必ず突き当たるものだからである。Apache-2.0、Rust製、リポジトリは2026年8月21日に開設、9月18日時点でv0.4.3、9月22日時点で491スター。
考え方はこうだ。エージェントは、何かをする前に、これから何をするかを機械が比較できる形で宣言する。同時には成り立たない2つの計画は、マージの場ではなく、問い合わせ可能なストアの中で衝突する。
ファイルパスではなくセマンティックスコープ
スコープは小さな構造化オブジェクトで、パスではなく、種別、キー、操作から成る:
{ "kind": "symbol", "key": "PaymentService", "operation": "replace" }
認識される種別:symbol、api、schema、config、infra、test、migration、env、file、component、contract、domain。種別とキーはどちらも、正規化された比較のために小文字化される。
肝心な区別は操作にあり、これは自分でこれを設計しようとしたとき、ほとんどの人が間違える部分だ:
- 保存的 —
add、extend、modify。このものに依存する他のものは動き続ける。 - 非保存的 —
replace、remove、rename、migrate。動き続けない。
この二値分類だけが、「2つのエージェントがPaymentServiceに触れた」(役に立たず、しょっちゅう起こる)を、「一方のエージェントが、もう一方が土台にしている拡張ポイントを削除しようとしている」(対処可能)に変える。
5つのルール、挙動のまま
| ルール | 発火条件 | 重大度 |
|---|---|---|
| FM-C001 破壊的 vs 追加的 | 重なるスコープで、一方が非保存的、もう一方が保存的 | 両方の操作が明示的に宣言されていればHIGH、推論されたものならMEDIUM |
| FM-C002 分岐する書き換え | 同じスコープで両方が非保存的 | HIGH(確定)/ MEDIUM(提示)— まずどの設計を目標にするか選ぶようエージェントに求める |
| FM-C003 共有契約 | 重なるスコープで両方が保存的 | MEDIUM、確定されることはない — 調整メモであり、変更は十分に両立しうる |
| FM-C004 重複作業 | 要約の類似度(トークン化、CamelCase分割、ストップワード除去)でJaccard ≥ 0.62、または操作が一致しスコープが重なり0.42超 | MEDIUM、確定されることはない |
| FM-C005 重複するクレーム | 同じ正規化スコープに既にアクティブなクレームがある | MEDIUMのソフトな警告 — 新しいクレームは作成される |
そこには、このツールを一度もインストールしなくても盗む価値のある細部が2つある。第一に、正規化されたスコープが完全に一致した場合のみ、所見を確定(assert)できる。推論されたもの、ゆるい一致のものはMEDIUMに格下げされ、提示(surface)されるだけだ。第二に、HIGHの所見を上書きするには空でない文章による正当化が必要になる。抜け道はあるが、記録が残る。
3つの意図的な拒否
- クレームは秒単位のリース期間を持ち、排他的な所有権にはならない。理由は運用上のものだ。クラッシュしたエージェントが1つ強いロックを握ったままだと、フリート全体が止まる。放棄された作業は自然に期限切れになる。脅威モデルは、敵対的なエージェントではなく、誤りを犯しうるエージェントだと明記されている。
- 競合検出は決定論的でヒューリスティックだ。同じ入力なら、毎回同じ答えになる。作者の主張はこうだ。実行のたびに判断を変える判定者は、このレイヤーが提供すべき信頼をまさに破壊する。また、競合ルールを単体テストできることも意味する。LLMの審判ではそれができない。
- マージキューは明示的にスコープ外で、Gitホストが担う。これはコード以前のレイヤーであり、コードレビュー、CI、アーキテクチャガバナンスの代わりにはならない。
状態の置き場所 — 優雅な部分
状態は、WALモードのSQLiteファイル1つで、.git/foremerge/state.sqlite3にある。サーバーなし、デーモンなし、インフラなし。そして、リポジトリのすべてのワークツリーはすでに共通のGitディレクトリを共有しているので、ワークツリー間で共有される調整状態は無料で手に入る。分離を可能にしたものが、そのまま調整も可能にする。
Claude Codeセッションのフリートに組み込む
# install + initialise coordination in the repo curl -fsSL https://foremerge.com/install.sh | sh foremerge init foremerge setup all # wires the agent clients (Claude Code, Codex, Cursor) over MCP # what an agent does before it writes a line of code foremerge intent publish foremerge work claim foremerge changeset accept
誰にも工学的に解消できないコンプライアンス問題
このプロトコルは、エージェントが実際に意図を公開してはじめて機能する。MCPが介在していれば、意図の宣言はエージェントのループにおける単なるもう1つのツール呼び出しにすぎず、他のMCPサーバーと同じ仕組みであるため、遵守率は高いと作者は主張する。Foremergeは、publish_intent、publish_changeset、run_verificationを含む18のライフサイクルツールをこの方法で公開し、セットアップ時にネイティブスキルをインストールする。
MCPがなければ、遵守はシステムプロンプトでモデルを説得できる範囲に依存する。つまり、フリートが忙しくなったまさにその瞬間に当てにならない。
- 公開されたベンチマークはまだなく、検証コマンドはサンドボックス化されておらず、プロジェクトは1.0前で、執筆時点で生後3週間だ。プロトコルを教訓として、バイナリは実験として扱うこと。
- 調整レイヤーは、すべてのエージェントのループに1ステップを追加する。フリートが2セッションなら、そのオーバーヘッドは見合わない。ワークツリーと短命ブランチの方針のほうが依然として優れている。
Part 3 — CIの壁、数字とともに
では反対側の端へ。Linearのエンジニアリングチームは、エージェントが生産的になったときに何が起こるかの算術を公開した。テストスイートは年初から4倍近くになり、週に約2,000件のテストのペースで増えている。
彼らの正直な見出しはこうだ。以下のすべての取り組みを経て、プルリクエストの待ち時間の中央値は6分超から5分強になった。最適化がなければ、同じスイートは今ごろ開発者をおよそ11分待たせていただろう。この捉え方こそが本当の教訓であり、労力の大半は、倍に膨らむスイートに対して現状維持を買うために使われたのだ。
クリティカルパスは短いジョブである
直感は、長いテストシャードを最適化せよと言う。計測は逆を示す。すべての実行は、PRがどのパスに触れたか、そして同じ入力に対してそれらのテストがすでに通っているかをチェックするゲートジョブから始まる。8つのAPIテストシャードは、これらが終わるまで1つも開始できない。つまり、小さなジョブで数秒を失えば、下流のすべてのジョブが同じ数秒を失う。
| ゲート作業 | 前 | 後 |
|---|---|---|
| 変更検出、最も遅い実行 | 138 s | 37 s |
| 変更検出、中央値 | 26 s | 8 s |
| 最も遅いゲートでのチェックアウト | 94 s | 20 s |
| チェックアウトが一切ないゲートジョブ | 27 s | 7 s |
| APIプルリクエストあたりのマージパス短縮 | — | 42 s |
具体的な工夫が2つある。変更検出には、履歴を限定したスパースでblobなしのチェックアウトで十分だった(さらに約11秒短縮)。そしてactions/checkoutは、バックオフ付きでリトライし、GIT_HTTP_LOW_SPEED_LIMIT / GIT_HTTP_LOW_SPEED_TIMEを設定するコンポジットアクションに置き換えられ、停止した接続が実行をハングさせずに約30秒で中断されるようになった。
次に、盤上で最も安い勝ち筋:7つの独立したチェックが、それぞれ数秒の実作業のためにランナーを起動し、リポジトリをチェックアウトし、依存関係をインストールしていた。これらをバッチ化することで、**月あたり約8万7,000ランナー分、CI総使用量の11.8%**を節約した。
- 最も遅いジョブを最適化すると、テールが短くなる。ゲートジョブを最適化すると、全員の待ち時間が短くなる。テストスイートに手を付ける前に、クリティカルパスを計測すること。
セットアップのオーバーヘッドが、どこまでシャードできるかを決める
シャード数を倍にしても実時間は半分にならない。各シャードがセットアップを再び支払うからだ。Linearが4シャードから8シャードに移行できたのは、シャードごとのセットアップが安くなってからだった:
| セットアップ項目 | 前 | 後 |
|---|---|---|
| シャードごとのセットアップ | 110–140 s | 67–73 s(−44%) |
pnpm install | 44–73 s | 16–18 s |
| データベースセットアップ(スナップショット) | コンテナあたり12 s | コンテナあたり1–2 s |
成果:4シャードではセットアップが合計8.3分を消費していた。削減後は、合計セットアップ7.5分で8シャードを動かせた。より少ない総オーバーヘッドで、より多くの並列性が得られた。クリティカルなジョブは、およそ19%高速化し19%安くなり、最も遅いシャードは5.25分から4.33分に、APIシャードの合計ランナー時間は実行あたり32.8分から22分になった。
ルールを書き換える前にツールを替える
最大の個別の成果は、気の利いたものではなかった。遅い実装を、同じ仕事をする速いものに置き換えたのだ。
| 変更 | 測定された効果 |
|---|---|
| GitHubホストのランナー → サードパーティのランナー | ジョブは平均34%高速化。tscワークロードは**−52%** |
tsc → tsgo | TypeScriptチェックの週次中央値が**−73%** |
| 型を考慮するカスタムlintルール → ASTのみの静的解析 | APIのlintが**−68%、リポジトリ全体のlintが−55%**(Oxlintによるさらなる削減を除く) |
isolate: falseのVitestオプトインプロジェクト | シャード時間が300–379 sから約195 s、月間CI費用の約**17%**に相当 |
最後のものは、ただでもらえるものではなく、本物のトレードオフだ。分離をオフにすると、安全なテストファイルが各ワーカー内でモジュールレジストリを共有できる。プロジェクトごとのオプトインなのは、まさにモジュール状態を書き換えるテストが、隣のテストを汚染するようになるからだ。テストは速くなるが、保証は弱くなる。意図して決めること。
スレッドからの反論
Hacker Newsの議論は前提をそのまま通さなかった。その異論は携えておく価値がある:*エージェントが週に2,000件のテストを追加しているからといって、2,000件分のシグナルが増えているとは限らない。*複数のコメント投稿者が、エージェントが価値の低いテストを非効率な方法で大量に書くと述べており、それはCIコストを永遠に膨らませ、将来の変更を難しくする。そうしたテストはすべて、後のリファクタリングが満たすか削除しなければならないものだ。
CIを19%高速化するために四半期を費やす前に、スイートの一部がそもそも存在すべきかを問う価値がある。本当の理由で失敗することのないテストは、純粋な保有コストである。
今週やること
- 過去30日間の、PRを開いてから全チェックがグリーンになるまでの時間の中央値を取る。次にそれを分解する:実作業が始まる前のゲート/セットアップがどれだけで、実際のテスト実行がどれだけか。ほとんどのチームは一度も見たことがなく、その比率に驚く。
- それぞれが、ランナーの起動、チェックアウト、依存関係のインストールを丸ごと支払っている。1つのジョブにバッチ化する。通常これが得られる最大のコスト削減であり、午後1つで終わる。
- 高価な部分、つまり依存関係のインストールやデータベース作成をキャッシュまたはスナップショット化する。それからシャード数を増やし、再計測する:総セットアップが、実行時間の短縮より速く増えるなら、一歩行き過ぎている。
- より速い型チェッカー、ASTのみのlinter、より速いランナー。これらはセマンティクスもルールも変えないので、レビューのコストはほぼゼロで、元に戻すのも容易だ。
- 並列エージェントが2つなら:ワークツリーと短命ブランチ。1つのコードベースで5つ以上なら:コードの前に宣言された計画(スコープ+操作)を必須にする。Foremergeのようなプロトコルでも、共有タスクファイルでも、設計を所有するリードエージェントでもよい。場当たり的な運用は、この移行を生き延びない。
- CLAUDE.mdまたはAGENTS.mdで、どんなときにテストを書かないかについて、エージェントに明示的な指示を与える。そうしないと、CIコストはエージェントの出力に比例して永遠に増え続ける。
Claude Codeで自分のクリティカルパスを監査する
Read our CI configuration under .github/workflows (or the CI config in this repo). Produce a table of every job with: does it block other jobs, its typical duration, and whether it starts a runner + checkout + dependency install to do less than 30 seconds of real work. Then answer three things: 1. Which jobs are on the critical path before any test can start? 2. Which short jobs could be batched into one, and what would that save? 3. Where does the same expensive setup step (dependency install, DB creation, checkout) get repeated across jobs that could share a cache or a snapshot? Do not change any files. Output the table and the three answers only.
覚えておきたい用語
理解度チェック
0/7- ワークツリーはファイルを分離するが、互いに矛盾する2つの計画は検出できない。分離を生き延びる3つのものは、破壊的 vs 追加的の衝突、重複作業、契約のドリフトである。
- 調整レイヤーは、エージェントにコードを書く前にスコープ(種別、キー、操作)を宣言させることで機能し、その操作における保存的 vs 非保存的の区別が、検出をノイズではなく対処可能なものにする。
- 検出経路は決定論的に、クレームは助言的に保つ。再現できない判定者は信頼を破壊し、強いロックはクラッシュしたエージェント1つをフリートの停止に変える。
- 自分のCIのクリティカルパスはおそらく、長いテストシャードではなく短いゲートジョブだ。Linearの変更検出ゲートの中央値は26 sから8 sになり、7つの小さなチェックのバッチ化でCI総使用量の11.8%を節約した。
- シャーディングにはセットアップの税がかかる。まずシャードごとのセットアップを削り、次にシャードを増やし、それから再計測する。
- ツールの差し替え(tscチェックでtsgoが−73%、ASTのみのlintが−68%、サードパーティランナーが−34%)はセマンティクスを変えず、手に入る最も安い勝ち筋だ。
- 上限なしにテストを生成するエージェントフリートには、これらのどれも追いつけない。それらを実行するスイートを最適化する前に、CLAUDE.mdまたはAGENTS.mdでテスト生成に上限を設けること。
出典と参考文献
- AI coding has made CI a bottleneck, so we reworked ours to keep up — Mufeez Amjad、Linear、2026年9月21日。このページのCIの数値はすべてここから。
- Linearの記事に関するHacker Newsの議論 — テスト量に関する反論を含む。
- naw103/foremerge — Apache-2.0、Rust。プロトコルオブジェクト、CLI、MCP連携。
- foremerge/docs/protocol.md — スコープの種別、保存的 vs 非保存的の操作、リースのセマンティクス、オブジェクトのライフサイクル。
- foremerge/docs/conflict-detection.md — FM-C001からFM-C005のルールとその重大度。
- Parallel coding agents without the carnageと31 hard questions about coordinating parallel coding agents — 作者による失敗モードの解説記事。
- Show HN: Foremerge — 2026年9月22日。
- Gitワークツリーのドキュメント — これらすべての下にある分離レイヤー。
次へ
- Gitワークツリーと並列ワークストリーム — このページが載っているファイル分離レイヤー
- サブエージェントフリートの上限 — 調整コストが支配的になる前に、実際に何個の並列エージェントを動かせるか
- 検証のボトルネック — 同じ問題の人間側の半分:フリートが生み出したものをレビューすること
- エージェントが書いたコードのためのCI/CD — マージキューの算術と、エージェントが自分の宿題を採点するのを止めるゲート