複数のChatGPTに同じシステムを開発させたら、普通に衝突した

連載「ChatGPTと育てる、自分専用AI基盤」第9回。複数のChatGPTが並列開発し、Control Planeを介して分離されたWorkspace A・B・Cへ安全に接続する構成を描いた水彩画調サムネイル。 AI

※「ChatGPTと育てる、自分専用AI基盤」Season 1 第9回です。

第8回までで、1つのRunの中ではGoal、Success Criteria、Evidenceを見ながら、次に何をするかをAIが選べるようになりました。

第8回:作業自動化と「自律するAI」は何が違うのか

ここまで来ると、次に考えることは自然です。

1つのAIで順番にやるより、複数のChatGPTを同時に動かした方が速いのでは?

実際、速くなりました。

そして、普通に衝突しました。

最初にぶつかったのは同じworking treeです。次にmainへのmergeやdeployのような共有状態。そして最後には、技術的には触れるけれど「それは別Chatの仕事では?」という責任範囲まで衝突しました。

並列化で必要だったのは、モデルを増やすことだけではありませんでした。

どこで作業し、何を共有し、誰がその仕事を進めてよいかを管理するcoordination layerが必要でした。

最初は、同じrepositoryを複数Chatから触っていた

ChatGPTからDevelopment MCPを使えるようになった当初、repositoryは一つです。

Chat AがLoop Engineを修正する。Chat BがPublishing MCPを修正する。Chat Cが別のfeatureを進める。

対象ファイルが違えば、何となく同時に進められそうに見えます。

でもGitのworking treeは一つです。

別Chatが未commitの変更を残している状態で、こちらがgit statusを見ると、その変更も見えます。さらにそのままcommitすれば、自分の変更と別Chatの変更を一緒にcommitする危険があります。

実際に、別Chatで進めていたPublishing MCPの未commit変更がcanonical working treeに残っている状態へ、別の開発作業が入ろうとしたことがありました。

これはかなり怖い。

ファイルが違うかどうか以前に、作業場所そのものを分ける必要があると分かりました。

isolated workspaceを作った

そこで、タスクごとにisolated workspace / worktreeを持つようにしました。

Chat A
  → Workspace A

Chat B
  → Workspace B

Chat C
  → Workspace C

それぞれが独立したbranchとworking treeを持ちます。

これならChat Aの未commit変更はChat Bから見えません。Chat Bが失敗しても、Chat Cのworking treeは汚れません。

単純ですが、複数Chatを本当に並列で動かすにはかなり重要でした。

Workspaceを分けても、同じcomponentを触れば危ない

ただしWorkspaceが別なら何でも並列にしてよいわけではありません。

たとえば、Workspace AとBが別でも、両方がservices/loop-engineを大きく変更していたら、最後にmergeする時に衝突します。

そこでcomponent leaseを持たせました。

「このWorkspaceは、いまこのcomponent scopeを担当している」という情報をControl Plane側へ残します。

別のWorkspaceが同じscopeを取ろうとしたら、少なくともその事実を認識できます。

これで、単なるGit conflictだけではなく、作業開始前に意味的な重複を避ける方向へ進みました。

並列開発しても、mainへのmergeは並列にできない

ここで別の問題が出ます。

Workspace AとBが完全に別componentだったとしても、両方が同じmainへmergeします。

たとえば3本のPRを同時に準備しました。

全部、同じmain SHAをbaseにしています。

PR Aをmergeすると、mainが進みます。

するとBとCが持っていた「このbaseから確認した」という証拠は古くなります。

実際、3 PRを並列に作ったdogfoodでは、最初の1本をmergeしただけで、残り2本のmerge previewがstaleになりました。

コードが競合していなくてもです。

ここで分かったのは、

開発作業は並列化できても、共有状態の変更は直列化しなければならない

ということでした。

mainへのmerge、candidate deploy、production mutationなどはshared mutationとして一つずつ通します。

「さっき安全だった」は、並列環境ではさらに危ない

第4回から、exact HEADやstale-state rejectionは使っていました。

第4回:ChatGPTからPRを作り、安全にマージできるようにした

並列化すると、この原則がさらに重要になります。

別Chatがmainを進める。別Workerがcandidateを更新する。PRのstatusが変わる。Leaseが取られる。

Vaultに「PR-ready」と書いてあっても、今もPR-readyとは限りません。

だから、重要な操作の前には、記録だけでなくlive stateを読み直します。

Vault
  → なぜそうしたか、要件、判断、履歴

SQLite / Run state
  → いま仕事がどこまで進んでいるか

Git / GitHub
  → 実際のcode / PR / HEAD

Runtime
  → 実際に何が動いているか

どれか一つを万能な正本にはしません。

特に現在状態はlive stateを優先するようになりました。

それでも防げなかった「責任」の衝突

Workspaceを分けた。component scopeも分けた。shared mutationも一つずつにした。

これでかなり安全になりました。

それでも、別の種類の問題が起きました。

2026年8月21日、主開発Chatがlive stateを確認すると、別Chatが所有しているPublishing MCPのworkspaceがactiveであることを見つけました。

技術的な競合はありません。

そこで主開発Chatは、「Production側も進められる」と判断し、その別Chatの仕事まで継続しようとしました。

私はログを見ていて違和感を持ちました。

「Publishing MCPの開発は別Chatでやっているけど、それも今ここで進めようとしてる?」

確認したところ、その通りでした。

幸い、追加実装、PR、merge、deployへ入る前に止められました。

この出来事は単独記事にもしています。

AIが別のChatの仕事まで進めそうになった話

「触れる」と「担当してよい」は別だった

この時、既存の安全機構はかなり正常でした。

Workspaceは別です。component conflictもない。Runnerもidle。mainも確認できます。

つまり、技術的には進められます。

でも、別Chatには別の会話があります。

そのChatで私と決めた方針。途中の判断。まだコードに出ていない前提。次に何をしようとしていたのか。

Workspaceだけ見ても、全部は分かりません。

そこで、workspace ownershipを明示するようにしました。

別ownerのactive workspaceは、原則observability-onlyです。

状態は見える。競合チェックにも使う。main driftにも対応する。

でも、明示的なhandoffがなければ、その仕事自体は引き継がない。

つまり排他制御の対象が、file、component、mainから、最後には責任まで広がりました。

Leaseにも、いくつか種類が必要だった

この頃には「lease」という言葉が何種類も出てきます。

Run leaseは、同じRunを複数Workerが同時に処理しないためのものです。

Component leaseは、同じ開発scopeを複数Workspaceが同時に触らないためのものです。

Shared mutation leaseは、mainやdeployのような共有状態を同時に変えないためのものです。

Workspace ownershipは、その仕事を誰が進める責任を持つかです。

似ていますが、守っているものは違います。

第7回でRun leaseを作った時は、二重実行を防ぐためでした。

第7回:AIが途中で止まっても、続きを再開できるようにした

並列化すると、それを仕事・コード・共有状態・責任の各層へ広げる必要がありました。

並列化は「複数のAIを起動する」ことではなかった

実際にやってみて、並列AI開発の難しいところはモデルではないと感じました。

ChatGPTを3つ開くこと自体は簡単です。

難しいのは、3つが同じ世界を触ることです。

誰がどこを触っているか。

どの状態が最新か。

何が同時に変更可能か。

誰がその仕事を担当しているか。

これを管理できなければ、人数を増やすほど危険になります。

人間の開発チームに似ています。

机を分ける。担当を決める。共有branchの変更は調整する。他人の作業を勝手に引き継がない。

AIを増やすと、結局「組織」の問題が出てきました。

そして次のボトルネックは、人間だった

Workspaceを分け、Leaseを入れ、shared mutationを直列化し、ownershipまで決める。

ここまで来ると、複数Chatでの開発はかなり安全に回るようになります。

すると、次に遅くなったのはAIではありませんでした。

私です。

PRができる。Quality Gateが通る。別Workspaceでも次のPRができる。

でも、そのたびにChatGPTが「承認してください」で止まり、私は「承認します」と返す。

並列化したのに、最後は全部一人の人間の承認待ちに並んでいました。

そこで次に、安全で可逆なroutine開発は、毎回人間へ戻さず次の本当の安全境界まで進めるStanding Delegationを導入しました。

第10回:AI開発のたびに「承認します」と打つのをやめた

そのうえで、本当に人間が必要な境界に残った承認は、文章を毎回打つのではなくApproval UIからOwner intentとして入力できるようにしました。ボタン自体にはmerge/deploy権限を持たせず、Authorityとlive-state再検証はサーバー側に残しています。

第11回:AIに「承認」ボタンを作った。でも、ボタンに権限は渡さなかった

次回:人間をボトルネックにしない

第10回では、routineな可逆作業と、本当に人間が判断すべきprotected boundaryを分けたStanding Delegationを扱います。

「人間を消す」のではなく、人間の承認を価値のある承認へ戻すための設計です。

連載ナビ

コメント

タイトルとURLをコピーしました