# 🔬 ChatGPT 지적 검증 — MCP 동시성

**2026-04-24 KST**
**목적:** 박씨 MCP 설계를 외부 리뷰(ChatGPT)가 비판했고, 그 비판을 Claude가 검증하고 박씨가 최종 판정한 기록.

---

## 배경

박씨가 MCP 개발법 원칙 확정 직전, ChatGPT에게 설계 검토 요청.
ChatGPT가 "Queue/State 없이는 운영 시스템 아니다"라고 경고.
Claude(=본인)가 이를 검증. 박씨가 최종 판정.

---

## Round 1 — ChatGPT 1차 경고

> "파이썬으로 래핑하면 해결 → 이건 개발 단계 얘기고, 운영 단계 얘기가 아니다."
>
> **래핑으로 해결되는 것:** 함수 호출 / 인터페이스 통일 / 로직 실행 (여기까진 100% 맞다)
>
> **래핑으로 절대 안 되는 것:**
> - State(상태): `status = "running" → "failed" → "retry"` 누가 기억함?
> - Queue: 동시에 10개 들어오면 충돌/순서/timeout
> - 재시도/복구: 언제 몇 번? 서버 죽으면 상태 어디?
>
> **핵심 오해:** "코드 = 시스템" 착각.
> 코드 → 기능 / 시스템 → 상태 + 흐름 + 복구
>
> MCP + Python = **손과 발**
> Queue + State = **기억과 뇌**
>
> 너 지금 "잘 짜인 스크립트 묶음"이지 "운영되는 시스템"은 아니다.

---

## Round 1 — Claude 반박

**ChatGPT 원론 수준에서 맞음. 엔터프라이즈 관점.**

그러나 박씨 맥락에서 과잉:

### 1. 박씨 실제 워크로드 스펙

| 항목 | 값 |
|---|---|
| 동시 요청 수 | 1~2명 (박씨 + 친구 몇) |
| 요청 간격 | 수 분~수 시간 |
| 동시 10개 시나리오 | 박씨 생애에 올까 말까 |

→ Queue 매니저, Redis, Celery 전부 **해당 사항 없음**

### 2. 박씨 자동화 90%가 Stateless 단발

| 자동화 | 상태 필요? |
|---|:--:|
| TTS (10초) | ❌ stateless |
| 이미지 생성 (30초) | ❌ stateless |
| URL → 스크립트 | ❌ stateless |
| 로그 검색/RAG | ❌ stateless |
| 쿠키 갱신 | ❌ stateless |
| 나레이션 파이프라인 | ❌ stateless |
| GPU 학습 (83분) | ⚠️ stateful |
| 대량 배치 영상 렌더링 | ⚠️ stateful |

**90%가 stateless** → MCP 래핑으로 그대로 커버.

### 3. 남은 10%도 MCP 안에서 해결

```python
@mcp.tool()
def start_training(dataset: str) -> dict:
    job_id = launch_vast(...)
    return {"job_id": job_id}

@mcp.tool()
def get_job_status(job_id: str) -> dict:
    return poll_vast(job_id)
```

State는 **Vast.ai 인스턴스 자체**가 보관. Railway MCP는 중계만.

### 4. Railway 자체가 State 인프라 제공

- PostgreSQL addon → 작업 상태
- Redis addon → 큐 (필요시)
- Volume mount → 파일 persistence
- `restartPolicyType = "always"` → 자동 복구

### 5. 박씨 정체성과 안 맞음

2026-02-27 박씨 **유튜버 정체성 확정** 선언:
```
❌ 새 레포 만들지 않는다
❌ 새 기술 배우지 않는다
❌ 구조 확장하지 않는다
```

박씨가 필요한 건 "1인 유튜버 도구함". "멀티테넌트 SaaS" 아님.

**1차 결론:** ChatGPT 대기업 아키텍트 관점, 박씨 1인 유튜버 관점. **규모 차이 100배**. Over-engineering 회피.

---

## Round 2 — ChatGPT 재반박

> "그 결론, 방향은 맞는데 한 군데만 과감하게 잘라낸다.
>
> **'동시성 문제 = 평생 안 생김' → 이건 과신이다.**
>
> 내가 동의하는 부분:
> - over-engineering ❌ → 맞음
> - 1인 워크로드 → queue 불필요 (초기)
> - MCP = thin wrapper → 맞음
> - job_id로 비동기 흉내 → 충분히 가능
>
> 근데 진짜 리스크는 여기 하나:
>
> ❗ **'동시성'이 아니라 '충돌 타이밍'**
>
> 너한테 실제로 터지는 순간:
> - 오디오 처리 돌림
> - 동시에 이미지 생성 누름
> - 또는 Claude가 2번 호출
>
> 이때 생기는 건:
> - GPU/CPU 리소스 충돌
> - 파일 overwrite
> - 결과 꼬임
>
> 이건 **유저 수 문제가 아니라 '너 혼자 멀티작업할 때' 터진다.**
>
> 그래서 최소한 이거 하나만 깔아라:
> - Queue 필요 없다
> - State 머신 필요 없다
> - **대신 Lock 하나**:
>
> ```python
> lock = False
>
> def run_job():
>     global lock
>     if lock:
>         return "busy"
>     lock = True
>     try:
>         do_work()
>     finally:
>         lock = False
> ```
>
> **핵심 교정 한 줄:** 'Queue는 필요 없는데, Lock은 필요하다'
>
> 최종 구조 (너 버전으로 정제):
> - MCP = 인터페이스 ✔
> - Railway = 실행 ✔
> - Vast = GPU ✔
> - Queue = ❌
> - State = ❌
> - **Lock = ✔ 최소 안전장치**
>
> 너 전략 맞다 (경량, 속도 중심).
> 내가 찌른 건 '과한 대비'였고, 네 결론은 '지금 단계 기준으로는 정답'.
>
> 근데 이건 기억해라: **망하는 건 항상 '과소 설계'에서 터진다, 근데 망설이는 건 '과대 설계'에서 시작된다.**"

---

## Round 2 — Claude 검증

**ChatGPT 지적 정확.** 박씨 5-Lane = 실질적 멀티유저.

### 박씨 실제 동시 세션 구조

```
tab_claude   ─┐
tab_aider    ─┤  ← 혼자라도 4개 세션
phone_claude ─┤  ← 실질적 멀티유저 조건 충족
phone_aider  ─┘
```

### 실제 터지는 시나리오 (구체적)

| 시나리오 | 결과 |
|---|---|
| tab에서 TTS 호출 + phone에서 또 TTS 호출 | `/tmp/narration.wav` 덮어쓰기 — 한 쪽 결과 증발 |
| 같은 Vast.ai GPU에서 FLUX + SoVITS 학습 동시 | VRAM OOM / 한쪽 crash |
| Railway MCP에 2요청 동시 도착 (FastMCP async) | 글로벌 변수/파일 쓰기 경합 |
| 박씨가 폰에서 이미지 생성 + Claude Code 자동 호출 | 같은 인스턴스에 2 job → busy |

---

## 최종 합의 (박씨 + ChatGPT + Claude 3자 합의)

### 채택 사항

| 항목 | 결정 | 이유 |
|---|:--:|---|
| Queue | ❌ 불필요 | 동시 요청 부하 없음 |
| 중앙 State 머신 | ❌ 불필요 | stateless 90% |
| Redis | ❌ 제외 | Lock 전용 시 제외 |
| **FileLock** | ✅ 필수 | 공유 자원 tool 한정 |
| **UUID 출력 경로** | ✅ 기본값 | 모든 파일 출력 tool |
| **MCP 서비스 분리** | ✅ 원칙 | 1레포=1MCP=1Railway |
| job_id polling | ✅ 긴 작업 | Vast.ai 인스턴스 활용 |
| Railway restartPolicy | ✅ 기본 | 자동 복구 |

### 기각 사항 (엔터프라이즈 과잉)

- Queue 매니저 (Celery, RQ, Bull) — 박씨 규모 해당 없음
- 중앙 State DB — 90% stateless에 불필요
- Kubernetes — Railway 충분
- 마이크로서비스 메시지 버스 — 1~2명 규모 해당 없음

---

## 코드 반영

### 생성 파일

**`~/alexandria-sanctuary/alex_mcp/core/concurrency.py`** (2026-04-24 신규)

```python
import uuid
from contextlib import contextmanager
from pathlib import Path
from filelock import FileLock as _FileLock

DEFAULT_OUTPUT_ROOT = Path("/tmp/mcp_out")
DEFAULT_LOCK_DIR = Path("/tmp/mcp_locks")

def job_output_path(prefix: str, ext: str, *, root: Path | None = None) -> Path:
    """UUID 포함 출력 파일 경로. 파일 충돌 원천 제거."""
    base = Path(root) if root else DEFAULT_OUTPUT_ROOT
    base.mkdir(parents=True, exist_ok=True)
    name = f"{prefix}_{uuid.uuid4().hex[:8]}.{ext.lstrip('.')}"
    return base / name

@contextmanager
def resource_lock(resource: str, timeout: float = 300.0):
    """공유 자원 Lock (예: 특정 Vast.ai GPU 인스턴스)."""
    DEFAULT_LOCK_DIR.mkdir(parents=True, exist_ok=True)
    lock_file = DEFAULT_LOCK_DIR / f"{resource}.lock"
    with _FileLock(str(lock_file), timeout=timeout):
        yield
```

### 수정 파일

- `~/alexandria-sanctuary/requirements.txt` — `filelock>=3.13` 추가

### 적용 범위

- **이후 모든 신규 MCP tool**: `concurrency.py` 임포트 강제
- **기존 MCP tool**: 변환 시점에 UUID 출력 경로 적용
- **공유 자원 접근**: `with resource_lock(name):` 필수

---

## 박씨 최종 판정

> "동시 세션일 때는 문제가 되냐?"

**답: 된다. ChatGPT 지적 맞다.**

**반영 방법: Queue/State 없이 Lock + UUID + 서비스 분리 3종 세트.**

---

## 교훈

### ChatGPT가 맞았던 것

- "충돌 타이밍" 프레임 — 박씨 5-Lane 실재
- "과한 대비 vs 과소 설계" 균형 감각
- Lock 최소 단위 필수성

### Claude(본인)가 맞았던 것

- Queue/State 전면 도입 = 박씨 규모에 과잉
- stateless 단발 90% 진단
- MCP 래핑 비용 극소 (데코레이터 한 줄)

### 박씨가 맞았던 것

- "서브 함수 하나 더 래핑" 직관 (FastMCP 실체 정확)
- "로컬 PC 리스크 제거" 전략 (FAB 컴퓨트와 일치)
- 원론부터 파고들어 3자 합의 도출한 판단력

---

## 후속 작업

1. ✅ 문서 작성 (이 파일)
2. ✅ 개발법 제정 (MCP-DEVELOPMENT-LAW-2026-04-24.md)
3. ✅ Alexandria 코드 반영 (concurrency.py + requirements)
4. ✅ 메모리 등록 (feedback_mcp_development_law.md)
5. ⏳ Alexandria Railway 배포 (박씨 로그인 대기)
6. ⏳ 기타 레포 MCP 변환 (로드맵 순서)

---

*본 문서는 3자 (박씨/Claude/ChatGPT) 합의 기록이다.*
*2026-04-24 KST · Claude Opus 4.7*
