Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions docs/PHASE2-SURVEY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Phase 2 조사 — 무엇이 있고 무엇이 빠졌나

작성일: 2026-08-05 · 기준 커밋: `develop` (main 대비 50커밋) · 목적: "Phase 2 를 끝냈다" 고 말하려면 끝의 정의가 먼저 필요하다

---

## 0. 먼저: 끝의 정의가 두 문서에서 다르고, 둘 다 현실과 다르다

- [DESIGN.md](DESIGN.md) 의 **Phase 2 는 "Code-OSS 포크로 이전"** 이다. 확장 API 로 불가능한 시각 효과를 위해 VSCodium 방식으로 포크한다는 계획이었다.
- [README.md](../README.md) 의 **Phase 2 는 "에디터 코어의 렌더러 레벨 시각 효과 심화"** 로 적혀 있고 *(in progress)* 다.
- **실제로는 둘 다 아니다.** 이 앱은 Code-OSS 포크가 아니라 Electron 43 + React 18 + Monaco 로 **처음부터 자기 렌더러를 갖고** 있다. 포크가 필요했던 이유(렌더러에 손댈 수 없다)가 애초에 없다.

즉 Phase 2 의 원래 목표는 **다른 방법으로 이미 달성됐고**, 남은 것은 포크 여부가 아니라 **네 기둥(DESIGN.md 2.1~2.4)이 실제로 화면에 있는가** 다. 아래 표의 기준은 그 네 기둥이다.

판정은 코드로 확인한 것만 적는다. △ 는 "비슷한 것이 있으나 설계가 말한 자리에 없다" 는 뜻이다.

---

## 1. 2.1 편집 과정 애니메이션

| 항목 | 상태 | 확인한 것 |
|---|---|---|
| 스트리밍 삽입 | △ | [editAnimator.ts](../ide/src/editor/editAnimator.ts) 가 16ms마다 3글자씩 모델에 밀어 넣는다(최대 2200ms). 다만 흘리는 것은 **이미 완성된 최종 텍스트의 재생**이지 모델의 토큰 스트림이 아니다. 설계는 "토큰 스트림을 그대로 흘려서" 라고 적었다. |
| 글로우/하이라이트 | ✓ | `.sz-ai-typing`(쓰고 있는 줄) + `.sz-ai-changed`(1.4초 잔광, `szAiFade`). `reducedMotion()` 을 직접 물어 모션 최소화도 지킨다. |
| 커서 고스트 | ✗ | 없다. 코드베이스 어디에도 유령 커서가 없다. |
| undo 한 덩어리 | ✓ | 타이핑 시작에 `pushStackElement` 한 번 — Ctrl+Z 로 AI 편집 전체가 한 번에 돌아온다. |

## 2. 2.2 변경 diff 시각화

| 항목 | 상태 | 확인한 것 |
|---|---|---|
| 인라인 diff 색 | △ | 거터 막대는 있다(`.sz-gd-add/mod/del`, [MonacoPane.tsx](../ide/src/editor/MonacoPane.tsx) 245~254). 그런데 그건 **git 기준 변경**이다. 아직 수락하지 않은 제안은 편집기 안에 안 보이고, 전체 diff 는 별도 탭([DiffPane.tsx](../ide/src/editor/DiffPane.tsx), `createDiffEditor`)에서 본다. |
| 변경 사유 툴팁 | △ | `rationale` 은 있고 제안 카드에 보인다(App.tsx:8387). 설계가 말한 자리 — **바뀐 줄 위의 툴팁** — 에는 없다. |
| 라인 단위 수락/거절 | △ | 헝크 단위 선택이 있다([review/hunks.ts](../ide/src/review/hunks.ts), `hunkSel`). 다만 카드 안에서 고르는 것이고, 설계가 적은 **CodeLens** 는 없다(`registerCodeLensProvider` 호출이 0건). |
| 변경 그룹핑 | △ | 한 제안 안에서 헝크로 묶인다. 파일을 가로지르는 "논리적 변경 하나" 묶음은 없다. |

## 3. 2.3 AI 작업 상태·계획 패널

| 항목 | 상태 | 확인한 것 |
|---|---|---|
| 현재 행동 | ✓ | `statusKey` 가 도구 실행·편집·검토를 따라간다. |
| 계획 뷰 | ✓ | `set_plan` 도구 → `plan` 상태 → 패널. 체크·진행·예정이 구분된다. |
| 툴 호출 로그 | ✓ | `addTool`/`setTool` 로 타임라인에 남고 펼쳐서 출력까지 본다. |
| 토큰/비용 미터 | ✓ | `bumpAgent(tin, tout)` + 잔여량 조회. |

**이 기둥은 끝났다.** 네 항목 모두 실제 경로로 채워진다.

## 4. 2.4 멀티파일 동시 편집 뷰

| 항목 | 상태 | 확인한 것 |
|---|---|---|
| 미니 파일 그리드 | △ | `renderChangeOverview`(App.tsx:8532)가 있다. 다만 **카드 그리드가 아니라 막대가 붙은 목록**이고, 파일이 2개 이상일 때만 뜬다. |
| 변경량 배지 | ✓ | 파일마다 `+N / −N`, 가장 큰 파일 기준 상대 막대. |
| 동시 진행 표시 | ✓ | 파일마다 점 색으로 pending·failed·담당 에이전트를 구분한다. |
| 카드 클릭 → 점프 | ✓ | 누르면 그 파일을 연다. |

---

## 5. 그래서 Phase 2 의 "끝" 을 무엇으로 둘 것인가

포크는 판단에서 뺀다 — 이 구조에서는 할 이유가 없고, 하지 않은 것이 맞다. 남은 것은 네 기둥의 빈칸이고, 그중 **설계가 이름으로 적었는데 코드에 없는 것**은 셋이다.

1. **커서 고스트** (2.1) — 없다. AI 가 지금 어디를 고치는지 눈으로 따라가게 하는 장치인데, 지금은 줄 하이라이트만 있다. 작고, 데코레이션으로 되고, 효과가 바로 보인다.
2. **변경 사유 툴팁** (2.2) — `rationale` 은 이미 있다. 바뀐 줄에 붙이기만 하면 된다. 이것도 데코레이션 hover 로 된다.
3. **CodeLens 수락/거절** (2.2) — 헝크 선택 로직이 이미 있으므로 편집기 안에 그 버튼을 다는 일이다. 셋 중 가장 크다.

나머지 △ 는 **설계와 다른 방식으로 이미 답이 있는 것**들이다(전체 diff 는 별도 탭, 파일 개요는 목록). 굳이 설계 문구에 맞춰 바꿀 값어치는 없어 보이고, 바꾼다면 그건 Phase 2 완료가 아니라 별개의 UI 결정이다.

"스트리밍 삽입" 만 애매하다. 지금은 완성된 텍스트를 재생하는 것이라 **모델이 실제로 쓰는 속도와 무관**하다. 진짜 토큰 스트림을 흘리려면 제안 경로(도구 호출 → 카드 → 수락)를 건드려야 하는데, 그건 시각 효과가 아니라 승인 모델의 변경이다. 별건으로 남긴다.

### 제안하는 완료 조건

> Phase 2 는 **커서 고스트 · 변경 사유 툴팁 · CodeLens 수락/거절** 셋이 실제 앱에서 동작하면 끝난 것으로 한다. 포크 항목은 아키텍처가 달라져 해당 없음으로 닫고, DESIGN.md 와 README 의 Phase 2 문구를 그 사실에 맞게 고친다.

셋 다 데코레이션·CodeLens 계층이라 [#70](https://github.com/SchutzScript/Schutz/pull/70) 에서 만든 것을 그대로 쓴다.
Loading