AI coding agent를 여러 개 동시에 돌릴 때 처음 신경 쓰게 되는 것은 보통 파일 충돌이다.
두 agent가 같은 파일을 수정하면 conflict가 생길 수 있다는 것은 직관적이다.
그런데 실제 Workspace Ops와 PhotoGram 작업에서 더 근본적인 문제가 발생했다.
두 세션이 같은 checkout을 공유하면 branch context 자체가 mutable shared state가 된다.
파일이 겹치지 않아도 위험했다.
두 세션은 서로 다른 일을 하고 있었다
Workspace Ops에서는 같은 시점에 두 개의 독립 작업이 진행 중이었다.
하나는 Codex가 Lens logical-tree/Generic Inspector 기능을 구현하는 작업이었다.
다른 하나는 Claude가 provider/session identity를 조사하는 canary 작업이었다.
각 세션이 기대한 branch는 달랐다.
Codex
→ feature/cli-surface-v1
Claude
→ refoundation/workspace-2026
문제는 둘이 같은 physical checkout을 보고 있었다는 것이다.
<shared-checkout-root>
한 세션이 checkout을 바꾸면 다른 세션의 현재 directory도 그 branch로 바뀐다.
"내 세션의 branch"라는 개념은 실제 filesystem에는 없었다
AI session 입장에서는 자신의 task와 branch가 고정돼 있다고 생각하기 쉽다.
하지만 Git working tree는 session별 resource가 아니다.
SESSION A thinks: branch A
SESSION B thinks: branch B
PHYSICAL CHECKOUT
= exactly one current branch
따라서 B가 git checkout을 실행하면 A의 working directory도 같은 순간 바뀐다.
A가 이를 모른 채 파일을 수정하면 변경은 B branch 위에 놓인다.
실제로 Claude provider 조사 변경 일부가 잠시 Codex의 feature branch checkout에 작성됐다.
다행히 git status가 이상한 상태를 보여줬다
사건은 mutation 이후 상태 점검에서 발견됐다.
Claude 세션이 기대한 branch와 실제 checkout branch가 달랐다.
복구는 자신의 변경만 식별해서 isolated worktree로 옮기고, 다른 세션의 변경은 보존하는 방식으로 했다.
identify own stray changes
→ create/use isolated worktree
→ move own delta
→ revert only own stray copies
→ preserve peer session work
중요한 것은 checkout 전체를 reset해서 깨끗하게 만들지 않았다는 점이다.
그랬다면 concurrent Codex 작업을 날릴 수 있었다.
Photo Editing R2에서는 실제 작업 손실까지 갔다
비슷한 문제가 며칠 뒤 PhotoGram에서도 더 크게 나타났다.
Photo Editing R2 frontend 구현 중 primary checkout에서 작업하고 있었는데, 다른 process/session이 같은 checkout에 들어와 다른 branch를 checkout하고 reset을 수행했다.
아직 commit하지 않은 foundational work가 사라졌다.
포함된 것은 단순 CSS 몇 줄이 아니었다.
contract types
photo edit recipe
editor state hook
tone math
canvas modules
parity fixtures/tests
여러 시간 분량의 uncommitted work가 shared checkout mutation으로 없어졌다.
이번에는 단순 wrong-branch mutation risk가 아니라 실제 data loss였다.
해결은 더 강한 prompt가 아니었다
이런 문제가 생기면 agent에게 다음과 같이 말하고 싶어진다.
다른 branch를 건드리지 마라
현재 branch를 반드시 확인해라
reset하지 마라
물론 유용한 규칙이다.
하지만 physical checkout을 계속 공유한다면 완전한 해결은 아니다.
왜냐하면 두 session이 모두 규칙을 지켜도 각자 자신의 작업을 위해 branch 전환이 필요할 수 있기 때문이다.
문제는 instruction보다 resource allocation이었다.
CONCURRENT SESSIONS
+
ONE MUTABLE CHECKOUT
=
STRUCTURAL RACE
Dedicated worktree가 실질적인 lock 역할을 했다
Photo Editing R2에서는 이후 전용 worktree로 옮겼다.
task A
→ worktree A
task B
→ worktree B
그러면 각 worktree는 독립적인 branch context를 가진다.
한 세션의 checkout이 다른 세션의 current branch를 바꾸지 않는다.
Git object database는 공유하지만 mutable working tree는 분리된다.
AI 병렬 작업에서 이것이 매우 큰 차이를 만든다.
commit frequency도 recovery boundary가 됐다
전용 worktree만으로 모든 사고를 막을 수는 없다.
그래서 meaningful chunk를 더 자주 commit했다.
uncommitted work
→ working-tree state
→ reset/crash에 취약
committed work
→ Git object
→ recovery 가능
여기서 commit은 release/promotion 의미가 아니다.
작업 복구를 위한 durable checkpoint이기도 하다.
즉:
COMMIT
!= ACCEPTANCE
but
COMMIT
= durable recovery boundary
가 된다.
세션 isolation은 파일 충돌만 피하는 문제가 아니다
동시 실행에서 공유되는 것은 파일만이 아니다.
current branch
HEAD
index
untracked files
generated artifacts
local DB
ports
runtime processes
cache
이번 사건에서는 branch context가 핵심이었다.
다른 프로젝트에서는 같은 DB나 같은 port가 race surface가 될 수 있다.
그래서 concurrency를 설계할 때 "두 agent가 다른 파일을 수정한다"만으로 독립성을 판단하면 안 된다.
Worktree도 만능은 아니다
이후 별도 사건에서는 source worktree가 분리돼 있어도 local MariaDB schema가 공유돼 drift가 생겼다.
즉:
WORKTREE ISOLATION
= source checkout isolation
NOT
= full environment isolation
이 글에서 다루는 문제는 Git checkout race다.
DB/state isolation은 또 다른 층이다.
두 문제를 구분해야 적절한 대응을 선택할 수 있다.
AI 병렬성은 CPU thread보다 운영자 병렬성에 가깝다
agent 여러 개를 돌리면 흔히 subtask parallelism으로 생각한다.
하지만 실제로는 여러 명의 운영자가 같은 workstation을 동시에 쓰는 것과 비슷한 면이 있다.
각 agent는:
git
filesystem
processes
network
tests
runtime
를 직접 변경할 수 있다.
따라서 concurrency model도 task list가 아니라 resource ownership까지 내려가야 한다.
가장 단순한 원칙은 physical mutation surface를 분리하는 것이다
결국 사건 이후 남은 원칙은 단순했다.
PARALLEL MUTATION
→ separate mutable workspace
SHARED READ
→ may share when safe
그리고 이미 shared checkout에서 작업 중이라면 destructive cleanup보다 먼저 ownership을 확인한다.
UNKNOWN DIRTY STATE
→ do not reset
identify owner
→ preserve unrelated changes
→ isolate own work
AI agent가 많아질수록 실행 속도는 빨라진다.
그만큼 filesystem과 Git도 multi-writer system으로 취급해야 한다.
이번 사고에서 branch가 스스로 바뀐 것은 아니었다.
두 개의 독립된 session이 하나의 mutable branch context를 함께 소유하고 있었던 것이 문제였다.