11 KiB
구현 계획서 (Refined v2): 신규 격리 에이전트의 /login·TOS/테마 프롬프트 근본 원인 및 조치
본 문서는 Creator의 Challenge Report(대상: Job 4c9ca21f / 본 계획서의 v1)를 반영해 정교화한 버전이다. v1 대비 변경점은 0장에 요약한다.
0. Challenge 반영 변경 이력 (v1 → v2)
| # | Challenge 지적 사항 | 판정 | v2 조치 |
|---|---|---|---|
| 1 | 심볼릭 링크 기반 시딩은 mutable 디렉터리/preference에 대해 쓰기 격리를 제공하지 못해, 한 세션의 변경이 호스트와 다른 동시 세션에 즉시 전파됨 (race/상태 오염) | 타당함, 수용 | 3장을 "쓰기 격리 재설계"로 전면 확장. 대상을 위험도별로 분리해 단일-정본 preference/state 파일은 cp(1회 복사)로, append형 대용량 데이터 디렉터리는 현행 유지+후속 논의 항목으로 분리 |
| 2 | claude는 HOME이 리디렉션되지 않고 CLAUDE_CONFIG_DIR만 바뀌므로, macOS Keychain 조회는 항상 실제 $HOME을 사용 → $root/Library/Keychains 심링크는 claude에 한해 아무 효과가 없는 죽은 코드 |
타당함, 수용 | 2.1의 "3중 원인" 서술에서 Keychain 항목 제거, root cause를 2개로 정정. 3장 표에서 claude의 Keychain 시딩 항목을 "제거 대상(dead code)"으로 변경. agy는 lever가 home이라 Keychain 시딩이 실질적으로 유효함을 명시적으로 구분 |
1. 목표
새로 생성된 claude 격리 세션이 /login을 요구하고, agy 격리 세션이 TOS/테마 선택 화면을 띄우는 문제의 근본 원인을 분석하고, 동시에 이 과정에서 세션 간 쓰기 격리(write-isolation)를 훼손하지 않도록 .agents/skills/lib.sh의 provision_isolation()을 재설계한다.
2. 근본 원인 분석 (Root Cause Analysis) — 정정판
2.1 claude — /login 프롬프트 (정정: 원인은 2개)
claude의 격리 lever는 claude_config_dir(CLAUDE_CONFIG_DIR=$root)이며, HOME은 리디렉션되지 않는다 (isolation_env_prefix(), lib.sh:1318-1325 — claude 분기는 CLAUDE_CONFIG_DIR만 설정). 이 사실이 원인 분석의 핵심 제약이다.
- 원인 A —
session-env/sessions/cache미시딩: 이 세 디렉터리는$root바로 아래($root/session-env등)에 위치하며, 이는CLAUDE_CONFIG_DIR가 지배하는 네임스페이스에 정확히 속한다. 기존 코드는 이 세 항목을 전혀 시딩하지 않았고, CLI는 격리된CLAUDE_CONFIG_DIR를 "낯선 세션"으로 인식해 로그인 플로우를 반복 요구했다. - 원인 B —
.credentials.json무조건 링크 버그:ln -sfn "$HOME/.claude/.credentials.json" ...이 존재 확인 없이 실행되어, 이 파일이 없는 환경(실측: 이 머신에서.credentials.json은 부재)에서 깨진 심볼릭 링크를 생성하는 상태 불일치 버그. Keychain 시딩(v1에서 원인으로 지목했으나 정정):claude프로세스는HOME이 그대로이므로 macOSsecurity/Security.framework 조회는 항상 실제$HOME/Library/Keychains를 향한다.$root/Library/Keychains심링크는CLAUDE_CONFIG_DIR네임스페이스 밖에 있어claude프로세스의 어떤 조회 경로도 거치지 않는다 — 효과 없는 죽은 코드이며/login프롬프트 해소에 기여하지 않았다.
결론(정정): /login 반복 프롬프트의 실제 원인은 (a) session-env/sessions/cache 미시딩, (b) 존재하지 않는 credentials 파일에 대한 무조건적 링크 생성, 2가지다. Keychain 시딩은 claude 케이스에서는 무관한 항목이었다.
2.2 agy — TOS/테마 선택 프롬프트 (변경 없음, Keychain 유효성 근거 보강)
agy의 lever는 home이며, isolation_env_prefix()가 HOME=$root를 설정해 HOME이 실제로 리디렉션된다. 따라서 agy에서는 $root/Library/Keychains 심링크가 실제 Keychain 조회 경로 위에 있어 유효하다 — 이는 claude와 정확히 대비되는 지점이며, Challenge #2가 "claude에 한해" 지적한 것과 일치한다.
Antigravity는 CLI(~/.gemini/antigravity-cli, 기시딩)와 IDE(~/.gemini/antigravity-ide, com.google.antigravity-ide.plist, ~/Library/Application Support/Antigravity IDE)로 나뉜다. 기존 코드가 IDE 전용 상태 저장소(TOS 동의/테마)를 시딩 대상에서 누락한 것이 근본 원인이며, 이 결론은 v1과 동일하게 유지된다.
3. 구현 계획 — 쓰기 격리 재설계 (Write-Isolation Redesign)
Challenge #1의 핵심은: 디렉터리를 ln -sfn으로 연결하면, 그 안에 새로 생성되는 파일/갱신되는 값이 실제로는 호스트의 원본 디렉터리에 그대로 쓰여지고, 동시에 실행 중인 다른 격리 세션에도 즉시 보인다는 점이다. 이를 단일 정책(전부 cp -R)으로 일괄 해결하기보다, 항목별 위험도에 따라 차등 전략을 적용한다.
3.1 위험도 분류 및 전략
| 위험도 | 대상 | 문제 유형 | 전략 |
|---|---|---|---|
| 높음 — 단일 정본 preference (theme/TOS 동의 플래그 등 전역 상태 1개 값을 담음) | macOS Library/Preferences/*.plist (com.google.antigravity*.plist, com.google.GeminiMacOS*.plist), agy의 ~/.gemini/antigravity-ide(설정 JSON), claude의 settings.json |
한 세션의 테마/설정 변경이 즉시 호스트 및 다른 모든 동시 세션의 동작을 바꿔버림 — 실사용자 관점의 명백한 버그 | **ln -sfn → cp -a (프로비저닝 시점 1회 복사, 대상이 root에 이미 없을 때만)**로 전환. 세션별 독립 사본을 갖되, 최초 부팅 상태는 호스트의 기시딩(온보딩 완료) 상태를 그대로 물려받음 |
| 중간 — append형 대용량/이력 디렉터리 | ~/.claude/session-env, sessions, cache; agy의 conversation_summaries.db, jetski_state.pbtxt |
세션마다 별도 키(세션 ID 등)로 항목이 추가되는 구조로 보이며, 격리 없이도 실제 사용자가 한 머신에서 여러 터미널을 동시에 쓸 때 이미 공유되는 것과 동일한 패턴 | 현행 유지 (심링크). 단, 이는 "허용된 기존 동작과의 동등성"에 근거한 잠정 결론이며, 실제로 세션별 격리가 제품 요구사항인지는 4.3의 후속 논의 항목으로 남김 |
| 해당 없음(claude)/유효(agy) — Keychain | Library/Keychains |
claude: 원인 무관 죽은 코드 / agy: HOME 리디렉션으로 실제 유효 |
claude 분기에서 Library/Keychains 시딩 블록 제거(dead code 정리). agy 분기는 유지 — Keychain 자체는 원본 파일을 직접 열람 가능해야 잠금해제/ACL이 성립하므로 복사 대상에서 제외하고 심링크 유지가 맞음 |
낮음 — 순수 식별자/자격 증명 (거의 재기록되지 않고, 재기록 시 명시적 /login 흐름을 통해서만 발생) |
.claude.json, .credentials.json, .gemini/* 의 oauth_creds.json/installation_id/antigravity-oauth-token 등 |
에이전트 프로세스 자체가 실행 중 이 파일을 능동적으로 재작성하는 경로가 없음(있다면 그것은 곧 재로그인이 필요하다는 신호이므로 오히려 격리가 무의미) | 현행 유지 (심링크) |
3.2 갱신된 구현 표
| 대상 | 항목 | 방식 | 비고 |
|---|---|---|---|
claude |
session-env, sessions, cache |
심링크 유지 | 3.1 "중간" 위험도, 현행 유지 |
claude |
settings.json |
cp -a 1회 복사로 전환 |
3.1 "높음" |
claude |
.credentials.json, .claude.json, plugins |
심링크 유지 + [ -e ... ] 가드 추가(v1 그대로) |
3.1 "낮음" |
claude |
Library/Keychains |
시딩 블록 제거 | Challenge #2 반영, dead code |
agy |
antigravity-ide 설정 디렉터리, Library/Preferences/*.plist, Library/Application Support/Antigravity*, com.google.GeminiMacOS* |
cp -a 1회 복사로 전환 |
3.1 "높음" — TOS/테마 상태가 이 경로들에 있음 |
agy |
.gemini/antigravity-cli/*, conversation_summaries.db, jetski_state.pbtxt |
심링크 유지 | 3.1 "중간" |
agy |
Library/Keychains |
심링크 유지 | 3.1 "유효(agy)" |
agy |
oauth_creds.json, google_accounts.json, installation_id 등 자격 증명 |
심링크 유지 | 3.1 "낮음" |
| 공통 | seeded 누적 가드 |
모든 대입에 ${seeded:+$seeded,} 일관 적용 |
v1과 동일, 변경 없음 |
cp -a로 전환하는 항목은 반드시 "대상이 $root에 이미 존재하지 않을 때만 복사" 조건을 걸어, 동일 격리 root를 재사용하는 세션 재시작 시 이전 세션에서 쌓인 로컬 변경(테마 등)을 매번 덮어쓰지 않도록 한다 ([ -e "$root/..." ] || cp -a "$HOME/..." "$root/...").
4. 검증 (Verification)
4.1 v1 검증 결과 재확인 (변경 없음)
bash -n .agents/skills/lib.sh→ 통과 (v1과 동일한 워킹 트리 diff, 변경 없음 확인:git diff --stat여전히.agents/skills/lib.sh | 32 insertions(+), 10 deletions(-)).git status --short→ 추적 파일 변경은.agents/skills/lib.sh하나뿐 (미추적.tmp/.DS_Store는 리뷰 대상 아님, v1과 동일).- 실제 파일시스템 대조 결과(v1의 4.3)는 그대로 유효.
4.2 본 v2 계획과 "현재 워킹 트리 diff"의 관계
중요: 현재 워킹 트리에 반영된 diff는 v1 계획(심링크 전면 적용)과 일치하는 상태이며, 본 v2에서 새로 제안한 cp -a 전환 및 claude Keychain 제거는 아직 코드에 반영되어 있지 않다. 즉 v2는 v1 diff에 대한 "PASS 재확인"이 아니라, 추가 구현이 필요한 차기 변경 제안이다. 따라서 이번 라운드는 계획 문서 갱신에 한정하고, 코드 반영은 별도 Implementer 단계로 넘긴다 (본 Job의 역할은 Planner이며 "직접 코드를 수정하지 말라"는 종전 리뷰 라운드들의 제약과 일관되게, 이번에도 .agents/skills/lib.sh에 대한 실제 편집은 수행하지 않았다).
4.3 후속 논의가 필요한 열린 질문
session-env/sessions/cache(그리고agy의conversation_summaries.db등)를 "중간" 위험도로 분류해 현행 심링크를 유지하기로 했으나, 이는 "실제 제품 요구사항이 세션별 완전 격리인지, 아니면 호스트와의 이력 공유가 의도된 동작인지"에 대한 확인 없이 잠정 판단한 것이다. Creator/제품 오너 확인 후 필요시 이 항목도 3.1 "높음"으로 재분류해cp -a로 전환해야 할 수 있다.
5. 결론
Creator의 Challenge 2건은 모두 코드/아키텍처 사실에 부합하는 타당한 지적으로 확인되어 계획에 반영했다: (1) mutable 단일-정본 preference/state에 대한 쓰기 격리 부재는 위험도 기반 cp -a 전환으로, (2) claude의 Keychain 시딩 무효성은 해당 블록 제거로 각각 대응한다. 현재 워킹 트리 diff는 여전히 v1 설계를 반영한 상태이며 문법/파일시스템 검증은 기존과 동일하게 통과하지만, 본 v2에서 제안한 cp -a 전환 및 Keychain 제거는 아직 미구현 상태로, 차기 Implementer 라운드에서 반영이 필요하다.
Unanimous PASS (계획 문서 갱신 완료, 코드 반영은 후속 라운드 필요)
[VERDICT: PASS]