docs: known-issues 아카이빙 + Collector 폐기 마킹 + 레퍼런스 문서 보강 #task-409

This commit is contained in:
Variet Worker
2026-03-18 06:28:14 +09:00
parent d06b1ea0db
commit 881a424b23
8 changed files with 706 additions and 691 deletions

View File

@@ -45,7 +45,7 @@ gravity_control/
├── bridge.py # 파일 기반 IPC (레거시 fallback) (479줄) ├── bridge.py # 파일 기반 IPC (레거시 fallback) (479줄)
├── watcher.py # Brain 디렉토리 변경 감시 (290줄) ├── watcher.py # Brain 디렉토리 변경 감시 (290줄)
├── parser.py # Markdown → Discord 변환 (245줄) ├── parser.py # Markdown → Discord 변환 (245줄)
├── collector.py # 원격 파일→HTTP 릴레이 (Phase 2 삭제 예정) (517줄) ├── collector.py # 원격 파일→HTTP 릴레이 (⚠️ DEPRECATED — WS Hub 사용) (523줄)
├── ── Extension 측 (TypeScript) ── ├── ── Extension 측 (TypeScript) ──
├── extension/src/ ├── extension/src/
@@ -252,11 +252,16 @@ Extension(step-probe.ts) → 새 step 텍스트 감지
``` ```
AG Engine → 파일 수정 → Extension(step-probe.ts) AG Engine → 파일 수정 → Extension(step-probe.ts)
→ edit_step_indices + modified_files 메타데이터 수집 → edit_step_indices + modified_files 메타데이터 수집
→ writePendingApproval (step_type="diff_review") → writePendingApproval (step_type="diff_review", 8초 지연)
→ Discord (Accept all / Reject all 버튼) → Discord (Accept all / Reject all 버튼)
→ 응답 → acknowledgeCodeActionStep RPC → 응답 → handleDiffReviewResponse()
→ openReviewChanges → 파일별 포커스 → agentAcceptAllInFile VS Code 커맨드
``` ```
> [!IMPORTANT]
> diff_review는 **VS Code 커맨드만 유효**합니다. RPC 방식(AcknowledgeCascadeCodeEdit 등)은 모두 실패 확정.
> 상세 경위는 known-issues-archive.md의 "Diff Review 관련" 섹션을 참조하세요.
--- ---
## 5. 통신 프로토콜 ## 5. 통신 프로토콜
@@ -292,7 +297,7 @@ AG Engine → 파일 수정 → Extension(step-probe.ts)
|------|---------|-------------|------| |------|---------|-------------|------|
| `local` | ✅ (brain 감시) | ❌ | 로컬 개발 (Extension과 같은 PC) | | `local` | ✅ (brain 감시) | ❌ | 로컬 개발 (Extension과 같은 PC) |
| `gateway` | ❌ | ✅ (port 8585) | 서버 배포 (WS Hub + Gateway) | | `gateway` | ❌ | ✅ (port 8585) | 서버 배포 (WS Hub + Gateway) |
| `remote` | ✅ | ❌ | 원격 브릿지 (레거시 Collector) | | `remote` | ✅ | ❌ | ⚠️ **DEPRECATED** — 레거시 Collector (WS Hub 사용 권장) |
--- ---

View File

@@ -89,3 +89,37 @@ Extension 모듈 분리 시 사용하는 패턴:
| Extension | `logToFile(msg)` → bridge/log/ | `[HH:MM:SS] message` + `[WS]` prefix | | Extension | `logToFile(msg)` → bridge/log/ | `[HH:MM:SS] message` + `[WS]` prefix |
| Hub | `[HUB]` prefix | `[HUB] Auth OK: {conn_id} project={project}` | | Hub | `[HUB]` prefix | `[HUB] Auth OK: {conn_id} project={project}` |
| Gateway | `[GATEWAY]` prefix | `[GATEWAY] HTTP API started on {host}:{port}` | | Gateway | `[GATEWAY]` prefix | `[GATEWAY] HTTP API started on {host}:{port}` |
## WS / File Bridge 상호 배타 패턴
> [!IMPORTANT]
> WS Hub과 파일 bridge는 **항상 상호 배타적**이어야 합니다.
> 양쪽에 동시에 쓰면 이중 전달 버그가 발생합니다. (known-issues-archive 참조)
**Extension (TypeScript):**
```typescript
// ✅ 올바른 패턴
if (ctx.wsBridge?.isConnected()) {
ctx.wsBridge.sendPending(data);
return; // ← 반드시 return으로 파일 쓰기 건너뛰기
}
// File fallback
fs.writeFileSync(pendingPath, JSON.stringify(data));
```
**Bot (Python):**
```python
# ✅ 올바른 패턴
if self.hub:
await self.hub.send_response(...)
else:
bridge.write_response(...)
```
**금지 패턴:**
```python
# ❌ 이중 쓰기 — 절대 금지
if self.hub:
await self.hub.send_response(...)
bridge.write_response(...) # ← Hub 성공해도 파일에도 씀 → 이중 처리
```

View File

@@ -0,0 +1,581 @@
# Known Issues — Archive
> **해결 완료된 이슈 아카이브입니다.**
> 현재 활성 이슈는 [`known-issues.md`](file:///c:/Users/Variet-Worker/Desktop/gravity_control/.agents/references/known-issues.md)를 참조하세요.
> 비슷한 문제가 재발할 때 이 문서에서 과거 해결 방법을 검색하세요.
---
## 포맷
```markdown
### [날짜] [키워드] — 한줄 요약
- **증상**: 무엇이 잘못되었는가
- **원인**: 근본 원인
- **해결**: 올바른 해결 방법
- **주의**: 재발 방지를 위한 교훈
```
---
## 승인 전략 결정 체인 (2026-03-08~09 전체 요약)
> **이 섹션은 2026-03-08~09 전체 세션의 시행착오를 요약합니다.**
> **이미 거부된 접근을 다시 시도하지 마세요.**
### ❌ 시도 후 거부된 접근 (재시도 금지)
| # | 접근 | 결과 | 거부 사유 |
|---|------|------|-----------|
| 1 | LS RPC `HandleCascadeUserInteraction` | `socket hang up` | AG 빌드에서 핸들러 미구현 |
| 2 | LS RPC `ResolveOutstandingSteps` | CANCEL 동작 (승인이 아님) | 명칭과 달리 step을 취소함 |
| 3 | VS Code 7개 승인 명령 (`terminalCommand.run` 등) | `command not found` | AG 런타임에 미등록 |
| 4 | 키보드 시뮬레이션 (`type {Enter}`) | 빈 메시지 전송 | Chat input에 캡처됨 |
| 5 | `sendChatActionMessage` / `executeCascadeAction` | 미등록 | 119개 명령에 없음 |
| 6 | pywinauto (OS 레벨) | 사용자 결정 폐기 | 크로스플랫폼 불가, 창 겹침 문제 |
| 7 | CDP (Chrome DevTools Protocol) | **사용자 명시적 거부** | 비표준, `--remote-debugging-port` 필요 |
| 8 | Renderer v1 DOM Click (flat scan) | Run 버튼 미발견 | webview iframe 격리 |
### 🔑 핵심 전제
- Run/Accept 버튼은 **`vscode-webview://` origin의 격리된 iframe** 안에 있음
- 외부 workbench DOM에서 `querySelector`로 접근 **불가** (cross-origin)
- `<webview>.executeJavaScript()`**유일한 표준 관통 경로** (Electron API)
- AG 패치 후 **반드시 풀 프로세스 재시작** 필요 (Reload Window 불충분)
- **양쪽 HTML (workbench.html + workbench-jetski-agent.html) 모두 inline 패치** 필수
- HTML 패치 변경 시 **`%APPDATA%\Antigravity\CachedData` 삭제 필수** (V8 바이트코드 캐시 무효화)
- **CSP `script-src``'unsafe-inline'` 패치 필수** (없으면 인라인 스크립트 무조건 차단)
---
## Renderer / HTML 패치 관련 (2026-03-08~09)
### [2026-03-08] Antigravity Renderer Injection — Electron 캐시 차단
- **증상**: workbench.html, workbench-jetski-agent.html에 `<script>` 태그 추가 후 리로드해도 실행되지 않음
- **원인**: Electron의 V8 코드 캐시가 수정된 HTML을 무시하고 캐시된 버전을 서빙
- **해결**: 렌더러 인젝션 방식 **포기**. Extension Host에서 RPC 폴링 방식으로 전환
- **주의**: Antigravity는 `workbench-jetski-agent.html`을 사용 (Jetski = 내부 코드네임)
### [2026-03-08] Antigravity 승인 대기 = RUNNING (NOT IDLE)
- **증상**: IDLE 기반 승인 감지가 실제 승인 대기를 놓침
- **원인**: 승인 대기 시 세션 상태가 `CASCADE_RUN_STATUS_RUNNING` (IDLE 아님), `IDLE`은 대화 대기(notify_user 후)
- **해결**: `RUNNING + delta=0` (stall) 기반 감지로 전환. 6 polls (30초) 이상 FROZEN 시 pending 생성
- **주의**: Thinking/생성 중에도 `RUNNING + delta=0`이 발생 → `lastModifiedTime`으로 구분 시도했으나 불완전
### [2026-03-08] ResolveOutstandingSteps RPC — 승인이 아닌 취소!
- **증상**: Discord 승인 → `ResolveOutstandingSteps` 호출 → step이 취소됨
- **원인**: `ResolveOutstandingSteps`는 blocking steps를 "resolve" = **REJECT/CANCEL**, approve가 아님
- **해결**: `ResolveOutstandingSteps` 제거. `HandleCascadeUserInteraction``socket hang up`
- **주의**: KI에 "more reliable"로 기록되어 있으나 실제 동작은 cancel임. KI 업데이트 필요
### [2026-03-08] VS Code Accept Commands — Silent Success 문제
- **증상**: 4개 accept command 모두 OK(undefined) 반환하나 실제 승인 안 됨
- **원인**: webview에 활성 포커스가 필요. `panel.focus()`로는 충분하지 않음
- **해결**: **미해결**. Windows UI Automation 등 OS 레벨 접근 필요
- **주의**: reject commands는 동작함. accept만 focus 의존성 있음
### [2026-03-08] Multi-Window 세션 등록 경쟁 조건
- **증상**: 이 창(gravity_control)의 대화가 `#ag-variet_agent` 채널로 메시지 전달
- **원인**: `writeRegistration()`이 폴링 루프에서 호출 → 먼저 폴링한 확장이 세션을 자기 프로젝트로 등록
- **해결**: `writeRegistration`을 폴링에서 제거, `writeChatSnapshot`/`writePendingApproval`에서만 지연 호출
- **주의**: `GetAllCascadeTrajectories`는 모든 창의 세션을 반환하므로 세션→창 매핑은 불가능. 활동 기반 등록만 신뢰 가능
### [2026-03-08] 공유 렌더러 스크립트 파일 덮어쓰기 문제
- **증상**: DOM Observer 렌더러 스크립트가 잘못된 HTTP bridge 포트에 연결
- **원인**: 두 확장이 동일한 `ag-sdk-variet-gravity-bridge.js` 파일에 각자 포트를 씀 → 마지막 확장 것만 남음
- **해결**: `ag-bridge-ports.json`에 모든 확장의 port를 JSON으로 기록, 렌더러가 all ports를 순회하며 ping
- **주의**: 렌더러 스크립트 파일 경로는 SDK patcher namespace에 의해 고정 — 변경 불가
### [2026-03-08] workbench.html vs workbench-jetski-agent.html
- **증상**: 렌더러에서 `[GB Observer]` 로그가 전혀 안 나옴
- **원인**: DevTools가 `workbench.html`을 로드 — 스크립트 태그는 `workbench-jetski-agent.html`에만 패치됨
- **해결**: `workbench.html`에도 스크립트 태그 필요. Antigravity 재설치 후 SDK patcher가 올바르게 패치하도록 함
- **주의**: SDK patcher는 `both` HTML 파일을 패치하지만, 수동 수정은 Antigravity integrity check에 의해 되돌려질 수 있음
### [2026-03-08] product.json 체크섬 불일치 → 렌더러 스크립트 미로딩
- **증상**: `<script>` 태그가 HTML에 존재하고 .js 파일도 디스크에 있으나, 렌더러 콘솔에 스크립트 로그가 전혀 없음
- **원인**: Antigravity 재설치 시 `product.json`의 SHA256 체크섬이 원본으로 리셋됨. Extension이 HTML을 패치하지만 `IntegrityManager.suppressCheck()`를 호출하지 않아 체크섬 불일치. `vscode-file://` 프로토콜이 체크섬 불일치 파일을 무시하고 **원본 캐시 HTML**을 서빙
- **해결**: `product.json``checksums` 항목에서 수정된 파일(workbench.html, workbench-jetski-agent.html)의 SHA256 해시를 실제 파일 기준으로 업데이트. SDK `IntegrityManager.suppressCheck()` 호출 또는 수동 스크립트로 해결
- **주의**: Extension `setupApprovalObserver()``suppressCheck()` 호출을 영구 추가해야 재설치마다 반복 안 됨. 해시 = `base64(sha256(file)).replace(/=+$/, '')`
### [2026-03-08] vscode-file:// 프로토콜 — 커스텀 .js 파일 서빙 불가
- **증상**: `<script src="./ag-sdk-variet-gravity-bridge.js">` 태그가 HTML에 있으나 `net::ERR_FILE_NOT_FOUND` 발생, GB Observer 로그 전혀 없음
- **원인**: `vscode-file://` 프로토콜은 원본 배포에 포함된 파일만 서빙. Extension이 디스크에 쓴 커스텀 `.js` 파일은 프로토콜 레벨에서 차단됨
- **해결**: 외부 `<script src>` 참조 대신 **인라인 `<script>...코드...</script>`** 방식으로 HTML에 직접 삽입
- **주의**: `ag-bridge-ports.json`도 같은 이유로 XHR 로딩 불가. 모든 렌더러 스크립트/데이터는 HTML 인라인으로 전달해야 함
### [2026-03-08] Renderer 포트 디스커버리 — ag-bridge-ports.json XHR 실패
- **증상**: `[GB Observer] Port discovery timeout after 2min` — 렌더러가 bridge 포트를 찾지 못함
- **원인**: 렌더러 스크립트가 `./ag-bridge-ports.json`을 동기 XHR로 읽으려 하나, `vscode-file://` 프로토콜이 `.json` 파일 서빙 거부
- **해결**: (1) 프로젝트명 해시 기반 **결정론적 포트** 사용 (`gravity_control→34332`), (2) 스크립트 생성 시 포트를 `HARDCODED_PORT=${port}`로 직접 삽입
- **주의**: `server.listen(0)` 랜덤 포트 → 매 재시작마다 변경되어 렌더러와 불일치. 결정론적 포트는 `EADDRINUSE` 시 랜덤 폴백 필요
### [2026-03-08] GetCascadeTrajectorySteps — cascadeId 파라미터 발견
- **증상**: `GetCascadeTrajectorySteps``trajectoryId` 파라미터 → 500 "trajectory not found"
- **원인**: 파라미터명이 `trajectoryId`가 아니라 **`cascadeId`**. 값은 `GetAllCascadeTrajectories.trajectorySummaries`의 맵 키(세션 ID)
- **해결**: `{ cascadeId: sessionId }`로 호출 → 전체 step 배열 반환 성공
- **주의**: `latestToolCallStep` 필드는 `GetAllCascadeTrajectories` 응답에 **존재하지 않음** (KI 오류)
### [2026-03-08] Step 구조 — CORTEX_STEP_STATUS_WAITING 즉시 감지
- **증상**: stall-based 감지(100초)가 너무 느림
- **원인**: 이제 `GetCascadeTrajectorySteps`로 최신 step의 status를 직접 확인 가능
- **해결**: stall 5초 후 step probe → `CORTEX_STEP_STATUS_WAITING` 확인 → 즉시 pending 생성
- **Step 구조**: `{type: "CORTEX_STEP_TYPE_RUN_COMMAND", status: "CORTEX_STEP_STATUS_WAITING", metadata: {toolCall: {name, argumentsJson}}, runCommand, requestedInteraction}`
- **주의**: 775-step 하드 리밋은 여전히 존재. 긴 세션에서는 fallback(40초) 사용
### [2026-03-08] Extension 재설치 안전성 — 자동 패치 메커니즘
- **증상**: Antigravity 삭제 후 재설치 시 렌더러 스크립트가 동작 안 함
- **원인**: 재설치 시 HTML/product.json이 원본으로 리셋됨
- **해결**: Extension의 `setupApprovalObserver()`**자동으로** 모든 패치를 수행
- **주의**: 패치 후 반드시 **Antigravity 풀 재시작** 필요 (Reload Window 불가)
### [2026-03-08] Response 파일 Race Condition — DOM Observer 승인 실패
- **증상**: Discord에서 승인 → `[RESPONSE] renderer-handled approval` 로그 출력 → 실제 버튼 클릭 안 됨
- **원인**: `processResponseFile` (파일 감시자)이 response 파일을 즉시 삭제 → renderer의 `pollResponse`가 HTTP `GET /response/:rid`로 조회 시 파일 이미 없음
- **해결**: DOM observer 소스일 때는 response 파일을 삭제하지 않도록 수정. HTTP endpoint가 renderer에게 서빙한 후 삭제
- **주의**: non-DOM (stall/step_probe relay)는 watcher에서 삭제해도 됨
### [2026-03-08] Renderer 스크립트 소스 혼동 — 3곳의 코드
- **증상**: `extension.ts`에 BTN-DUMP 추가 → Reload 2번 → 콘솔에 안 나옴
- **원인**: renderer 코드가 **3곳**에 존재: (1) `extension.ts``generateApprovalObserverScript()` (소스), (2) `ag-sdk-variet-gravity-bridge.js` (배포됨, Reload시 소스에서 재생성), (3) `workbench-jetski-agent.html` inline (HTML, JS파일과 중복로드 방지됨)
- **해결**: 항상 `extension.ts``generateApprovalObserverScript()` 함수를 수정 → 컴파일 → 배포 → Reload
- **주의**: HTML inline은 JS파일이 먼저 로드되어 `window.__agSDK` 가드에 의해 실행 안 됨. 실제 실행되는 것은 JS파일 경로의 스크립트
---
## 승인 / RPC 관련 (2026-03-09)
### [2026-03-09] VS Code Accept — SDK 승인 명령이 AG에 미등록
- **증상**: Discord 승인 → `antigravity.terminalCommand.run` 등 7개 명령 → 모두 `command not found`
- **원인**: SDK(command-bridge.ts)에 정의된 7개 승인 명령이 현재 AG 빌드에 **등록되어 있지 않음**
- **해결**: Renderer DOM Click 구현 → v3 `deepFindButtons()` 업그레이드
- **주의**: `agentPanel.focus`도 미등록, `agentSidePanel.focus`만 존재
### [2026-03-09] Renderer DOM — webview iframe 격리 확인 + v3 deep traversal
- **증상**: Renderer trigger-click이 `document.querySelectorAll('button')`으로 버튼 검색 → Run 버튼 미발견
- **원인**: Run/Accept 버튼은 AG 채팅 webview iframe (`vscode-webview://` origin) 안에 렌더링
- **해결**: Renderer v3 `deepFindButtons()` 구현 (iframe contentDocument + webview.executeJavaScript + shadow DOM)
- **주의**: CDP(Chrome DevTools Protocol)는 **사용자 결정에 의해 명시적으로 거부됨**
### [2026-03-09] Deep Inspect HTTP Endpoint — curl로 DOM 분석 트리거
- **증상**: AG DevTools 콘솔에 붙여넣기 불가 (Chromium 보안 정책)
- **원인**: Electron 렌더러 DevTools에서 `allow pasting`이 SyntaxError 발생
- **해결**: Extension HTTP bridge에 `/deep-inspect` 엔드포인트 추가
- **주의**: 시작 3초 후 자동 실행 + curl로 재트리거 가능
### [2026-03-09] workbench.html inline 스크립트 미삽입 — jetski만 패치한 버그
- **증상**: AG 재시작 후 `/deep-inspect` timeout — renderer v3 스크립트 미로딩
- **원인**: `setupApprovalObserver()``workbench-jetski-agent.html`에만 inline 삽입
- **해결**: HTML 패치 로직을 **양쪽 모두 inline** 삽입으로 변경
- **주의**: **항상 양쪽 HTML을 동일하게 패치**
### [2026-03-09] V8 CachedData — 체크섬 정상이어도 스크립트 미실행
- **증상**: HTML 패치 + product.json 체크섬 일치 → 그런데도 renderer 스크립트 미실행
- **원인**: V8 바이트코드 캐시가 `vscode-file://` 프로토콜에도 적용
- **해결**: `%APPDATA%\Antigravity\CachedData\*` 전체 삭제 후 AG 풀 재시작
- **주의**: **HTML 패치 변경 시마다 CachedData 삭제 필수**
### [2026-03-09] CSP script-src — 인라인 스크립트 무조건 차단
- **증상**: HTML 패치 ✅, 체크섬 ✅, CachedData 삭제 ✅ — 그런데도 renderer 미실행
- **원인**: CSP `script-src``'unsafe-inline'` 없음
- **해결**: CSP `script-src``'unsafe-inline'` 추가
- **주의**: `style-src`에는 `'unsafe-inline'`이 있어 스타일은 동작 → 스크립트만 차단되는 것이 함정
### [2026-03-09] 중복 승인 요청 — DOM scan + Step probe 동시 발동
- **증상**: Discord에 같은 명령에 대해 승인 요청이 2개 도착
- **원인**: DOM Observer + Step probe가 동일 step에 대해 2개 파일 생성
- **해결**: `writePendingApproval()`에 15초 dedup 윈도우 추가
- **주의**: DOM scan은 제거 불가 — step probe가 감지 못하는 UI 버튼 존재
### [2026-03-09] Step probe reject → ResolveOutstandingSteps가 AI 작업 취소
- **증상**: Discord에서 거부 클릭 → AI의 현재 step뿐 아니라 진행 중인 작업 전체가 중단
- **원인**: step probe 경로의 `tryApprovalStrategies(approved=false)``ResolveOutstandingSteps` RPC 호출
- **해결**: step probe 경로에서 reject 시 `tryApprovalStrategies` 호출 제거
- **주의**: `ResolveOutstandingSteps`는 이름과 달리 "해결"이 아닌 "취소". 승인에 **절대 사용 금지**
### [2026-03-09] Pending 파일 무한 누적 — write_response 후 미삭제
- **증상**: `bridge/pending/` 디렉토리에 79개 이상의 .json 파일 누적
- **원인**: `write_response()`가 pending 파일을 삭제하지 않음
- **해결**: pending 파일 삭제 + 5분 age filter + 시작 시 cleanup
- **주의**: 봇 재시작 시 자동 정리
### [2026-03-09] Discord 승인 "Run" 표시 — DOM/step_probe 타이밍 불일치
- **증상**: Discord에 상세 명령어 대신 "Run"만 표시
- **원인**: DOM observer가 "Run" pending 생성 → 봇이 3초 후 전송 → step_probe MERGE가 10초 후 완료
- **해결**: step_probe가 기존 DOM pending에 MERGE + 봇에서 짧은 명령어 대기
- **주의**: MERGE 타이밍은 최소 10초
### [2026-03-09] DOM observer false positive — Proceed/Continue/Open 버튼 오감지
- **증상**: 작업 전환 시 승인 요청 없는데도 Discord에 승인 요청 도착
- **원인**: DOM observer가 AG UI의 PathsToReview 버튼을 승인 버튼으로 오인
- **해결**: FALSE_POSITIVE_RE 필터 추가 + sessionStalled 조건
- **주의**: 렌더러 인라인 스크립트는 VSIX 빌드 필요
### [2026-03-09] Discord ApprovalView timeout — 5분 후 버튼 무응답
- **증상**: 시간이 지난 후 Discord 승인 버튼 클릭해도 반응 없음
- **원인**: Discord.py View의 기본 timeout이 300초
- **해결**: timeout을 1800초로 증가
- **주의**: Discord View timeout은 서버 재시작 후만 적용
---
## 멀티 프로젝트 / Pending 관련 (2026-03-10)
### [2026-03-10] DOM Observer 승인 ENOENT — response 파일 Race Condition
- **증상**: Discord에서 ✅승인 → `ENOENT: response/xxx.json` 에러
- **원인**: `processResponseFile()`이 response 파일 즉시 삭제 → renderer 조회 실패
- **해결**: DOM observer 경로에서 response 파일을 삭제하지 않고 HTTP handler가 서빙 후 삭제
- **주의**: DOM observer와 step_probe 두 경로가 독립적
### [2026-03-10] Allow Once + Allow This Conversation — 별개 pending으로 분리되는 문제
- **증상**: 파일 접근 시 Discord에 2개 별도 메시지로 도착
- **원인**: renderer `scan()`이 한 사이클에 한 버튼만 처리
- **해결**: `findButtonContainer()` + `collectSiblingButtons()`로 그룹화, `buttons` 배열 전송
- **주의**: `buttons` 배열이 없는 legacy pending은 기존 2버튼(✅승인/❌거부)으로 표시
### [2026-03-10] step_probe verbosity — argumentsJson 미포함
- **증상**: Discord 승인 메시지에 파라미터 이름만 표시, 값 없음
- **원인**: `GetCascadeTrajectorySteps` 기본 verbosity에서 `argumentsJson` 빈 문자열
- **해결**: `verbosity: 1` (DEBUG) 추가
- **주의**: verbosity 0=NORMAL (키만), 1=DEBUG (값 포함)
### [2026-03-10] 파일 권한 응답 — "unexpected user interaction type: not file permission"
- **증상**: `.agents` 디렉토리 접근 시 에러
- **원인**: 봇이 file_permission pending에 잘못된 interaction type 전송
- **해결**: step_type별 올바른 RPC 라우팅
- **주의**: file_permission과 run_command가 동시에 대기 시 올바른 RPC 라우팅 필수
### [2026-03-10] active_project.lock — 멀티 프로젝트 동시 사용 차단
- **증상**: 여러 AG 프로젝트 실행 시 첫 번째만 bridge 연결
- **원인**: `active_project.lock` 파일이 단일 프로젝트만 허용
- **해결**: lock 메커니즘 완전 제거, `project_name` 필터 기반으로 전환
- **주의**: bridge 격리는 `project_name` 필드 기반 filtering으로 충분
### [2026-03-10] step_probe file_permission — 3-button 미주입
- **증상**: Discord에 3개 선택지 대신 2개만 표시
- **원인**: `writePendingApproval()`이 buttons 배열 미주입
- **해결**: `step_type === 'file_permission'`일 때 자동 3-button 배열 주입
- **주의**: DOM observer 경로는 기존 command 텍스트 기반 감지 유지
### [2026-03-10] GetAllCascadeTrajectories — 크로스 윈도우 세션 가로채기
- **증상**: Deriva AG에서 대화 시작 → gravity_control 채널에 Deriva 내용이 릴레이
- **원인**: `GetAllCascadeTrajectories`가 모든 인스턴스의 세션 반환
- **해결**: `workspaces[0].workspaceFolderAbsoluteUri` 비교하여 자기 workspace 세션만 처리
- **주의**: workspace URI normalize 필수 (protocol strip, %3A decode, 슬래시 통일, lowercase)
### [2026-03-10] 크로스 프로젝트 Response Watcher 우회
- **증상**: Deriva 세션 승인 시도가 gravity_control에서 실패
- **원인**: pending 파일 삭제 후 response watcher가 project_name 체크 건너뜀
- **해결**: response JSON의 project_name으로 fallback 필터
- **주의**: response 데이터 자체에 project_name 필수
### [2026-03-10] file_permission — write 도구 3-button 미주입
- **증상**: `replace_file_content` 등 파일 수정 시 Discord에 2개만 표시
- **원인**: step_probe의 file_permission 도구 리스트에 write 도구 누락
- **해결**: write 도구를 file_permission 리스트에 추가
- **주의**: AG가 파일 접근 권한을 요청하는 모든 도구는 이 리스트에 포함필요
### [2026-03-10] bestSession IDLE 고착 — RUNNING 세션 못 잡는 버그
- **증상**: 새 대화 시작 → bridge가 구 IDLE 세션만 추적
- **원인**: `bestSession` 선택이 `lastModifiedTime`만 비교
- **해결**: RUNNING 세션이 IDLE보다 항상 우선
- **주의**: Reload Window로도 해결되지만 근본적으로는 RUNNING 우선 로직 필요
### [2026-03-10] Bot IDLE 채널 자동 생성 — 불필요한 Discord 채널 증식
- **증상**: 봇 시작 시 모든 등록된 프로젝트의 채널을 자동 생성
- **원인**: `pending_approval_scanner`가 매 사이클마다 채널 생성
- **해결**: 자동 채널 생성 루프 제거, on-demand 생성
- **주의**: `_get_channel()`은 이미 on-demand 생성 로직 포함
### [2026-03-10] Reload Window 후 세션 stale
- **증상**: Reload Window 후 세션이 IDLE/구 stepCount로 고정
- **원인**: LS 프로세스는 유지되어 trajectory tracker 캐시 미갱신
- **해결**: AG 완전 종료 → 재실행 (Full restart)
- **주의**: Extension 코드 변경 후 배포 시 Full restart 권장
### [2026-03-10] start_bot.bat — Windows Store Python 스텁 우선 실행
- **증상**: `start_bot.bat` 실행 시 스텁이 먼저 실행
- **원인**: `where python`이 Windows Store의 Python 스텁을 먼저 찾음
- **해결**: conda 경로를 우선 확인
- **주의**: Windows 10/11에서 App Aliases의 python.exe가 PATH에 기본 포함
### [2026-03-10] VSIX 빌드 — SDK JS 파일 미포함 (require 실패)
- **증상**: Extension 활성화 후 `SDK not initialized`
- **원인**: TypeScript 컴파일러가 `.js` 파일을 `out/`에 복사하지 않음
- **해결**: `compile` 스크립트에 복사 단계 추가 (`src/sdk/``out/sdk/`)
- **주의**: VSIX 패키징은 `out/sdk/`를 포함함. 문제는 빌드 단계 복사 누락
### [2026-03-10] SDK _findLSProcess — 대소문자 구분 workspace hint 매칭 실패
- **증상**: variet-agent AG에서 Discord에 신호 미도달
- **원인**: SDK가 workspace hint를 대소문자 구분으로 비교
- **해결**: `fixLSConnection()` 함수로 대소문자 무시 비교 + 재연결
- **주의**: 각 AG 창마다 별도 LS 프로세스 존재 (workspace_id로 구분)
---
## 환경변수 / 설정 관련 (2026-03-11)
### [2026-03-11] config.py BRAIN_PATH — `.env` 빈 문자열 → CWD 해석 버그
- **증상**: 봇이 Extension의 snapshot/pending을 전혀 읽지 못함
- **원인**: `.env``BRAIN_PATH=` (빈 값)이면 빈 문자열 반환
- **해결**: `os.getenv("BRAIN_PATH") or default` 패턴
- **주의**: `os.getenv(key, default)`는 빈 값이라도 default 미사용
### [2026-03-11] Extension DEDUP MERGE — 크로스 프로젝트 pending 오염
- **증상**: `#ag-lifetimepd` 채널에 variet_agent의 승인 요청 표시
- **원인**: DEDUP 로직이 `project_name`을 체크하지 않음
- **해결**: 3곳 dedup 조건에 `project_name` 가드 추가
- **주의**: 모든 Extension 인스턴스가 동일한 `bridge/pending/` 디렉토리 공유
### [2026-03-11] Collector 동기 HTTP — aiohttp 전환
- **증상**: Collector가 이벤트 루프 전체 블로킹
- **원인**: `urllib.request.urlopen()` 사용 (blocking I/O)
- **해결**: `aiohttp.ClientSession` 기반 비동기 전환
- **주의**: `import aiohttp`는 lazy
---
## Rate Limit / 무한 루프 관련 (2026-03-12)
### [2026-03-12] RemoteTransport 429 무한 루프 — Extension 크래시 + AG 먹통
- **증상**: `429 Rate limited` 로그가 초당 수십 건 무한 반복
- **원인**: 3가지 복합 (백오프 없음 + 개별 HTTP 요청 + 공격적 rate limit)
- **해결**: 지수 백오프 + `Retry-After` 지원 + rate limit 완화
- **주의**: AG 먹통은 봇 자체가 유발한 문제
### [2026-03-12] workbench.html 0-byte 파괴 — AG 새 창 먹통
- **증상**: AG 새 창 열면 화면 먹통
- **원인**: 3개 Extension 인스턴스가 동시에 workbench.html 읽기/쓰기 → 0 bytes로 덮어쓰기
- **해결**: pre-patch backup(.orig) + 구조 검증 + 자동 복원
- **주의**: 멀티 윈도우 환경에서 HTML 패치 race condition은 파일 잠금 없이 완전 해결 불가
### [2026-03-12] workbench.html 크로스 복원 — CSS 미로딩으로 레이아웃 깨짐
- **증상**: 아이콘은 보이지만 레이아웃 완전 깨짐
- **원인**: workbench.html을 jetski HTML에서 복원할 때 CSS 교체 누락
- **해결**: 파일별 `requiredMarker` 검증 + `.orig` 백업 + 자동 복원
- **주의**: **workbench.html과 workbench-jetski-agent.html은 교환 불가능**
### [2026-03-12] Collector 단일 프로젝트 폴링 — 멀티 프로젝트 command 전달 불가
- **증상**: Deriva AG IDE에 명령 전달되지 않음
- **원인**: Collector가 단일 프로젝트만 폴링
- **해결**: `_discover_local_projects()`로 모든 프로젝트 폴링
- **주의**: `/api/commands/all` 엔드포인트는 크로스 PC 명령 오염을 유발
### [2026-03-12] RemoteTransport backing off 무한 반복
- **증상**: IDLE 시 `backing off 1s` 경고가 영구 반복
- **원인**: 3가지 구조적 결함 (즉시 리셋 + 불필요 요청 + asyncio burst)
- **해결**: 연속 5회 성공 후 절반 감소 + adaptive 간격 + 루프 stagger
- **주의**: `_reset_backoff()` 즉시 리셋 패턴은 다중 소비자 환경에서 **절대 사용 금지**
---
## DEDUP / 크로스 세션 관련 (2026-03-15)
### [2026-03-15] DEDUP step_index 크로스 세션 충돌 — 승인 신호 누락
- **증상**: WAITING step 감지 → pending 미생성 → 10분+ 대기
- **원인**: DEDUP 로직이 `conversation_id`를 비교하지 않음
- **해결**: DEDUP 조건에 `conversation_id` 가드 추가
- **주의**: `project_name` 가드만으로는 불충분 — 같은 Extension이 여러 세션을 볼 수 있음
### [2026-03-15] Discord Gateway MESSAGE_CREATE 중복 — embed 이중 전송
- **증상**: Discord 명령 시 동일 embed가 2개 전송
- **원인**: Discord Gateway가 WebSocket 불안정 시 이벤트 중복 전달
- **해결**: `on_message``_processed_message_ids` dedup 추가
- **주의**: Gateway reconnection, RESUME 실패 시 발생 빈도 증가
### [2026-03-15] HTML 패치 멀티 인스턴스 race condition — 화면 파괴
- **증상**: Extension 패치 후 AG 재시작 시 전체 화면 날아감
- **원인**: 2+ Extension 인스턴스가 동시에 같은 HTML에 readFileSync/writeFileSync
- **해결**: `.patch-lock` 파일 기반 cross-instance lock 추가
- **주의**: Lock은 "방지", .orig 백업은 "복구". 둘 다 유지
### [2026-03-15] 로컬 승인 ↔ Discord 승인 교차 race condition
- **증상**: AG에서 직접 Run 클릭 후 Discord 승인 요청이 "완료됨" 표시 안 됨
- **원인**: auto_resolve가 Discord에 알림 없음 + processResponseFile 상태 미체크
- **해결**: writeChatSnapshot 추가 + 상태 확인 후 skip + _approval_messages dict
- **주의**: processResponseFile L2534의 리셋이 핵심 gate
### [2026-03-15] 크로스 프로젝트 DEDUP MERGE — Deriva→gravity_control 오염
- **증상**: Deriva의 데이터가 gravity_control pending에 MERGE됨
- **원인**: MERGE 조건에 `project_name` 가드 없음
- **해결**: MERGE 조건에 `project_name` 추가
- **주의**: `bridge/pending/` 디렉토리는 모든 Extension 인스턴스가 공유
### [2026-03-15] Double-Fire Auto-Approve — AI 세션 중단
- **증상**: auto-approve ON 시 AI 세션이 간헐적으로 중단
- **원인**: Extension auto-approve 경로 + Bot auto-approve 경로 동시 실행 → 2번 RPC
- **해결**: Extension auto-approve 경로 제거. Bot만 담당
- **주의**: 단일 경로 원칙 유지
### [2026-03-15] DOM Observer "Deny" False Positive — Auto-approve 세션 크래시
- **증상**: auto-approve ON 시 "Deny" command가 자동 승인됨 → 세션 크래시
- **원인**: DOM observer가 Deny를 독립 pending으로 생성. default 분기로 잘못된 RPC 전송
- **해결**: FALSE_POSITIVE_RE에 Deny/Allow Once 등 추가 + reject-word 차단 가드
- **주의**: VSIX 빌드 → AG 풀 재시작 필요
### [2026-03-15] PATS 배열 Deny 트리거 — 근본 수정
- **증상**: Deny가 주 트리거로 사용됨
- **원인**: PATS 배열에 Deny 패턴 포함
- **해결**: PATS에서 거절/보조 버튼 제거. 긍정 버튼만 그룹 트리거
- **주의**: PATS = "그룹 생성 트리거", ALL_ACTION_RE = "형제 수집 패턴"
### [2026-03-15] Auto-Resolved 채팅 폭주 — 루프 내 writeChatSnapshot
- **증상**: "✅ AG에서 직접 승인됨" 메시지가 반복 전송
- **원인**: 루프 내부에서 매 파일마다 writeChatSnapshot 호출
- **해결**: 루프 바깥에서 1회 + conversation_id 조건 추가
- **주의**: 외부 시스템에 메시지 보낼 때는 반드시 루프 바깥에서 집계 후 1회 발송
### [2026-03-15] projectName=default 승인 오발
- **증상**: workspace 없는 AG 창이 다른 프로젝트의 WAITING을 감지
- **원인**: `detectProjectName()`이 workspace 없으면 "default" 반환
- **해결**: `projectName === 'default'`이면 pending 생성/auto-approve 억제
- **주의**: Empty Window에서는 bridge 기능을 최소화
### [2026-03-15] 이전 분석 오판(False Positive) — 교훈
- **증상**: P0/P1으로 보고한 문제들이 이미 방어되고 있었음
- **원인**: 로컬 코드 스니펫만 보고 판단
- **해결**: 전체 Flow 추적으로 교차 검증
- **주의**: **코드 감사 시 반드시 producer→transport→consumer→side effects 전체 경로를 추적**
---
## processResponseFile 상태 관리 (2026-03-16)
### [2026-03-16] processResponseFile 상태 리셋 — 무한 루프 vs auto_resolve 회귀
- **증상**: Discord 승인 후 같은 step에 대해 pending이 반복 생성 → 무한 auto-approve 루프
- **원인**: processResponseFile이 무조건 리셋 → step_probe가 같은 WAITING step을 새 step으로 착각
- **해결**: `sawRunningAfterPending = true`만 설정. lastPendingStepIndex와 stallProbed 유지
- **주의**: **processResponseFile의 상태 리셋은 sawRunningAfterPending = true만 설정**. `docs/approval-flow.md` 참조
### [2026-03-16] recentPendingSteps 메모리 dedup
- **증상**: pending 파일 삭제 → 같은 step_index로 새 pending 생성
- **원인**: writePendingApproval()의 dedup이 파일 존재 여부에만 의존
- **해결**: `recentPendingSteps` Map (TTL 60초) 추가
- **주의**: DOM observer HTTP 경로는 이 메모리 dedup 미적용
### [2026-03-16] 멀티 프로젝트 동시 신호 정지 — Scanner O(N) Discord API 병목
- **증상**: 여러 프로젝트 동시 pending → 모든 프로젝트 신호 전달 정지
- **원인**: scanner가 1 tick에 모든 pending 순차 처리 → Discord 429 rate limit
- **해결**: `discord.utils.get(guild.channels)` 캐시 + per-tick cap (5건)
- **주의**: `guild.channels`는 discord.py 내부 캐시
---
## Diff Review 관련 (2026-03-16)
### [2026-03-16] step_type 매핑 버그 — write_to_file이 file_permission으로 잘못 매핑
- **증상**: 코드 편집 승인 시 잘못된 RPC 전송
- **원인**: 쓰기 도구가 읽기 도구와 함께 `file_permission`으로 매핑
- **해결**: 읽기/쓰기 도구 분리, 쓰기는 `code_edit` step_type 사용
- **주의**: AG는 대부분 파일 쓰기에 WAITING 안 만듦
### [2026-03-16] diff_review isDirty 실패 — AG diff는 VS Code dirty 아님
- **증상**: Accept 클릭 → `isDirty` 문서 0개 → 효과 없음
- **원인**: AG stacked code review는 VS Code `isDirty`와 무관
- **해결**: `AcknowledgeCascadeCodeEdit` RPC → fallback으로 VS Code 커맨드
- **주의**: diff_review pending에 `modified_files``edit_step_indices` 필수
### [2026-03-16] diff_review pending 순서 — AI 응답보다 먼저 Discord 도착
- **증상**: diff_review 버튼이 먼저, AI 응답 텍스트가 나중
- **원인**: pending_approval_scanner가 chat_snapshot_scanner보다 먼저 fire
- **해결**: diff_review pending 생성을 `setTimeout(8000)`으로 지연
- **주의**: 8초는 전체 전파 경로 고려
### [2026-03-16] diff_review AcknowledgeCascadeCodeEdit steps=[] — Collector pending 삭제 race
- **증상**: Accept all 클릭 → RPC SUCCESS → diff review 바 안 사라짐
- **원인**: Collector가 pending 파일 즉시 삭제 → Extension이 메타데이터 못 읽음
- **해결**: `diffReviewMetadata` 인메모리 Map 추가
- **주의**: Extension Reload 시 소실되지만 새 diff_review는 정상 동작
### [2026-03-16] AcknowledgeCascadeCodeEdit SUCCESS → diff review bar 미해제 — 잘못된 RPC 메서드명
- **증상**: RPC SUCCESS 반환 → diff review bar 여전히 표시
- **원인**: RPC 메서드명 자체가 틀렸음 (`AcknowledgeCascadeCodeEdit` → 실제는 `acknowledgeCodeActionStep`)
- **해결**: `agentAcceptAllInFile` / `agentRejectAllInFile` VS Code 커맨드 사용
- **주의**: AG의 RPC는 잘못된 메서드명도 에러 없이 `{}` 반환. **RPC `{}`는 실패로 간주해야 함**
### [2026-03-16] diff_review RPC 3개 전략 모두 dead-end
- **증상**: 3개 RPC 전략 모두 실패
- **원인**: (1) submitCodeAcknowledgement 미등록, (2) acknowledgeCodeActionStep 404, (3) AcknowledgeCascadeCodeEdit no-op
- **해결**: VS Code 커맨드 기반 (`agentAcceptAllInFile` / `agentRejectAllInFile`)
- **주의**: **diff_review를 RPC로 해결하려는 시도 모두 실패 확정. VS Code 커맨드 기반만 유효**
### [2026-03-16] AG 소스 역분석 — diff review 내부 동작 체인
- **증상**: Accept all / Reject all 내부 동작을 재현해야 함
- **원인**: AG 공식 API/문서 없음
- **해결**: AG 설치 경로의 JS 소스에서 역분석
- **주의**: minified JS에서 변수명은 버전마다 변경됨
### [2026-03-16] diff_review 이중 승인 요청 — DOM observer가 Accept/Reject 버튼 캡처
- **증상**: diff_review 외에 별도 "Accept"/"Reject" pending 도착
- **원인**: `openReviewChanges` 커맨드가 diff UI 패널 → DOM observer 감지
- **해결**: FALSE_POSITIVE_RE에 Accept/Reject all 추가
- **주의**: diff review bar 버튼은 전용 시스템에서 처리
### [2026-03-16] diff_review가 brain/ artifact에도 트리거
- **증상**: task.md만 수정해도 "코드 리뷰" pending 생성
- **원인**: diff_review 감지 로직이 모든 수정 파일 추적
- **해결**: `.gemini/antigravity/brain/` 경로 파일 필터링하여 제외
- **주의**: 코드 파일 + brain artifact 혼합 시 코드 파일만 diff_review
---
## WS Hub 전환 관련 (2026-03-16~17)
### [2026-03-16] !auto 이중 메시지 — Extension echo + Bot embed
- **증상**: `!auto` 토글 시 메시지 2개 표시
- **원인**: Bot embed + Extension writeChatSnapshot echo
- **해결**: Extension의 `!auto` handler에서 writeChatSnapshot echo 제거
- **주의**: Bot 재시작 시 auto_approve_projects 초기화 → 수동 모드 복귀
### [2026-03-16] 병렬 WAITING step 누락 — step_probe break문
- **증상**: 병렬 tool call 시 1개만 승인 요청 도착
- **원인**: step_probe 루프에서 `break`문이 첫 번째 WAITING 후 종료
- **해결**: `break` 제거, 모든 WAITING step에 pending 생성
- **주의**: 중복 방지는 `recentPendingSteps` Map이 처리
### [2026-03-16] Bot chat_snapshot 전송 로깅 부재
- **증상**: 전송 성공/실패를 Bot 로그에서 확인 불가
- **원인**: `channel.send()` 성공 후 INFO 로그 없음
- **해결**: 전송 성공/실패 로그 추가
- **주의**: `_get_channel()` 실패 시 WARNING은 이전에도 있었음
### [2026-03-16] 크로스 프로젝트 이벤트 폭주 — Watcher/Collector 무필터
- **증상**: /start 시 타 프로젝트 알림 유입
- **원인**: watcher.py가 brain/ 전체를 감시
- **해결**: `_is_my_session()` 필터 + 이벤트 전달 필터 추가
- **주의**: 미등록 세션은 allow-through 방식
### [2026-03-16] pending 파일 139개 누적 — 정리 로직 부재
- **증상**: bridge/pending/에 139개 파일 누적
- **원인**: auto_resolved/expired 파일을 아무도 삭제 안 함
- **해결**: Collector에서 auto_resolved/expired 전달 후 삭제 + 10분 자동 삭제
- **주의**: startup_pending은 정리 대상에서 제외
### [2026-03-17] NPM WebSocket 프록시 — Upgrade 헤더 미전달
- **증상**: `wss://ag.variet.net/ws` 연결 시 HTTP 400
- **원인**: Nginx Proxy Manager에 WebSocket Support 미활성화
- **해결**: NPM 대시보드에서 Websockets Support 체크
- **주의**: 새 프록시 호스트 생성 시 반드시 확인
### [2026-03-17] WS auth_fail 무한 재연결 — _cleanup() close 이벤트
- **증상**: Auth failed 후 60초마다 재연결 반복
- **원인**: `_cleanup()`이 ws.close() → close 이벤트 → _scheduleReconnect() 체인
- **해결**: `this.shouldReconnect = false``_cleanup()` 이전에 설정
- **주의**: `_cleanup()`은 이벤트 핸들러를 트리거하므로 상태 변경은 반드시 호출 전에
### [2026-03-17] initStepProbe workspaceUri 누락 — 세션 감지 완전 불능
- **증상**: POLL alive만 출력, SESSION-FILTER/SNAPSHOT 없음
- **원인**: `initStepProbe()` 호출 시 필수 필드 미전달 + `as` 캐스트가 런타임 검증 없음
- **해결**: `workspaceUri`, `diffReviewMetadata: new Map()` 추가
- **주의**: TypeScript `as` 캐스트는 런타임 검증 없음
### [2026-03-17] WS 명령어 에코 릴레이 — Discord 메시지 2번 표시
- **증상**: Discord 메시지 입력 → 같은 메시지가 다시 표시
- **원인**: handleWSCommand에서 `recentDiscordSentTexts`에 마킹 안 함
- **해결**: `recentDiscordSentTexts.set()` 추가
- **주의**: 파일 기반 경로에는 이미 마킹 있었음
### [2026-03-17] writeRegistration 이중 쓰기 — WS 전송 후 파일도 작성
- **증상**: WS 상태에서도 register/ 파일 생성
- **원인**: WS 전송 후 `return` 없이 파일 쓰기 실행
- **해결**: WS 전송 후 `return` 추가
- **주의**: 새 WS 전송 함수 추가 시 file fallback과 상호 배타적 `return` 확인

View File

@@ -4,12 +4,14 @@
> 디버깅이나 구현 전에 **반드시** 이 파일을 확인하세요. > 디버깅이나 구현 전에 **반드시** 이 파일을 확인하세요.
> 세션 종료 시 새로 발견된 이슈를 이 파일에 추가합니다. > 세션 종료 시 새로 발견된 이슈를 이 파일에 추가합니다.
> [!TIP]
> 해결 완료된 과거 이슈는 [`known-issues-archive.md`](file:///c:/Users/Variet-Worker/Desktop/gravity_control/.agents/references/known-issues-archive.md)에 보관되어 있습니다.
> 비슷한 문제가 재발하면 archive에서 검색하세요.
--- ---
## 포맷 ## 포맷
각 항목은 아래 형식을 따릅니다:
```markdown ```markdown
### [날짜] [키워드] — 한줄 요약 ### [날짜] [키워드] — 한줄 요약
- **증상**: 무엇이 잘못되었는가 - **증상**: 무엇이 잘못되었는가
@@ -22,24 +24,6 @@
## 공통 이슈 ## 공통 이슈
### [2026-03-17] Hub pending_owners 생명주기 — WS 재연결 시 승인 응답 소실
- **증상**: Discord에서 승인 클릭해도 AG Extension에서 아무 동작 안함 (이중 메시지 전달 이후 특히 발생)
- **원인**: `hub.py _disconnect()` 에서 Extension 연결이 끊기면 `pending_owners[rid]`를 **삭제**함. Extension이 재연결하면 새 conn_id 할당되지만, 기존 pending의 owner 정보는 이미 삭제됨. `send_response_to_pending_owner()`가 owner를 찾지 못해 `False` 반환. File bridge fallback은 Docker 컨테이너 볼륨에 파일 작성하므로 Extension 접근 불가.
- **해결**: (1) `_disconnect`에서 삭제 대신 같은 project 다른 연결로 재할당, (2) `_register_connection`에서 orphaned pending_owners를 새 conn_id로 재할당, (3) `send_response_to_pending_owner`에 같은 project 활성 연결 fallback 추가
- **주의**: Gateway 모드에서 file bridge fallback은 **완전히 무용** — Docker 볼륨에 파일 작성하지만 Extension은 로컬 bridge/ 감시. **WS 라우팅 실패 시 file bridge에 의존하지 말 것**.
### [2026-03-17] diff_review Accept All WS 경로 regression (v0.4.5 fix)
- **증상**: Discord에서 Accept all 클릭해도 AG에서 반응 없음
- **원인**: v0.4.0 WS 전환 시 `onResponse` 핸들러에 `diff_review` step_type 분기가 누락됨. `processResponseFile` (파일 경로)에만 diff_review 로직이 있었고, WS `onResponse`는 무조건 `tryApprovalStrategies()`만 호출. `tryApprovalStrategies`는 diff_review를 처리하지 않음
- **해결**: `step-probe.ts``handleDiffReviewResponse()` export 함수 추출. `extension.ts` `onResponse`에서 `stepType === 'diff_review'`일 때 이 함수 호출
- **주의**: **WS 경로 추가 시 file-bridge 경로의 모든 분기를 반드시 포팅할 것**. step_type별 분기(diff_review, file_permission 등)가 누락되기 쉬움
### [2026-03-17] _auto_approve_via_hub 이중 쓰기 (v0.4.5 fix)
- **증상**: auto-approve 시 Extension에 응답이 2번 도착
- **원인**: `bot.py:_auto_approve_via_hub()` L1095-1100에서 Hub WS 전송 후 `return` 없이 file bridge에도 씀
- **해결**: `if self.hub:` → WS 전송 + `else:` → file bridge. if/else 구조로 변경
- **주의**: Hub WS와 file bridge는 **항상 상호 배타적**이어야 함. `return`이 아닌 `if/else` 사용 권장
### [2026-03-08] PowerShell curl — Invoke-WebRequest 충돌 ### [2026-03-08] PowerShell curl — Invoke-WebRequest 충돌
- **증상**: `curl` 명령이 예상과 다른 응답 형식을 반환 - **증상**: `curl` 명령이 예상과 다른 응답 형식을 반환
- **원인**: PowerShell에서 `curl``Invoke-WebRequest`의 별칭 - **원인**: PowerShell에서 `curl``Invoke-WebRequest`의 별칭
@@ -48,690 +32,81 @@
### [2026-03-08] PowerShell npm — 실행 정책 오류 ### [2026-03-08] PowerShell npm — 실행 정책 오류
- **증상**: `npm run` 명령이 `실행 정책` 관련 오류로 실패 - **증상**: `npm run` 명령이 `실행 정책` 관련 오류로 실패
- **원인**: PowerShell 스크립트 실행 정책이 제한적으로 설정됨 - **원인**: PowerShell 스크립트 실행 정책이 제한적
- **해결**: `cmd /c npm run dev` 형식으로 cmd를 통해 실행 - **해결**: `cmd /c npm run dev` 형식으로 cmd를 통해 실행
- **주의**: npm 관련 명령은 항상 `cmd /c` 접두어 사용 권장 - **주의**: npm 관련 명령은 항상 `cmd /c` 접두어 사용 권장
--- ---
## 프로젝트별 이슈 ## 미해결 이슈
> 아래에 프로젝트 특화 이슈를 추가하세요. ### [2026-03-11] fs.watch silent fail — Discord→Extension 명령 전달 불가
- **증상**: `!auto`, `!stop`, 텍스트 릴레이 등 Discord→Extension 방향 명령이 전부 작동 안 함. Extension log에 `[AUTO]` 로그 0건
### [2026-03-08] Antigravity Renderer Injection — Electron 캐시 차단 - **원인**: `watchCommandsDir()``fs.watch`가 Windows에서 silent fail. watcher 세팅은 되지만 이벤트가 실제로 fire 안 됨
- **증상**: workbench.html, workbench-jetski-agent.html에 `<script>` 태그 추가 후 리로드해도 실행되지 않음 - **해결**: `fs.watch` 유지 + 3초 `setInterval` 폴링 fallback 추가. `processAllCommands()` 함수로 공통화
- **원인**: Electron의 V8 코드 캐시가 수정된 HTML을 무시하고 캐시된 버전을 서빙 - **주의**: `fs.watch`는 Windows에서 구조적으로 불안정. **새 watcher 추가 시 반드시 polling fallback 병행**
- **해결**: 렌더러 인젝션 방식 **포기**. Extension Host에서 RPC 폴링 방식으로 전환
- **주의**: Antigravity는 `workbench-jetski-agent.html`을 사용 (Jetski = 내부 코드네임)
### [2026-03-08] Antigravity 승인 대기 = RUNNING (NOT IDLE)
- **증상**: IDLE 기반 승인 감지가 실제 승인 대기를 놓침
- **원인**: 승인 대기 시 세션 상태가 `CASCADE_RUN_STATUS_RUNNING` (IDLE 아님), `IDLE`은 대화 대기(notify_user 후)
- **해결**: `RUNNING + delta=0` (stall) 기반 감지로 전환. 6 polls (30초) 이상 FROZEN 시 pending 생성
- **주의**: Thinking/생성 중에도 `RUNNING + delta=0`이 발생 → `lastModifiedTime`으로 구분 시도했으나 불완전
### [2026-03-08] ResolveOutstandingSteps RPC — 승인이 아닌 취소!
- **증상**: Discord 승인 → `ResolveOutstandingSteps` 호출 → step이 취소됨
- **원인**: `ResolveOutstandingSteps`는 blocking steps를 "resolve" = **REJECT/CANCEL**, approve가 아님
- **해결**: `ResolveOutstandingSteps` 제거. `HandleCascadeUserInteraction``socket hang up`
- **주의**: KI에 "more reliable"로 기록되어 있으나 실제 동작은 cancel임. KI 업데이트 필요
### [2026-03-08] VS Code Accept Commands — Silent Success 문제
- **증상**: 4개 accept command 모두 OK(undefined) 반환하나 실제 승인 안 됨
- **원인**: webview에 활성 포커스가 필요. `panel.focus()`로는 충분하지 않음
- **해결**: **미해결**. Windows UI Automation 등 OS 레벨 접근 필요
- **주의**: reject commands는 동작함. accept만 focus 의존성 있음
### [2026-03-08] Multi-Window 세션 등록 경쟁 조건
- **증상**: 이 창(gravity_control)의 대화가 `#ag-variet_agent` 채널로 메시지 전달
- **원인**: `writeRegistration()`이 폴링 루프에서 호출 → 먼저 폴링한 확장이 세션을 자기 프로젝트로 등록
- **해결**: `writeRegistration`을 폴링에서 제거, `writeChatSnapshot`/`writePendingApproval`에서만 지연 호출
- **주의**: `GetAllCascadeTrajectories`는 모든 창의 세션을 반환하므로 세션→창 매핑은 불가능. 활동 기반 등록만 신뢰 가능
### [2026-03-08] 공유 렌더러 스크립트 파일 덮어쓰기 문제
- **증상**: DOM Observer 렌더러 스크립트가 잘못된 HTTP bridge 포트에 연결
- **원인**: 두 확장이 동일한 `ag-sdk-variet-gravity-bridge.js` 파일에 각자 포트를 씀 → 마지막 확장 것만 남음
- **해결**: `ag-bridge-ports.json`에 모든 확장의 port를 JSON으로 기록, 렌더러가 all ports를 순회하며 ping
- **주의**: 렌더러 스크립트 파일 경로는 SDK patcher namespace에 의해 고정 — 변경 불가
### [2026-03-08] workbench.html vs workbench-jetski-agent.html
- **증상**: 렌더러에서 `[GB Observer]` 로그가 전혀 안 나옴
- **원인**: DevTools가 `workbench.html`을 로드 — 스크립트 태그는 `workbench-jetski-agent.html`에만 패치됨
- **해결**: `workbench.html`에도 스크립트 태그 필요. Antigravity 재설치 후 SDK patcher가 올바르게 패치하도록 함
- **주의**: SDK patcher는 `both` HTML 파일을 패치하지만, 수동 수정은 Antigravity integrity check에 의해 되돌려질 수 있음
### [2026-03-08] product.json 체크섬 불일치 → 렌더러 스크립트 미로딩
- **증상**: `<script>` 태그가 HTML에 존재하고 .js 파일도 디스크에 있으나, 렌더러 콘솔에 스크립트 로그가 전혀 없음
- **원인**: Antigravity 재설치 시 `product.json`의 SHA256 체크섬이 원본으로 리셋됨. Extension이 HTML을 패치하지만 `IntegrityManager.suppressCheck()`를 호출하지 않아 체크섬 불일치. `vscode-file://` 프로토콜이 체크섬 불일치 파일을 무시하고 **원본 캐시 HTML**을 서빙
- **해결**: `product.json``checksums` 항목에서 수정된 파일(workbench.html, workbench-jetski-agent.html)의 SHA256 해시를 실제 파일 기준으로 업데이트. SDK `IntegrityManager.suppressCheck()` 호출 또는 수동 스크립트로 해결
- **주의**: Extension `setupApprovalObserver()``suppressCheck()` 호출을 영구 추가해야 재설치마다 반복 안 됨. 해시 = `base64(sha256(file)).replace(/=+$/, '')`
### [2026-03-08] vscode-file:// 프로토콜 — 커스텀 .js 파일 서빙 불가
- **증상**: `<script src="./ag-sdk-variet-gravity-bridge.js">` 태그가 HTML에 있으나 `net::ERR_FILE_NOT_FOUND` 발생, GB Observer 로그 전혀 없음
- **원인**: `vscode-file://` 프로토콜은 원본 배포에 포함된 파일만 서빙. Extension이 디스크에 쓴 커스텀 `.js` 파일은 프로토콜 레벨에서 차단됨
- **해결**: 외부 `<script src>` 참조 대신 **인라인 `<script>...코드...</script>`** 방식으로 HTML에 직접 삽입
- **주의**: `ag-bridge-ports.json`도 같은 이유로 XHR 로딩 불가. 모든 렌더러 스크립트/데이터는 HTML 인라인으로 전달해야 함
### [2026-03-08] Renderer 포트 디스커버리 — ag-bridge-ports.json XHR 실패
- **증상**: `[GB Observer] Port discovery timeout after 2min` — 렌더러가 bridge 포트를 찾지 못함
- **원인**: 렌더러 스크립트가 `./ag-bridge-ports.json`을 동기 XHR로 읽으려 하나, `vscode-file://` 프로토콜이 `.json` 파일 서빙 거부
- **해결**: (1) 프로젝트명 해시 기반 **결정론적 포트** 사용 (`gravity_control→34332`), (2) 스크립트 생성 시 포트를 `HARDCODED_PORT=${port}`로 직접 삽입
- **주의**: `server.listen(0)` 랜덤 포트 → 매 재시작마다 변경되어 렌더러와 불일치. 결정론적 포트는 `EADDRINUSE` 시 랜덤 폴백 필요
### [2026-03-08] Extension 컴파일 경로 != 설치 경로
- **증상**: `npm run compile` 후 Extension 동작이 변하지 않음
- **원인**: `npm run compile``extension/out/extension.js`에만 빌드. Antigravity는 `~/.antigravity/extensions/variet.gravity-bridge-X.X.X/out/extension.js`에서 로드
- **해결**: 컴파일 후 반드시 설치 경로로 수동 복사하거나, `vsce package` → VSIX 재설치
- **주의**: `extension/out/` ≠ 실행 경로. 항상 설치 경로 확인 필요
### [2026-03-08] Electron 메인 프로세스 체크섬 캐시 — Reload Window 불충분
- **증상**: product.json 체크섬 업데이트 + HTML 패치 후 `Reload Window` → 패치 미적용
- **원인**: Electron 메인 프로세스가 시작 시 product.json 체크섬을 메모리에 캐시. `Reload Window`는 렌더러만 재시작하므로 캐시된 구 체크섬 사용
- **해결**: Antigravity를 **완전 종료 후 재시작** 필요 (File → Exit 후 재실행)
- **주의**: `Reload Window` ≠ 앱 재시작. 체크섬 변경 시 항상 풀 재시작 필요
### [2026-03-08] Renderer 동기 XHR — Electron 보안 정책 차단
- **증상**: `tryPing()` 함수가 동기 `XMLHttpRequest`로 HTTP bridge에 연결 시도 → 타임아웃
- **원인**: Electron 렌더러 프로세스에서 동기 XHR이 보안 정책에 의해 차단됨
- **해결**: `fetch()` + `AbortSignal.timeout(2000)` 비동기 방식으로 교체 (`tryPingAsync`)
- **주의**: `async/await` 사용 불가 (ES5 환경). `.then()` 체이닝으로 구현
### [2026-03-08] DOM Observer — Run 버튼 감지 불가 (webview iframe 격리)
- **증상**: Allow Once/Allow This Conversation는 감지되나 Run/Accept 버튼은 감지 안 됨
- **원인**: Trust/permission 버튼은 워크벤치 외부 DOM에 렌더링, Run/Accept는 **Antigravity 채팅 webview iframe** 내부의 별도 DOM에 렌더링. 렌더러 스크립트의 `document.querySelector()`는 iframe 내부 접근 불가
- **해결**: Run 버튼은 DOM Observer가 아닌 **`latestToolCallStep` RPC 기반** 즉시 감지로 대체
- **주의**: webview iframe에 스크립트 주입은 Electron `executeJavaScript()`로 가능하나, 현재 RPC 방식이 더 안정적
### [2026-03-08] Accept all/Reject all 리뷰 바 — agent 패널 밖 DOM
- **증상**: 코드 변경 리뷰 바(Accept all/Reject all)가 DOM Observer에 감지 안 됨
- **원인**: `scan()` 함수가 `findPanel()` (`.antigravity-agent-side-panel` 등) 내부만 검색. 리뷰 바는 에디터/notification 영역에 렌더링되어 패널 밖에 있음
- **해결**: `scan()` 검색 범위를 `document.body` 전체로 확장, `Accept all` / `Reject all` 패턴 추가
- **주의**: 패널+body 이중 검색 시 dedupe 필요 (같은 버튼이 두 번 잡힐 수 있음)
### [2026-03-08] GetCascadeTrajectorySteps — cascadeId 파라미터 발견
- **증상**: `GetCascadeTrajectorySteps``trajectoryId` 파라미터 → 500 "trajectory not found"
- **원인**: 파라미터명이 `trajectoryId`가 아니라 **`cascadeId`**. 값은 `GetAllCascadeTrajectories.trajectorySummaries`의 맵 키(세션 ID)
- **해결**: `{ cascadeId: sessionId }`로 호출 → 전체 step 배열 반환 성공
- **주의**: `latestToolCallStep` 필드는 `GetAllCascadeTrajectories` 응답에 **존재하지 않음** (KI 오류)
### [2026-03-08] Step 구조 — CORTEX_STEP_STATUS_WAITING 즉시 감지
- **증상**: stall-based 감지(100초)가 너무 느림
- **원인**: 이제 `GetCascadeTrajectorySteps`로 최신 step의 status를 직접 확인 가능
- **해결**: stall 5초 후 step probe → `CORTEX_STEP_STATUS_WAITING` 확인 → 즉시 pending 생성
- **Step 구조**: `{type: "CORTEX_STEP_TYPE_RUN_COMMAND", status: "CORTEX_STEP_STATUS_WAITING", metadata: {toolCall: {name, argumentsJson}}, runCommand, requestedInteraction}`
- **주의**: 775-step 하드 리밋은 여전히 존재. 긴 세션에서는 fallback(40초) 사용
### [2026-03-08] Extension 재설치 안전성 — 자동 패치 메커니즘
- **증상**: Antigravity 삭제 후 재설치 시 렌더러 스크립트가 동작 안 함
- **원인**: 재설치 시 HTML/product.json이 원본으로 리셋됨
- **해결**: Extension의 `setupApprovalObserver()`**자동으로** 모든 패치를 수행:
1. `workbench.html` + `workbench-jetski-agent.html` 인라인 스크립트 삽입
2. `product.json` SHA256 체크섬 자동 업데이트
3. HTTP bridge 서버 시작 + 결정론적 포트
- **주의**: 패치 후 반드시 **Antigravity 풀 재시작** 필요 (Reload Window 불가). Extension VSIX만 설치하면 수동 패치 불필요
### [2026-03-08] Response 파일 Race Condition — DOM Observer 승인 실패
- **증상**: Discord에서 승인 → `[RESPONSE] renderer-handled approval` 로그 출력 → 실제 버튼 클릭 안 됨
- **원인**: `processResponseFile` (파일 감시자)이 response 파일을 즉시 삭제 → renderer의 `pollResponse`가 HTTP `GET /response/:rid`로 조회 시 파일 이미 없음
- **해결**: DOM observer 소스일 때는 response 파일을 삭제하지 않도록 수정. HTTP endpoint가 renderer에게 서빙한 후 삭제
- **주의**: non-DOM (stall/step_probe relay)는 watcher에서 삭제해도 됨
### [2026-03-08] Renderer 스크립트 소스 혼동 — 3곳의 코드
- **증상**: `extension.ts`에 BTN-DUMP 추가 → Reload 2번 → 콘솔에 안 나옴
- **원인**: renderer 코드가 **3곳**에 존재: (1) `extension.ts`의 `generateApprovalObserverScript()` (소스), (2) `ag-sdk-variet-gravity-bridge.js` (배포됨, Reload시 소스에서 재생성), (3) `workbench-jetski-agent.html` inline (HTML, JS파일과 중복로드 방지됨). 직접 JS파일 패치는 Reload시 소스에서 재생성되어 **덮어씌워짐**
- **해결**: 항상 `extension.ts``generateApprovalObserverScript()` 함수를 수정 → 컴파일 → 배포 → Reload
- **주의**: HTML inline은 JS파일이 먼저 로드되어 `window.__agSDK` 가드에 의해 실행 안 됨. 실제 실행되는 것은 JS파일 경로의 스크립트
### [2026-03-09] VS Code Accept — SDK 승인 명령이 AG에 미등록
- **증상**: Discord 승인 → `antigravity.terminalCommand.run` 등 7개 명령 → 모두 `command not found`
- **원인**: SDK(command-bridge.ts)에 정의된 7개 승인 명령이 현재 AG 빌드에 **등록되어 있지 않음**. 활성 시 72개, 세션 중 119개로 동적 등록되지만 승인 관련 명령은 없음
- **검증**:
- `HandleCascadeUserInteraction` RPC 3 variants → 모두 `socket hang up`
- `ResolveOutstandingSteps``run state not found` (500 에러, 실제로는 CANCEL 동작)
- `sendChatActionMessage`, `executeCascadeAction` → 119개 명령 중 미등록
- 존재하는 approval-like 명령: `agentAcceptAllInFile` (코드 diff), `agentAcceptFocusedHunk` (hunk), `acceptCompletion` (자동완성) — 터미널 승인과 무관
- **해결**: ~~Renderer DOM Click 구현됨 (미검증)~~**v1 검증 실패: webview iframe 격리 확인**. v3 `deepFindButtons()`로 업그레이드 (iframe contentDocument + webview.executeJavaScript + shadow DOM). AG 완전 재시작 후 DOM-DUMP로 접근 가능 여부 확인 필요
- **주의**: `agentPanel.focus`도 미등록, `agentSidePanel.focus`만 존재
### [2026-03-09] Renderer DOM — webview iframe 격리 확인 + v3 deep traversal
- **증상**: Renderer trigger-click이 `document.querySelectorAll('button')`으로 버튼 검색 → Run 버튼 미발견. 감지된 것은 외부 DOM의 trust-level 버튼(`RunAlt+?`)뿐
- **원인**: Run/Accept 버튼은 AG 채팅 webview iframe (`vscode-webview://` origin) 안에 렌더링. 외부 workbench DOM (`vscode-file://` origin)에서 cross-origin으로 접근 불가
- **해결**: Renderer v3 `deepFindButtons()` 구현:
1. Main document 검색 (기존)
2. `iframe.contentDocument` 접근 시도 (same-origin이면 성공)
3. `<webview>.executeJavaScript()` 접근 시도 (Electron API)
4. Shadow DOM 재귀 탐색
**미검증** (AG 재시작 후 DOM-DUMP 결과 필요)
- **주의**: CDP(Chrome DevTools Protocol)는 **사용자 결정에 의해 명시적으로 거부됨** (`--remote-debugging-port` 필요, 비표준 접근). 표준 DOM API/Electron API 범위 내에서만 해결할 것
### [2026-03-09] Deep Inspect HTTP Endpoint — curl로 DOM 분석 트리거
- **증상**: AG DevTools 콘솔에 붙여넣기 불가 (Chromium 보안 정책)
- **원인**: Electron 렌더러 DevTools에서 `allow pasting`이 SyntaxError 발생 (`Unexpected identifier 'pasting'`)
- **해결**: Extension HTTP bridge에 `/deep-inspect` 엔드포인트 추가. `curl.exe http://127.0.0.1:34332/deep-inspect`로 bridge→renderer→재귀 DOM 분석→결과 JSON 반환. 결과는 `~/.gemini/antigravity/bridge/deep-inspect-result.json`에도 저장됨
- **주의**: 시작 3초 후 자동 실행 + curl로 재트리거 가능. renderer가 2초마다 `/deep-inspect-trigger` 폴링
---
### [2026-03-09] workbench.html inline 스크립트 미삽입 — jetski만 패치한 버그
- **증상**: AG 재시작 후 `/deep-inspect` timeout — renderer v3 스크립트 미로딩
- **원인**: `setupApprovalObserver()``workbench-jetski-agent.html`에만 inline 삽입하고, `workbench.html`에는 외부 `<script src>`만 추가. `vscode-file://` 프로토콜은 커스텀 .js 파일을 서빙하지 않으므로 사실상 미로딩
- **해결**: HTML 패치 로직을 `htmlFiles = ['workbench.html', 'workbench-jetski-agent.html']` 루프로 변경하여 **양쪽 모두 inline** 삽입. 수동 pre-patch 스크립트(`/tmp/patch_workbench.py`)로 즉시 적용 + product.json 체크섬 업데이트
- **주의**: **항상 양쪽 HTML을 동일하게 패치**. AG가 어느 HTML을 로드할지 런타임까지 알 수 없음. pre-patch 후 1회 풀 재시작이면 충분 (체크섬 사전 업데이트 완료)
### [2026-03-09] V8 CachedData — 체크섬 정상이어도 스크립트 미실행
- **증상**: HTML 패치 + product.json 체크섬 일치 + Bridge 서버 정상 → 그런데도 renderer 스크립트 미실행 (`/deep-inspect` timeout)
- **원인**: AG 프로세스 인자 `--code-cache-schemes=vscode-webview,vscode-file`에 의해 V8 바이트코드 캐시가 `vscode-file://` 프로토콜에도 적용. product.json 체크섬 검증과 V8 코드 캐시는 **별도 메커니즘** — 체크섬이 맞아도 V8은 `%APPDATA%\Antigravity\CachedData`의 이전 컴파일된 바이트코드를 재사용
- **해결**: `%APPDATA%\Antigravity\CachedData\*` 전체 삭제 후 AG 풀 재시작. AG 실행 중에도 삭제 가능 (파일 잠금 없음 확인됨)
- **주의**: CachedData 삭제 후 첫 시작이 약간 느릴 수 있음 (V8이 모든 JS를 재컴파일). **HTML 패치 변경 시마다 CachedData 삭제 필수**. `product.json` 체크섬 업데이트만으로는 불충분
---
## 승인 전략 결정 체인 (다음 세션 필독)
> **이 섹션은 2026-03-08~09 전체 세션의 시행착오를 요약합니다.**
> **다음 세션은 이미 거부된 접근을 다시 시도하지 마세요.**
### ❌ 시도 후 거부된 접근 (재시도 금지)
| # | 접근 | 결과 | 거부 사유 |
|---|------|------|-----------|
| 1 | LS RPC `HandleCascadeUserInteraction` | `socket hang up` | AG 빌드에서 핸들러 미구현 |
| 2 | LS RPC `ResolveOutstandingSteps` | CANCEL 동작 (승인이 아님) | 명칭과 달리 step을 취소함 |
| 3 | VS Code 7개 승인 명령 (`terminalCommand.run` 등) | `command not found` | AG 런타임에 미등록 |
| 4 | 키보드 시뮬레이션 (`type {Enter}`) | 빈 메시지 전송 | Chat input에 캡처됨 |
| 5 | `sendChatActionMessage` / `executeCascadeAction` | 미등록 | 119개 명령에 없음 |
| 6 | pywinauto (OS 레벨) | 사용자 결정 폐기 | 크로스플랫폼 불가, 창 겹침 문제 |
| 7 | CDP (Chrome DevTools Protocol) | **사용자 명시적 거부** | 비표준, `--remote-debugging-port` 필요 |
| 8 | Renderer v1 DOM Click (flat scan) | Run 버튼 미발견 | webview iframe 격리 |
### ✅ 현재 진행 중인 접근
| # | 접근 | 상태 | 다음 단계 |
|---|------|------|-----------|
| 1 | **Renderer v3 Deep DOM Traversal** | 패치+체크섬 OK, **V8 CachedData 삭제 완료, AG 재시작 후 검증** | AG 재시작 → `curl.exe http://127.0.0.1:34332/deep-inspect` |
| 2 | `<webview>.executeJavaScript()` | v3에 포함, **미검증** | 위 결과에서 `hasExecJS=true`이면 유력 |
| 3 | TerminalExecutionPolicy.EAGER (Turbo) | 미시도, **최후 수단** | 통제권 포기이므로 사용자 승인 필요 |
### 🔑 핵심 전제
- Run/Accept 버튼은 **`vscode-webview://` origin의 격리된 iframe** 안에 있음
- 외부 workbench DOM에서 `querySelector`로 접근 **불가** (cross-origin)
- `<webview>.executeJavaScript()`**유일한 표준 관통 경로** (Electron API)
- AG 패치 후 **반드시 풀 프로세스 재시작** 필요 (Reload Window 불충분)
- **양쪽 HTML (workbench.html + workbench-jetski-agent.html) 모두 inline 패치** 필수
- HTML 패치 변경 시 **`%APPDATA%\Antigravity\CachedData` 삭제 필수** (V8 바이트코드 캐시 무효화)
- **CSP `script-src``'unsafe-inline'` 패치 필수** (없으면 인라인 스크립트 무조건 차단)
### [2026-03-09] CSP script-src — 인라인 스크립트 무조건 차단
- **증상**: HTML 패치 ✅, 체크섬 ✅, CachedData 삭제 ✅ — 그런데도 renderer v3 스크립트 미실행 (`/deep-inspect` timeout)
- **원인**: `workbench.html`의 CSP `<meta http-equiv="Content-Security-Policy">`에서 `script-src 'self' 'unsafe-eval' blob:`**`'unsafe-inline'` 없음**. 브라우저가 인라인 `<script>` 태그를 무조건 차단
- **해결**: CSP의 `script-src``'unsafe-inline'` 추가. Extension `setupApprovalObserver()`에 CSP 자동 패치 로직 영구 추가
- **주의**: `style-src`에는 `'unsafe-inline'`이 있어 스타일은 동작 → 스크립트만 차단되는 것이 함정. `connect-src``http://127.0.0.1:*` 존재하여 HTTP fetch는 허용됨 (CSP 통과 시 통신은 문제없음). 이 CSP 이슈는 **V8 CachedData 이슈와 동시에 존재**하여 진단이 매우 어려웠음
### [2026-03-09] 중복 승인 요청 — DOM scan + Step probe 동시 발동
- **증상**: Discord에 같은 명령에 대해 승인 요청이 2개 도착
- **원인**: DOM Observer가 `RunAlt+↵` 버튼을 감지하여 pending 생성 + Step probe가 `CORTEX_STEP_STATUS_WAITING` 감지하여 pending 생성 → 동일 step에 대해 2개 파일
- **해결**: `writePendingApproval()`에 15초 dedup 윈도우 추가 — 최근 DOM observer pending이 있으면 step probe pending 스킵
- **주의**: DOM scan은 제거 불가 — `Allow Once`, `Allow This Conversation` 등 step probe가 감지 못하는 UI 버튼 존재. 버튼 텍스트도 `(Alt|Ctrl|Shift|Meta)\+.*` 정규식으로 키보드 단축키 정제
### [2026-03-09] Step probe reject → ResolveOutstandingSteps가 AI 작업 취소
- **증상**: Discord에서 거부 클릭 → AI의 현재 step뿐 아니라 진행 중인 작업 전체가 중단
- **원인**: step probe 경로의 `tryApprovalStrategies(approved=false)``ResolveOutstandingSteps` RPC 호출 → 이것은 step을 **CANCEL**하는 파괴적 동작
- **해결**: step probe 경로에서 reject 시 `tryApprovalStrategies` 호출 제거. reject은 로그만 남기고 파기적 동작 없음. DOM observer 경로만 실제 Reject 버튼 클릭 허용
- **주의**: `ResolveOutstandingSteps`는 이름과 달리 "해결"이 아닌 "취소". 승인에 절대 사용 금지 (이전 이슈 #55~59 참조)
### [2026-03-09] Pending 파일 무한 누적 — write_response 후 미삭제
- **증상**: `bridge/pending/` 디렉토리에 79개 이상의 .json 파일이 쌓여 봇 시작 시 폭주
- **원인**: `write_response()`가 pending 파일 status만 변경하고 삭제하지 않음. `get_pending_requests()`에 age filter 없음
- **해결**: (1) `write_response()`에서 pending 파일 삭제, (2) `get_pending_requests()`에 5분 age filter, (3) 시작 시 `_cleanup_stale_pending()` 호출
- **주의**: 봇 재시작 시 자동 정리. age filter는 expired 마킹 후 skip
### [2026-03-09] Discord 승인 "Run" 표시 — DOM/step_probe 타이밍 불일치
- **증상**: Discord에 상세 명령어 대신 "Run"만 표시
- **원인**: DOM observer가 "Run" pending 생성(t=0) → 봇이 3초 후 전송 → step_probe MERGE가 10초 후 완료 → 이미 전송 후
- **해결**: (1) step_probe가 기존 DOM pending에 MERGE (skip 대신 update), (2) 봇에서 짧은 명령어(≤15자) 4 cycles(12s) 대기, 매 cycle re-read하여 merge 즉시 전송
- **주의**: MERGE 타이밍은 step_probe poll interval(5s) + stall detection 필요하므로 최소 10초. defer는 이보다 길어야 함
### [2026-03-09] DOM observer false positive — Proceed/Continue/Open 버튼 오감지
- **증상**: 작업 전환 시(notify_user, task_boundary) 승인 요청 없는데도 Discord에 승인 요청 도착
- **원인**: DOM observer가 AG UI의 PathsToReview "Proceed"/"Open" 버튼, 파일 Open 버튼 등을 승인 버튼으로 오인
- **해결**: (1) HTTP POST /pending 핸들러에 false positive 필터 추가 (Proceed/Continue/Open/Close/OK 등), (2) "Run" 버튼은 `sessionStalled=true`일 때만 허용
- **주의**: renderer 인라인 스크립트(HTML)는 extension.js 배포로 안 바뀜 → 서버사이드 필터가 필수. PATS 패턴 수정은 HTML 재패치 시에만 적용
### [2026-03-09] Discord ApprovalView timeout — 5분 후 버튼 무응답
- **증상**: 시간이 지난 후 Discord 승인 버튼 클릭해도 반응 없음
- **원인**: Discord.py View의 기본 timeout이 300초(5분)로 설정됨
- **해결**: timeout을 1800초(30분)로 증가
- **주의**: Discord View timeout은 서버 재시작 후만 적용. 기존 메시지의 View는 이미 만료됨
### [2026-03-10] DOM Observer 승인 ENOENT — response 파일 Race Condition
- **증상**: Discord에서 ✅승인 → extension.log에 `ENOENT: response/xxx.json` 에러 → AG에서 Run 미실행 (간헐적)
- **원인**: `processResponseFile()` (response watcher)이 response 파일을 읽고 즉시 `fs.unlinkSync()` → renderer `pollResponse()``GET /response/:rid`로 조회할 때 파일 이미 없음
- **해결**: DOM observer 경로(`isDomObserver`)일 때 `processResponseFile()`에서 response 파일을 삭제하지 않고, HTTP handler(`GET /response/:rid`)가 renderer에 전달 후 삭제. step_probe 경로는 `clickTrigger`로 처리하므로 기존처럼 삭제 OK
- **주의**: DOM observer와 step_probe 두 경로가 독립적으로 pending을 생성할 수 있으므로, response 삭제 타이밍을 경로별로 구분해야 함
### [2026-03-10] Allow Once + Allow This Conversation — 별개 pending으로 분리되는 문제
- **증상**: 파일 접근 시 Allow Once와 Allow This Conversation이 Discord에 2개 별도 메시지로 도착. Deny 선택지 없음
- **원인**: renderer `scan()`이 한 사이클에 한 버튼만 처리 후 `return`. 각 버튼이 별도 pending으로 전송. Deny는 PATS 패턴에 미등록
- **해결**: (1) `scan()`에서 `findButtonContainer()`+`collectSiblingButtons()`로 같은 컨테이너의 관련 버튼을 그룹화하여 `buttons` 배열로 전송, (2) `bot.py` `ApprovalView``buttons` 배열이 있으면 `clear_items()` 후 동적 Discord 버튼 추가, (3) `bridge.py` `UserResponse``button_index` 추가, (4) renderer `pollResponseGroup()`에서 `button_index`에 따라 DOM 버튼 클릭
- **주의**: `buttons` 배열이 없는 legacy pending은 기존 2버튼(✅승인/❌거부)으로 표시. Deny를 PATS에 추가함
### [2026-03-10] step_probe verbosity — argumentsJson 미포함
- **증상**: Discord 승인 메시지에 `list_dir: DirectoryPath` (파라미터 이름만 표시, 값 없음)
- **원인**: `GetCascadeTrajectorySteps` 기본 verbosity에서 `argumentsJson` 필드가 빈 문자열
- **해결**: `verbosity: 1` (DEBUG)을 모든 step_probe 호출에 추가 → argumentsJson 포함. 추출 로직에 `DirectoryPath`, `SearchPath`, `AbsolutePath`, `Url`, `Query` 등 값 우선 표시
- **주의**: verbosity 0=NORMAL (키만), 1=DEBUG (값 포함). `Object.keys(args)` fallback은 값 추출 실패 시에만
### [2026-03-10] 파일 권한 응답 — "unexpected user interaction type: not file permission"
- **증상**: `.agents` 디렉토리 접근 시 "unexpected user interaction type: not file permission" 에러
- **원인**: 봇이 file_permission pending에 대해 `runCommand.confirm` RPC를 전송 (file_permission이 아닌 잘못된 interaction type). 또는 오래된 pending에 대해 봇이 자동 처리
- **해결**: (1) pending의 `step_type``file_permission`일 때 extension이 `filePermission` RPC 사용 (이미 구현됨), (2) DOM Observer의 file_permission 감지 → `buttons` 배열 + `step_type: 'file_permission'` 명시
- **주의**: 봇이 오래된 pending을 먼저 처리하면 타이밍 불일치 발생 가능. file_permission과 run_command가 동시에 대기 시 올바른 RPC 라우팅 필수
### [2026-03-10] active_project.lock — 멀티 프로젝트 동시 사용 차단
- **증상**: 동일 PC에서 여러 AG 프로젝트 실행 시 첫 번째 프로젝트만 bridge 연결, 나머지는 경고 후 비활성화 시도
- **원인**: `active_project.lock` 파일이 단일 프로젝트만 bridge 사용을 허용하는 설계. 그런데 `bridgeDisabled` 플래그 설정 후 실제로 아무것도 차단하지 않아 → 모든 인스턴스가 같은 pending/response/commands 디렉토리를 동시에 읽고 씀
- **해결**: (1) `active_project.lock` 메커니즘 완전 제거, (2) step_probe auto-resolve scan에 `project_name` 필터 추가, (3) response watcher의 기존 project_name 필터 유지
- **주의**: bridge 격리는 `project_name` 필드 기반 filtering으로 충분. 파일시스템 레벨 분리(옵션 B)는 불필요하게 복잡
### [2026-03-10] step_probe file_permission — 3-button 미주입
- **증상**: AG에서 파일 접근 권한 요청 시 Discord에 3개 선택지(Allow Once/Allow This Conversation/Deny) 대신 2개(승인/거부)만 표시
- **원인**: `writePendingApproval()``step_type: 'file_permission'`을 설정하지만 `buttons` 배열을 주입하지 않음. DOM observer의 `/pending` 핸들러는 `cmdLower.includes('allow')` 조건에서만 buttons 주입 → step_probe의 `view_file: /tmp/...` 형태 command에서는 trigger 안 됨
- **해결**: `writePendingApproval()`에서 `step_type === 'file_permission'` && `!buttons`일 때 자동으로 3-button 배열 주입
- **주의**: DOM observer 경로는 기존 command 텍스트 기반 감지 유지. step_probe 경로만 수정
### [2026-03-10] GetAllCascadeTrajectories — 크로스 윈도우 세션 가로채기
- **증상**: Deriva AG에서 대화 시작 → Discord에 신호 안 잡힘, gravity_control 채널에 Deriva 내용이 릴레이됨
- **원인**: `GetAllCascadeTrajectories` RPC가 **모든 AG 인스턴스의 세션**을 반환. 기존 register 파일 기반 필터링은 새 세션(아직 register 없음)에 대해 먼저 폴링한 인스턴스가 `bestSession`으로 가져감. gravity_control extension이 Deriva 세션을 자기 것으로 등록
- **해결**: `trajectoryMetadata.workspaces[0].workspaceFolderAbsoluteUri``vscode.workspace.workspaceFolders[0].uri.fsPath`와 비교하여 자기 workspace 세션만 처리. register 파일은 metadata 없는 레거시 세션용 fallback으로 유지
- **주의**: workspace URI는 `file:///c:/Users/...` 형식이므로 normalize 필수 (protocol strip, %3A decode, 슬래시 통일, lowercase). 양쪽 AG 풀 재시작 필요
### [2026-03-10] 크로스 프로젝트 Response Watcher 우회
- **증상**: Deriva 세션에 대한 승인 시도가 gravity_control에서 `stepIndex:-1`로 반복 실패
- **원인**: (1) pending 파일 삭제 후 response watcher가 project_name 체크 건너뜀, (2) `processResponseFile`이 전역 `activeSessionId` 사용
- **해결**: (1) response JSON의 `project_name`으로 fallback 필터, (2) 세션ID를 pending에서 우선 사용, (3) `logToFile``[projectName]` 접두사, (4) `UserResponse``project_name` 추가
- **주의**: response 데이터 자체에 project_name 필수. auto_resolve로 pending 삭제 시 우회됨
### [2026-03-10] file_permission — write 도구 3-button 미주입
- **증상**: `replace_file_content` 등 파일 수정 시 AG에선 3개 버튼(Deny/Allow Once/Allow This Conversation) 표시, Discord에선 2개(승인/거부)만 표시
- **원인**: step_probe의 `file_permission` 도구 리스트에 read 도구만 포함 (`view_file`, `grep_search` 등). `replace_file_content`, `write_to_file`, `multi_replace_file_content` 누락
- **해결**: 세 write 도구를 file_permission 리스트에 추가 (2곳: offset/normal scan)
- **주의**: AG가 파일 접근 권한을 요청하는 모든 도구는 이 리스트에 포함되어야 함
### [2026-03-10] bestSession IDLE 고착 — RUNNING 세션 못 잡는 버그
- **증상**: Deriva AG에서 새 대화 시작 → bridge가 구 IDLE 세션만 추적, 새 RUNNING 세션 무시
- **원인**: `bestSession` 선택이 `lastModifiedTime`만 비교. 구 IDLE 세션의 modTime이 더 최신이면 새 RUNNING 세션보다 우선 선택됨
- **해결**: 2단계 비교 — (1) RUNNING 세션이 IDLE보다 항상 우선, (2) 동일 상태 내에서 `lastModifiedTime` 최신 순
- **주의**: Reload Window로도 해결되지만 근본적으로는 RUNNING 우선 로직이 필요. `[SESSION-FILTER]` 진단 로그도 추가됨
### [2026-03-10] Bot IDLE 채널 자동 생성 — 불필요한 Discord 채널 증식
- **증상**: 봇 시작 시 IDLE 프로젝트까지 포함하여 모든 등록된 프로젝트의 채널을 자동 생성
- **원인**: `pending_approval_scanner`가 매 사이클마다 `conv_to_project` 전체를 순회하며 채널 생성
- **해결**: 자동 채널 생성 루프 제거. 채널은 실제 신호(snapshot/pending) 도착 시 `_get_channel()`로 on-demand 생성
- **주의**: `_get_channel()`은 snapshot scanner와 approval sender에서 이미 호출되므로 별도 사전 등록 불필요
### [2026-03-10] Reload Window 후 세션 stale — GetAllCascadeTrajectories 미갱신
- **증상**: Reload Window 후 현재 대화의 세션이 `GetAllCascadeTrajectories`에 IDLE/구 stepCount로 고정. 새 메시지를 보내도 RUNNING으로 변경되지 않음
- **원인**: Reload Window 시 Extension은 리셋되지만 LS 프로세스는 유지됨. LS 내부 trajectory tracker가 Reload 이전 세션 상태를 캐시하고 갱신하지 않음
- **해결**: AG 완전 종료 → 재실행 (Full restart). Reload Window로는 해결 불가
- **주의**: Extension 코드 변경 후 배포 시 Reload Window 대신 Full restart 권장. 이건 AG LS 내부 동작이라 사용자 측에서 수정 불가
### [2026-03-10] start_bot.bat — Windows Store Python 스텁 우선 실행
- **증상**: `start_bot.bat` 실행 시 `'...' is not recognized` 에러 후 `Python`만 출력되고 즉시 종료
- **원인**: `where python`이 Windows Store의 Python 스텁(AppAlias)을 먼저 찾음. 이 스텁은 실제 Python이 아니라 Store 페이지로 리다이렉트하는 더미
- **해결**: conda 경로(`C:\ProgramData\miniforge3\envs\gravity_control\python.exe`)를 `where python`보다 먼저 확인하도록 순서 변경
- **주의**: Windows 10/11에서 App Aliases의 `python.exe`가 PATH에 기본 포함됨. 항상 구체적 경로 우선 확인 필요
### [2026-03-10] VSIX 빌드 — SDK JS 파일 미포함 (require 실패)
- **증상**: Extension 활성화 후 `SDK not initialized`, `gravityBridge.connect` 클릭 시 에러. `extension.log`에 SDK init 성공 로그 없음
- **원인**: `src/sdk/index.js`는 순수 JavaScript 파일. TypeScript 컴파일러(`tsc`)는 `.ts`만 변환하고 **`.js` 파일을 `out/`에 복사하지 않음**. `require('./sdk/index')``out/sdk/index.js`를 찾지 못해 SDK 로드 실패
- **해결**: `package.json``compile` 스크립트에 `tsc``node -e "..."` 복사 단계 추가 (`src/sdk/``out/sdk/`)
- **주의**: VSIX 패키징은 `.vscodeignore``!out/**` 규칙으로 `out/sdk/`를 포함함. **문제는 빌드 단계에서 복사 누락**이므로 `npm run compile``out/sdk/` 존재 여부 반드시 확인
### [2026-03-10] SDK _findLSProcess — 대소문자 구분 workspace hint 매칭 실패
- **증상**: variet-agent AG에서 활성 대화 진행 중인데 Discord에 신호 미도달. extension.log에 `[SESSION-FILTER] NO session matched! total=11`
- **원인**: SDK `_findLSProcess()`가 workspace hint(`desktop_variet_agent`, 소문자)를 LS 프로세스 command line의 `Desktop_variet_agent`(대문자 D)과 `String.includes()`(대소문자 구분)로 비교 → 매치 실패 → 첫 번째 LS(gravity_control)로 fallback → variet-agent 세션 없음. 각 AG 창은 **별도의 LS 프로세스**를 가지며(workspace_id로 구분), SDK가 잘못된 LS에 연결하면 해당 창의 세션을 볼 수 없음
- **해결**: `extension.ts``fixLSConnection()` 함수 추가. SDK init 후 PowerShell로 모든 LS 프로세스를 조회, `--workspace_id`를 **대소문자 무시 비교**하여 올바른 LS 발견 → `sdk.ls.setConnection(port, csrfToken)`으로 재연결
- **주의**: 각 AG 창마다 별도 LS 프로세스 존재 확인됨 (workspace_id로 구분). SDK `_getWorkspaceHint()``.toLowerCase()` 적용하지만 검색 대상(LS command line)은 원본 대소문자를 유지하여 불일치 발생. 이 fix는 모든 multi-window AG 환경에서 필수
### [2026-03-11] config.py BRAIN_PATH — `.env` 빈 문자열 → CWD 해석 버그
- **증상**: 봇이 Extension의 snapshot/pending을 전혀 읽지 못함. 로그에 `Brain path: .`, `Bridge protocol initialized: bridge` (상대경로)
- **원인**: `.env``BRAIN_PATH=` (빈 값)이 있으면 `os.getenv("BRAIN_PATH", default)`가 빈 문자열 `""`를 반환 (default 미사용). `Path("")``Path(".")` → CWD로 해석. 봇의 bridge 디렉토리가 `CWD/bridge/`가 되어 Extension의 `~/.gemini/antigravity/bridge/`**다른 경로**
- **해결**: `os.getenv("BRAIN_PATH") or default` 패턴으로 빈 문자열도 처리
- **주의**: `os.getenv(key, default)`는 key가 존재하면 (빈 값이라도) default를 사용하지 않음. 환경변수의 빈 값을 fallback 처리하려면 반드시 `or` 사용
### [2026-03-11] Extension DEDUP MERGE — 크로스 프로젝트 pending 오염
- **증상**: `#ag-lifetimepd` 채널에 variet_agent의 `write_to_file` 승인 요청이 표시됨
- **원인**: `writePendingApproval()`의 DEDUP 로직이 `project_name`을 체크하지 않음. LifetimePD DOM observer가 "Deny" pending 생성 → 7초 후 variet_agent step_probe가 **같은 pending에 MERGE** → command가 덮어씌워짐. pending의 `project_name: lifetimepd`는 유지되어 잘못된 채널로 라우팅
- **해결**: 3곳 dedup 조건에 `existing.project_name === projectName` 가드 추가: (1) MERGE, (2) step_index 중복 스킵, (3) file_permission 중복 필터
- **주의**: 모든 Extension 인스턴스가 **동일한 `bridge/pending/` 디렉토리**를 공유하므로, pending 파일 간 상호작용 시 반드시 `project_name` 일치 여부 확인 필수
### [2026-03-11] Collector 동기 HTTP — aiohttp 전환
- **증상**: Collector가 Gateway에 동기 urllib 요청 시 이벤트 루프 전체 블로킹, 3초 폴링이 10초+로 늘어남
- **원인**: `RemoteTransport._request()``urllib.request.urlopen()` 사용 (blocking I/O)
- **해결**: `aiohttp.ClientSession` 기반 비동기 전환 + 연결 모니터링 + 재시도 큐 (100건)
- **주의**: `import aiohttp`는 lazy (`_get_session()` 내부). 로컬 conda 환경에 `aiohttp>=3.9.0` 설치 필수
### [2026-03-11] Extension fs.watch — Collector response 파일 감지 누락
- **증상**: Discord에서 거부 → Collector가 `bridge/response/` 파일 정상 생성 → Extension `processResponseFile` 미호출 (`[RESPONSE]` 로그 0건)
- **원인**: `setupResponseWatcher()``event === 'rename'`만 필터링. 파일 생성 방식에 따라 `change` 이벤트만 발생할 수 있음. Windows `fs.watch`는 빠른 write+delete 시 이벤트 누락 알려짐
- **해결**: **미해결**`event` 필터 제거 또는 polling 전환 필요. 사이드이펙트 검증 필요하여 보류
- **주의**: 이 문제로 인해 **Discord에서의 모든 거부/정지 명령이 Extension에 전달되지 않음**
### [2026-03-11] rejectAgentStep — AG 미등록 VS Code 커맨드 ### [2026-03-11] rejectAgentStep — AG 미등록 VS Code 커맨드
- **증상**: `/stop` 및 거부 시 `antigravity.agent.rejectAgentStep``command not found` - **증상**: `/stop` 및 거부 시 `antigravity.agent.rejectAgentStep``command not found`
- **원인**: AG IDE가 이 커맨드를 런타임에 등록하지 않음 - **원인**: AG IDE가 이 커맨드를 런타임에 등록하지 않음
- **해결**: **미해결** — AG가 실제 등록하는 커맨드 목록 조사 후 올바른 커맨드로 교체 필요 - **해결**: **미해결** — AG가 실제 등록하는 커맨드 목록 조사 후 올바른 커맨드로 교체 필요
- **주의**: `[2026-03-09] VS Code Accept Commands` 이슈와 같은 근본 원인 (AG 커맨드 미등록) - **주의**: AG 런타임 커맨드 미등록 문제의 근본 원인 (archive 참조: `[2026-03-09] VS Code Accept`)
### [2026-03-12] RemoteTransport 429 무한 루프 — Extension 크래시 + AG 먹통
- **증상**: Collector→Gateway HTTP 요청 시 `429 Rate limited` 로그가 초당 수십 건 무한 반복. Extension 꺼지고 AG 재시작 시 화면 먹통
- **원인**: 3가지 복합: (1) `RemoteTransport._arequest()`가 429 수신 시 백오프 없이 즉시 리턴 → 3초 후 다시 전체 재시도, (2) `_poll_responses_loop()`가 모든 forwarded pending에 개별 HTTP 요청 → pending 쌓이면 1초에 10개 초과, (3) Gateway rate limit이 10 req/1초로 너무 공격적
- **해결**: (1) `bridge.py` — 지수 백오프 추가 (1s→2s→4s…60s) + `Retry-After` 헤더 지원 + `is_rate_limited` 프로퍼티, (2) `gateway.py` — rate limit 10→30으로 완화 + `Retry-After` 헤더 응답, (3) `collector.py` — 모든 루프에서 `is_rate_limited` 체크 + response 폴링에 0.2초 인터-리퀘스트 딜레이
- **주의**: AG 먹통은 봇 자체가 유발한 문제. Extension이나 AG 내부를 건드린 것이 아님. 봇을 끄고 AG를 재시작하면 정상 복구 가능
### [2026-03-12] workbench.html 0-byte 파괴 — AG 새 창 먹통
- **증상**: AG 새 창 열면 화면 먹통 (빈 화면). 봇을 꺼도 복구 안 됨
- **원인**: 멀티 윈도우 환경(gravity_control + variet_agent + edf)에서 3개 Extension 인스턴스가 동시에 `workbench.html`을 읽고/패치/쓰기. 한 인스턴스가 `writeFileSync` 중에 다른 인스턴스가 `readFileSync` → 빈 문자열 반환 → 파이프라인 처리 후 0 bytes로 덮어쓰기
- **해결**: (1) pre-patch backup (.orig 파일) 생성, (2) 파일별 구조 검증 (requiredMarker), (3) 손상/잘못된 타입 감지 시 .orig에서 자동 복원
- **주의**: **AG 풀 재시작 필수**. 멀티 윈도우 환경에서 HTML 패치 race condition은 근본적으로 파일 잠금 없이는 완전 해결 불가 — 안전 가드로 피해 최소화
### [2026-03-12] workbench.html 크로스 복원 — CSS 미로딩으로 레이아웃 깨짐
- **증상**: AG 재시작 후 아이콘/요소는 보이지만 전부 왼쪽으로 쏠려서 정렬 안 됨. 레이아웃 완전 깨짐
- **원인**: `workbench.html``workbench-jetski-agent.html`에서 복원할 때 JS만 교체 (`jetskiAgent.js``workbench.js`)하고 **CSS 참조를 교체하지 않음**. 두 파일은 완전히 다른 CSS를 사용:
- `workbench.html``workbench.desktop.main.css` (VS Code 기본 레이아웃)
- `workbench-jetski-agent.html``tw-base.tailwind.css` + `jetskiMain.tailwind.css` (Jetski Agent 전용)
잘못된 CSS가 로드되면 JS는 정상 작동하나 레이아웃이 완전히 무너짐
- **해결**: (1) Extension에 파일별 `requiredMarker` 검증 추가 (workbench.html은 `workbench.desktop.main.css`, jetski는 `jetskiMain.tailwind.css` 필수), (2) 첫 패치 전 `.orig` 백업 자동 생성, (3) 손상 또는 잘못된 타입 감지 시 `.orig`에서 자동 복원. **두 HTML 파일은 절대 크로스 복원 불가**
- **주의**: `workbench.html``workbench-jetski-agent.html`**교환 불가능**. CSS 경로, JS 엔트리 포인트, CSP 세부 설정이 모두 다름. 수동 복원 시도 금지 — Extension의 자동 복원 로직에 의존할 것
### [2026-03-12] Collector 단일 프로젝트 폴링 — 멀티 프로젝트 command 전달 불가
- **증상**: Discord `ag-deriva` 채널에서 메시지 전송 → Deriva AG IDE에 전달되지 않음. Gateway에 command 정상 저장됨
- **원인**: `collector.py` `_poll_commands_loop()``self.project_name` (= `.env``PROJECT_NAME`, 기본 `gravity_control`)으로만 `GET /api/commands/{project}` 폴링. Gateway는 프로젝트별로 command를 저장(`_commands["deriva"]`)하지만 Collector가 `"gravity_control"`만 요청 → 다른 프로젝트 명령이 30분 TTL 후 만료
- **해결**: `_discover_local_projects()``bridge/register/*.json`에서 로컬 프로젝트 목록을 자동 발견, 모든 프로젝트에 대해 폴링. Extension은 L131에서 `project_name` 필터링이 있어 자기 프로젝트만 소비
- **주의**: 멀티 PC 환경에서 `/api/commands/all` 엔드포인트는 크로스 PC 명령 오염을 유발하므로 사용 금지. 각 Collector가 자기 PC의 `register/` 기반으로 프로젝트를 발견하는 것이 올바른 설계
### [2026-03-12] RemoteTransport backing off 무한 반복 — IDLE에서 더 심함
- **증상**: AG 미사용(IDLE) 시 `backing off 1s` 경고가 ~4초마다 영구 반복. 사용 중보다 IDLE 시 더 자주 발생
- **원인**: 3가지 구조적 결함의 복합:
1. **백오프 즉시 리셋**: `_reset_backoff()`가 성공 1회에 `_backoff_seconds=0` → 7개 루프가 같은 transport 공유 → 첫 성공에 리셋 → 지수 백오프가 영원히 1s에서 멈춤
2. **IDLE 시 불필요한 요청**: 6개 프로젝트 command 폴링이 3초마다 빈 응답 반복
3. **asyncio burst**: 7개 루프가 같은 `asyncio.sleep(3)` → 같은 tick에 동시 깨어남 → 순간 burst로 Gateway 1초 윈도우(30 req) 초과
- **해결**: (1) `_on_request_success()` — 연속 5회 성공 후에만 백오프 절반 감소, (2) `_poll_commands_loop` adaptive 간격 (빈 응답 시 3s→10s→30s→60s), (3) Gateway 윈도우 1s/30→10s/100, (4) 루프 stagger (0~3.5s 오프셋)
- **주의**: `_reset_backoff()` [즉시 리셋] 패턴은 **다중 소비자가 같은 transport를 공유하는 환경에서 절대 사용 금지**. 단일 성공이 전체 백오프를 무효화함
### [2026-03-15] DEDUP step_index 크로스 세션 충돌 — 승인 신호 누락
- **증상**: variet_agent에서 WAITING step 감지 → pending 미생성 → Discord 승인 요청 미전달 → 10분+ 대기
- **원인**: `writePendingApproval()`의 DEDUP 로직이 `step_index`로 중복 검사 시 `conversation_id`를 비교하지 않음. 세션 A(step=28)와 세션 B(step=28)가 동일시되어 DEDUP skip. 각 세션의 step_index는 0부터 시작하므로 크로스 세션 충돌 빈번
- **해결**: DEDUP 조건에 `existing.conversation_id === data.conversation_id` 가드 추가
- **주의**: `project_name` 가드만으로는 불충분 — 같은 Extension 인스턴스가 여러 세션을 볼 수 있음. 반드시 `conversation_id`까지 비교 필요
### [2026-03-15] fs.watch silent fail — Discord→Extension 명령 전달 불가
- **증상**: `!auto`, `!stop`, 텍스트 릴레이 등 Discord→Extension 방향 명령이 전부 작동 안 함. Extension log에 `[AUTO]` 로그 0건
- **원인**: `watchCommandsDir()``fs.watch`가 Windows에서 silent fail. watcher 세팅은 되지만 이벤트가 실제로 fire 안 됨. 실측 테스트에서 command 파일 드롭 후 2초 대기 → 미소비 확인
- **해결**: `fs.watch` 유지 + 3초 `setInterval` 폴링 fallback 추가. `processAllCommands()` 함수로 공통화
- **주의**: `fs.watch`는 Windows에서 구조적으로 불안정 — 이 프로젝트의 response watcher (known-issue [2026-03-11])에서도 동일 문제. **새 watcher 추가 시 반드시 polling fallback 병행**
### [2026-03-15] projectName=default 승인 오발 — workspace 없는 AG 창
- **증상**: workspace 없는 AG 창(Empty Window)이 step_probe로 다른 프로젝트의 WAITING step 감지 → `project_name: "default"` pending 생성 → `#ag-default` 채널로 전달 → 유저 미확인
- **원인**: `detectProjectName()`이 workspace 없으면 `"default"` 반환. step_probe는 LS의 `GetAllCascadeTrajectories`**모든** 세션을 볼 수 있으므로, 다른 workspace 세션의 WAITING을 감지하여 잘못된 project_name으로 pending 생성
- **해결**: step_probe 2곳(normal + offset)에서 `projectName === 'default'`이면 pending 생성/auto-approve 억제. 로그만 남김
- **주의**: `#ag-default` 채널이 생성되면 유저가 인지하지 못하므로 치명적. Empty Window에서는 bridge 기능을 최소화해야 함
### [2026-03-15] Discord Gateway MESSAGE_CREATE 중복 — embed 이중 전송
- **증상**: 텍스트 메시지, `!auto` 등 Discord 명령 시 동일 embed가 2개 전송
- **원인**: Discord Gateway가 WebSocket 불안정 시 `MESSAGE_CREATE` 이벤트를 중복 전달 (known discord.py issue). 봇 프로세스 1개, 코드상 `on_message` 1회 실행 로직이지만 이벤트 자체가 2번 도착
- **해결**: `on_message``_processed_message_ids: set[int]` (bounded 200개) 중복 방지 추가
- **주의**: Gateway reconnection, RESUME 실패 시 발생 빈도 증가. message ID 기반 dedup이 가장 확실한 방어
### [2026-03-15] HTML 패치 멀티 인스턴스 race condition — 화면 파괴
- **증상**: Extension 패치 후 AG 재시작 시 전체 화면 날아감 (빈 화면/깨진 레이아웃)
- **원인**: 2+ Extension 인스턴스가 `setupApprovalObserver()`에서 동시에 같은 `workbench.html`/`workbench-jetski-agent.html``readFileSync`/`writeFileSync` → 0-byte 파일 또는 부분 데이터 → 영구 손상
- **해결**: `.patch-lock` 파일 기반 cross-instance lock 추가 (30초 stale 판정). Lock 취득 실패 시 패치 skip
- **주의**: Lock은 "방지"에 해당. 기존 `.orig` 백업은 "복구"에 해당. 둘 다 유지해야 함. Lock 파일 경로 = `scriptDir/.patch-lock`
### [2026-03-15] 로컬 승인 ↔ Discord 승인 교차 race condition
- **증상**: AG에서 직접 Run 클릭 후 Discord 승인 요청이 "완료됨" 표시 안 됨. Discord에서도 뒤늦게 클릭 시 이미 완료된 step에 RPC 실행 → 에러 스팸
- **원인 1**: auto_resolve가 pending 상태만 변경하고 Discord에 알림 없음 → `writeChatSnapshot()` 추가
- **원인 2**: `processResponseFile()`이 pending의 `auto_resolved`/`expired` 상태를 체크하지 않음 → 상태 확인 후 skip 로직 추가
- **원인 3**: Bot의 auto_resolved 스캐너가 `discord_message_id`에만 의존 — Extension은 이 값을 모름 → `_approval_messages` dict (rid→msg_id) 추가, fallback 조회
- **주의**: `processResponseFile` L2534의 `lastPendingStepIndex = -1` 리셋이 Discord 승인 경로에서 auto_resolve 중복 진입을 방지하는 핵심 gate. 이 줄을 삭제하면 중복 알림 발생
### [2026-03-15] Extension 버전 미배포 — source ≠ deployed
- **증상**: 소스(v0.3.10)에 수정한 코드가 실제 동작하지 않음. 로그에서 수정 전 동작 확인됨
- **원인**: Extension 빌드/배포 누락. `~/.antigravity/extensions/`에 구 버전(v0.3.8) 남아있음
- **해결**: VSIX 빌드 → 설치 → 구 버전 디렉토리 삭제 → AG 전체 재시작 (Reload Window 불충분)
- **주의**: Extension 코드 수정 후 **반드시** `npm run compile && npx vsce package` → 배포까지 확인. AG는 전체 File→Exit 후 재시작 필요
### [2026-03-15] 크로스 프로젝트 DEDUP MERGE — Deriva→gravity_control 오염
- **증상**: Deriva의 step_probe 데이터(step_index, command)가 gravity_control의 DOM observer pending에 MERGE됨. Discord에 Deriva 명령이 gravity_control 채널에 표시
- **원인**: `writePendingApproval()` DEDUP MERGE 조건에 `project_name` 가드 없음 — `source === 'dom_observer' && status === 'pending'`만 검사하므로 타 프로젝트 pending에도 MERGE
- **해결**: MERGE 조건에 `existing.project_name === projectName` 추가 (v0.3.10)
- **주의**: `bridge/pending/` 디렉토리는 모든 Extension 인스턴스가 공유. 파일 읽기/쓰기 시 반드시 `project_name` 기반 필터링 필수
### [2026-03-15] Double-Fire Auto-Approve — AI 세션 중단
- **증상**: auto-approve ON 시 AI 세션이 간헐적으로 중단/멈춤
- **원인**: step_probe가 WAITING 감지 시 `autoApproveEnabled`면 직접 `tryApprovalStrategies()` 호출(경로A). 동시에 `writePendingApproval()` → Bot auto_approve_scanner → response 파일 → `processResponseFile()``tryApprovalStrategies()` 호출(경로B). 같은 step에 대해 2번 RPC 호출 → 충돌
- **해결**: Extension auto-approve 경로 A 제거. Bot만 auto-approve 담당 (v0.3.11). Extension은 항상 `writePendingApproval()` 경로 사용
- **주의**: 향후 Extension에서 직접 approve 로직을 추가할 때는 Bot auto-approve와의 경합을 반드시 고려. 단일 경로 원칙 유지
### [2026-03-15] DOM Observer "Deny" False Positive — Auto-approve 세션 크래시
- **증상**: auto-approve ON 시 Discord에 "Deny" command가 자동 승인됨 → AI 세션 반복 크래시
- **원인**: AG file_permission UI에 [Allow Once] [Allow This Conversation] [Deny] 3개 버튼 표시 → DOM observer가 "Deny" 텍스트를 독립 pending으로 생성 (`FALSE_POSITIVE_RE`에 "Deny" 미포함). 이 pending에는 `step_type`이 없어 default 분기 `runCommand: { confirm: true }` RPC 전송 → 실제 대기 중인 `file_permission`과 타입 불일치 → 세션 크래시
- **해결**: (1) `FALSE_POSITIVE_RE``Deny|Allow Once|Allow This Conversation|Dismiss|Decline` 추가, (2) bot.py auto-approve에 reject-word command 차단 가드, (3) smart button_index 선택 (방어)
- **주의**: `FALSE_POSITIVE_RE`는 렌더러 인라인 스크립트 안에 있으므로 **VSIX 빌드 → AG 풀 재시작** 필요. 새 UI 버튼 패턴 추가 시 반드시 이 필터 점검. **수정 시 해당 파일만 보지 말고 전체 데이터 플로우(producer→consumer→side effects) 분석 필수 (AGENT.md 규칙 #10)**
### [2026-03-15] PATS 배열 Deny 트리거 — 근본 수정
- **증상**: DOM Observer가 "Deny"를 주 트리거로 사용하여 command="Deny" pending 생성. step_probe MERGE와 결합하여 디스코드에 Deny 더미 전달
- **원인**: `PATS` 배열에 `{re:/^Deny$/i, type:'permission'}`이 포함되어 있어 DOM 순서상 Deny가 먼저 스캔됨. `FALSE_POSITIVE_RE`가 HTTP POST 경로에서는 차단하지만 `writePendingApproval` 직접 파일 작성 경로를 우회
- **해결**: PATS에서 거절/보조 버튼(Deny, Reject all, Dismiss) 제거. 긍정 버튼만 그룹 트리거 → 보조 버튼은 `ALL_ACTION_RE` + `collectSiblingButtons`로 형제 수집
- **주의**: PATS = "그룹 생성 트리거", ALL_ACTION_RE = "형제 수집 패턴". 새 버튼 추가 시 이 2단계 구조를 반드시 이해하고 추가
### [2026-03-15] Auto-Resolved 채팅 폭주 — 루프 내 writeChatSnapshot
- **증상**: "✅ AG에서 직접 승인됨" 메시지가 pending 파일 개수(4~5개)만큼 Discord에 반복 전송
- **원인**: auto_resolved 루프 내부에서 매 파일마다 `writeChatSnapshot()` 호출. 또한 `conversation_id` 미검증으로 타 세션 pending도 오염
- **해결**: (1) writeChatSnapshot을 루프 바깥으로 이동(resolvedCount > 0일 때 1회), (2) `pd.conversation_id === activeSessionId` 조건 추가, (3) primaryCommand에서 'Deny'/'Allow' 텍스트 제외
- **주의**: Bridge 파일 루프에서 외부 시스템(Discord)에 메시지를 보낼 때는 반드시 루프 바깥에서 집계 후 1회 발송
### [2026-03-16] 멀티 프로젝트 동시 신호 정지 — Scanner O(N) Discord API + fetch_channels 병목
- **증상**: 여러 프로젝트(3+)가 동시에 pending을 생성하면 모든 프로젝트의 신호 전달이 정지, AI 멈춤
- **원인**: 2가지 복합: (1) `pending_approval_scanner`가 1 tick에 모든 pending(15건+)을 순차 처리 → 건당 `_get_channel()` + `channel.send/edit/fetch_message` Discord API 호출 → 20~40 API 호출이 Discord 429 rate limit 유발 → discord.py 내부 대기 → scanner tick 수십 초 블로킹 → 모든 프로젝트 신호 지연. (2) `_get_channel()`이 캐시 미스 시 `guild.fetch_channels()` (Discord API)를 asyncio Lock 내에서 호출 → Lock 대기 + API 호출 순차 발생
- **해결**: (1) `_get_channel()``discord.utils.get(guild.channels)` 캐시 기반으로 변경 — API 호출 제거, (2) scanner에 per-tick cap 추가 (Phase 1: 5건, Phase 2: 5건) — 나머지는 다음 tick으로 이월
- **주의**: `guild.channels`는 discord.py 내부 캐시(Gateway 이벤트로 자동 갱신). 채널 삭제/생성은 캐시에 즉시 반영됨. per-tick cap은 최대 3초 지연을 유발하지만 전체 정지보다 훨씬 나음
### [2026-03-15] 이전 분석 오판(False Positive) — 교훈
- **증상**: 시스템 감사 시 P0/P1으로 보고한 문제들이 실제로는 코드 방어 로직(멱등성, try-catch, 의도된 exact-match)으로 이미 방어되고 있었음
- **원인**: 로컬 코드 스니펫만 보고 판단. 전체 데이터 생명주기를 끝까지 추적하지 않아 방어 로직을 놓침
- **해결**: 나노단위 전체 Flow 추적으로 교차 검증 후 진짜 결함만 추림 (P2 3건, P3 2건)
- **주의**: **코드 감사 시 반드시 producer→transport→consumer→side effects 전체 경로를 추적. 단편적 로컬 분석으로 위험도를 과장하지 말 것**
### [2026-03-16] processResponseFile 상태 리셋 — 무한 루프 vs auto_resolve 회귀
- **증상**: (v0.3.11) Discord 승인 후 같은 step에 대해 pending이 반복 생성 → 무한 auto-approve 루프
- **원인**: processResponseFile이 `lastPendingStepIndex = -1` + `stallProbed = false`로 무조건 리셋 → step_probe가 같은 WAITING step을 새 step으로 착각 → pending 재생성 → 루프
- **1차 시도 실패**: 리셋 2줄을 완전 제거 → 무한 루프 해소, BUT **L479 회귀** (sawRunningAfterPending이 false 유지 → Discord 승인 후 AG 진행 시 auto_resolve 중복 알림 발생)
- **올바른 해결 (v0.3.12)**: `sawRunningAfterPending = true`만 설정. lastPendingStepIndex와 stallProbed는 유지(dedup 보호), sawRunningAfterPending=true로 auto_resolve gate 닫기. 3개 변수 모두 delta>0에서 자연 리셋
- **주의**: processResponseFile의 상태 리셋은 **sawRunningAfterPending = true만 설정**. lastPendingStepIndex와 stallProbed를 건드리려면 반드시 `docs/approval-flow.md`의 상태 전이 다이어그램을 확인하고, known-issues L479 회귀 및 무한 루프 시나리오를 검증할 것. 자세한 Flow는 `docs/approval-flow.md` 참조
### [2026-03-16] recentPendingSteps 메모리 dedup — pending 파일 삭제 후 재생성 방지
- **증상**: Bot/Collector가 pending 파일을 삭제 → 파일 기반 dedup 통과 → 같은 step_index로 새 pending 생성
- **원인**: writePendingApproval()의 dedup이 파일 존재 여부에만 의존. write_response()가 pending 삭제 → dedup 무효화
- **해결**: `recentPendingSteps` Map (TTL 60초) 추가. `${conversationId}:${stepIndex}`를 키로 사용. 파일 삭제 후에도 메모리에서 차단. delta>0에서 해당 세션 항목 클리어
- **주의**: DOM observer HTTP `/pending` 경로(L738-812)는 `writePendingApproval()`을 우회하므로 이 메모리 dedup 미적용. "Run" 필터(L757)와 file_permission dedup(L786-800)이 대신 방어
### [2026-03-16] pending 파일 무한 누적 — Collector/Bot이 로컬 파일 삭제 안 함 ### [2026-03-16] pending 파일 무한 누적 — Collector/Bot이 로컬 파일 삭제 안 함
- **증상**: `bridge/pending/` 디렉토리에 56개 파일 누적 (auto_resolved 36개 + pending 20개) - **증상**: `bridge/pending/` 디렉토리에 56개+ 파일 누적 (auto_resolved + pending)
- **원인**: `remote` 모드에서 Bot은 Gateway 서버에서 동작하여 로컬 pending 파일 직접 삭제 불가. Collector는 pending을 Gateway로 전달하지만 auto_resolved/expired 상태 파일을 로컬에서 삭제하는 로직 없음 - **원인**: `remote` 모드에서 Bot은 서버에서 동작하여 로컬 pending 파일 직접 삭제 불가
- **해결**: (미완료) Collector에 로컬 pending cleanup 로직 추가 필요. 리팩토링 시 파일 기반 IPC 자체를 제거하면 근본 해결 - **해결**: **(미완료)** WS Hub 전환으로 파일 기반 IPC 자체가 줄어들면 자연 해소. Collector 정리 로직 일부 추가됨
- **주의**: pending 파일 누적은 Collector `_forward_pending_loop`의 매 사이클 읽기/해싱을 느리게 하여 새 pending 전달 지연 유발 - **주의**: WS 연결 상태에서는 pending 파일을 아예 생성하지 않으므로 해당 없음
### [2026-03-16] step_type 매핑 버그 — write_to_file이 file_permission으로 잘못 매핑 ---
- **증상**: Discord에서 코드 편집 승인 시 `filePermission` RPC 전송 → 파일 읽기용 interaction이 전송됨
- **원인**: L2060/L2121에서 `write_to_file`, `replace_file_content`, `multi_replace_file_content`가 읽기 도구와 함께 `file_permission`으로 매핑됨. `tryApprovalStrategies``AcknowledgeCascadeCodeEdit` 경로(L2907)는 `typeLower.includes('write_to_file')` 체크 → 실제 값이 `file_permission`이라 영영 도달 불가
- **해결**: 읽기 도구(`view_file`, `list_dir` 등)와 쓰기 도구(`write_to_file`, `replace_file_content`, `multi_replace_file_content`)를 분리. 쓰기 도구는 `code_edit` step_type 사용. `tryApprovalStrategies``code_edit` 분기 추가
- **주의**: AG는 대부분 파일 쓰기에 WAITING을 안 만듦 (한번 승인하면 이후 자동). 실제 WAITING은 새 대화 첫 파일 접근 시에만 발생
### [2026-03-16] diff_review isDirty 실패 — AG diff는 VS Code dirty 아님 ## 모니터링 중 이슈 (최근 수정, 재발 관찰 필요)
- **증상**: Discord diff_review Accept 클릭 → `agentAcceptAllInFile` 실행 → `isDirty` 문서 0개 → 대상 없이 실행 → 효과 없음
- **원인**: AG의 stacked code review는 VS Code의 `isDirty` 상태와 무관. AG 자체 diff 시스템으로 관리되며, 파일은 이미 디스크에 저장됨
- **해결**: (1차) `AcknowledgeCascadeCodeEdit` RPC로 직접 protocol 수락 시도 → (2차 fallback) `openReviewChanges` 패널 열기 + 수정 파일 focus + `agentAcceptAllInFile` 실행
- **주의**: diff_review pending에 `modified_files` (전체 경로)와 `edit_step_indices` (step 번호) 포함 필수. `agentAcceptAllInFile`은 diff 에디터가 포커스된 상태에서만 동작할 수 있음
### [2026-03-16] diff_review pending 순서 — AI 응답보다 먼저 Discord 도착 ### [2026-03-17] Hub pending_owners 생명주기 — WS 재연결 시 승인 응답 소실
- **증상**: Discord에 diff_review 승인 버튼이 먼저 표시되고, AI 응답 텍스트가 나중에 도착. 유저가 승인 클릭 후에야 마지막 대화 내용을 확인할 수 있음 - **증상**: Discord에서 승인 클릭해도 AG Extension에서 아무 동작 안함
- **원인**: RUNNING→IDLE 전환 시 AI 응답 snapshot과 diff_review pending이 같은 poll tick에 생성. `pending_approval_scanner`(3초)가 `chat_snapshot_scanner`보다 먼저 fire하여 버튼이 먼저 Discord에 전달됨 - **원인**: `_disconnect()`에서 Extension 연결 끊기면 `pending_owners[rid]` 삭제 → 재연결 후 owner 정보 소실
- **해결**: diff_review pending 생성을 `setTimeout(8000)`으로 지연. 변수는 closure로 캡처 (`capturedSessionId`, `capturedStepCount`, 파일 목록). tracking 배열은 즉시 리셋 - **해결**: (1) 삭제 대신 같은 project 다른 연결로 재할당, (2) `_register_connection`에서 orphaned pending 재할당, (3) 같은 project 활성 연결 fallback
- **주의**: 8초는 snapshot_scanner + Collector + Gateway + Bot 전체 경로의 전파 시간을 고려한 값. 너무 짧으면 여전히 버튼이 먼저 도착 - **주의**: Gateway 모드에서 file bridge fallback은 **완전히 무용** — Docker 볼륨에 파일 작성하지만 Extension은 로컬 bridge/ 감시
### [2026-03-16] diff_review AcknowledgeCascadeCodeEdit steps=[] — Collector pending 삭제 race ### [2026-03-17] diff_review Accept All WS 경로 regression (v0.4.5 fix)
- **증상**: Discord에서 Accept all 클릭`AcknowledgeCascadeCodeEdit(steps=[])` → RPC SUCCESS `{}` 반환 → AG에서 diff review 바가 사라지지 않음 (실제 no-op) - **증상**: Discord에서 Accept all 클릭해도 AG에서 반응 없음
- **원인**: Collector가 Gateway response를 받으면 로컬 pending 파일을 즉시 삭제 (`collector.py L259`). Extension `processResponseFile`이 pending 파일에서 `edit_step_indices`를 읽으려 할 때 파일 이미 없음 → `trackedSteps=[]` - **원인**: WS 전환 시 `onResponse` 핸들러에 `diff_review` step_type 분기 누락
- **해결**: `diffReviewMetadata` 인메모리 Map 추가 (extension.ts L57). `writePendingApproval`에서 diff_review pending 생성 시 `edit_step_indices` + `modified_files`를 메모리에 캐시. `processResponseFile`에서 메모리 먼저 조회, pending 파일은 fallback - **해결**: `handleDiffReviewResponse()` export + WS `onResponse`에서 호출
- **주의**: 인메모리 캐시는 Extension Reload 시 소실됨. 그러나 diff_review pending 자체가 RUNNING→IDLE 전환 시 새로 생성되므로, 리로드 후에도 새 diff_review는 정상 동작. `bridge.py write_response()` L461의 pending 삭제도 동일 문제를 유발하지만 remote 모드에서는 Collector 경로만 해당 - **주의**: **WS 경로 추가 시 file-bridge 경로의 모든 분기를 반드시 포팅할 것**
### [2026-03-16] AcknowledgeCascadeCodeEdit SUCCESS → diff review bar 미해제 — **잘못된 RPC 메서드명** ### [2026-03-17] _auto_approve_via_hub 이중 쓰기 (v0.4.5 fix)
- **증상**: `AcknowledgeCascadeCodeEdit(session=xxx, accept=true, steps=[40])``SUCCESS: {}` 반환 → AG diff review bar 여전히 표시됨 - **증상**: auto-approve 시 Extension에 응답이 2번 도착
- **원인**: **RPC 메서드명 자체가 틀렸음.** AG 내부 LS 메서드는 `AcknowledgeCascadeCodeEdit`가 아닌 **`acknowledgeCodeActionStep`**(proto ID 167). AG 소스 역분석으로 확인. 그러나 `acknowledgeCodeActionStep`도 ConnectRPC 404 반환 (LS의 `exa.language_server_pb.LanguageServerService`에 미등록). `submitCodeAcknowledgement` VS Code 커맨드도 런타임 미등록 - **원인**: Hub WS 전송 후 `return` 없이 file bridge에도 씀
- **해결**: ~~v0.3.14 3단계 RPC 전략~~ 모두 실패. **v0.3.15**: `agentAcceptAllInFile` / `agentRejectAllInFile` VS Code 커맨드 사용 (런타임에 등록 확인됨). `openReviewChanges` → 파일별 포커스 → 커맨드 실행 - **해결**: `if self.hub:` → WS 전송 + `else:` → file bridge. if/else 구조로 변경
- **주의**: AG의 RPC는 잘못된 메서드명도 에러 없이 `{}` 반환함 (proto unknown field). `AcknowledgeCascadeCodeEdit``{}` 반환 → `diffReviewDone=true` 설정 → 실제 동작하는 전략 차단이 핵심 버그였음. **RPC `{}`는 실패로 간주해야 함** - **주의**: Hub WS와 file bridge는 **항상 상호 배타적**이어야 함
### [2026-03-16] diff_review RPC 3개 전략 모두 dead-end — VS Code 커맨드만 유효
- **증상**: v0.3.14 E2E 테스트에서 3개 RPC 전략 모두 실패, diff review bar 해제 안 됨
- **원인**: (1) `submitCodeAcknowledgement`: AG 런타임 119개 명령에 미등록, (2) `acknowledgeCodeActionStep`: ConnectRPC 404 (LS 서비스에 미등록), (3) `AcknowledgeCascadeCodeEdit`: `{}` no-op 반환 후 `diffReviewDone=true` → Strategy 2 차단
- **해결**: v0.3.15에서 dead-end RPC 3개 제거. `agentAcceptAllInFile` / `agentRejectAllInFile` (런타임 등록 확인) + `openReviewChanges` + 파일별 포커스 방식으로 전환. Hunk 단위 fallback 추가 (`agentAcceptFocusedHunk`)
- **주의**: diff_review Accept/Reject를 RPC로 해결하려는 시도 **모두 실패 확정**. VS Code 커맨드 기반만 유효. 단, 이 커맨드도 diff editor 포커스 의존성 있을 수 있음 — 재시작 후 E2E 검증 필요
### [2026-03-16] AG 소스 역분석 — diff review 내부 동작 체인
- **증상**: Accept all / Reject all 버튼의 내부 동작을 Extension에서 프로그래밍 방식으로 재현해야 함
- **원인**: AG 공식 API/문서 없음. VS Code 커맨드 중 많은 것이 미등록 상태
- **해결**: AG 설치 경로의 JS 소스에서 직접 역분석. 핵심 발견:
- **LS 메서드**: `acknowledgeCodeActionStep` (proto ID 167, 메시지 타입 `vKa`/`QLc`) — 단, ConnectRPC 404
- **VS Code 커맨드**: `antigravity.prioritized.submitCodeAcknowledgement` — 미등록
- **실제 동작 커맨드**: `antigravity.prioritized.agentAcceptAllInFile` / `agentRejectAllInFile` (런타임 등록 확인)
- **Accept all 체인**: UI 클릭 → `fireEvent({type:"accept-all-in-file"})` → 내부 처리
- **파일 위치**: `%LOCALAPPDATA%\Programs\Antigravity\resources\app\out\jetskiAgent\main.js` (LS 메서드 정의), `vs\workbench\workbench.desktop.main.js` (UI 커맨드 + 핸들러)
- **주의**: Python `re.finditer`로 대용량 JS 검색 시 PowerShell `IndexOf`보다 안정적. minified JS에서 변수명(`vKa`, `QLc` 등)은 버전마다 변경됨
### [2026-03-16] diff_review 이중 승인 요청 — DOM observer가 Accept/Reject 버튼 캡처
- **증상**: Discord에 diff_review 승인 요청(Accept all/Reject all)과 별도로 "Accept" / "Reject" 단독 pending이 1건 더 도착
- **원인**: diff_review 처리 시 `openReviewChanges` 커맨드가 diff UI 패널을 열면 Accept/Reject 버튼이 DOM에 렌더링됨. DOM observer가 이 버튼을 감지하여 별도 pending 생성 (`cmd="Accept" btns=2 ctx="RejectShift+Alt+⌫"`)
- **해결**: `FALSE_POSITIVE_RE``Accept|Reject|Accept all|Reject all` 추가 (v0.3.16)
- **주의**: diff review bar 버튼은 전용 `diff_review` pending 시스템에서 처리하므로 DOM observer가 별도로 캡처할 필요 없음
### [2026-03-16] !auto 이중 메시지 — Extension echo + Bot embed
- **증상**: `!auto` 토글 시 Discord에 Auto 모드 변경 메시지가 2개 표시 (Bot embed + Extension echo)
- **원인**: Bot이 embed를 전송하고 + `!auto on/off` command를 Extension에 전달 → Extension이 `writeChatSnapshot()`으로 확인 메시지를 다시 Discord에 전송 → Bot의 `chat_snapshot_scanner`가 이것을 읽어 또 전송
- **해결**: Extension의 `!auto` command handler에서 `writeChatSnapshot()` echo 제거 (v0.3.16). Bot의 embed 1개만 표시
- **주의**: Extension 측 `autoApproveEnabled` 변수는 여전히 정상 토글됨 (로그에 기록). 단, Bot 재시작 시 `auto_approve_projects` set은 초기화되므로 Extension은 auto 상태여도 Bot이 auto-approve를 실행하지 않음 → 사실상 수동 모드로 복귀
### [2026-03-16] 병렬 WAITING step 누락 — step_probe break문
- **증상**: AG가 병렬 tool call(예: run_command 3개)를 동시 실행 시 Discord에 1개만 승인 요청 도착, 나머지는 AG UI에만 표시
- **원인**: `extension.ts` step_probe 루프(L2082-2134)에서 `break`문이 첫 번째 WAITING step 처리 후 루프 종료. 나머지 병렬 WAITING step은 pending 생성 안 됨. offset retry 루프(L2029-2071)에도 동일 `break` 존재
- **해결**: `break` 제거하여 모든 WAITING step에 pending 생성. `lastPendingStepIndex`는 가장 큰 index로만 갱신. 중복 방지는 `writePendingApproval``recentPendingSteps` Map이 처리
- **주의**: 병렬 pending이 동시에 생성되면 Bot이 여러 auto-approve를 거의 동시에 처리. Collector의 polling 주기(5초)와 Extension의 response watcher(3초) 사이 타이밍 이슈 가능
### [2026-03-16] Bot chat_snapshot 전송 성공/실패 로깅 부재
- **증상**: Discord에 chat snapshot이 전달됐는지 Bot 로그에서 확인 불가. 전송 성공 시 아무 로그 없음
- **원인**: `bot.py` `chat_snapshot_scanner`(L895-988)에서 `channel.send()` 성공 후 INFO 로그 없음. 실패 시 `discord.NotFound`만 catch하고 일반 Exception은 catch 안 함
- **해결**: 전송 성공 시 `[SNAPSHOT] Sent to #채널명 (inline/file, N chars)` INFO 로그 추가. `Exception` catch도 추가하여 `[SNAPSHOT] Discord send failed` ERROR 로그 출력
- **주의**: `_get_channel()` 실패 시 `[SNAPSHOT] No Discord channel` WARNING은 이전에도 있었으나, channel이 정상이면 아무 단서 없었음
### [2026-03-16] 크로스 프로젝트 이벤트 폭주 — Watcher/Collector 무필터
- **증상**: /start 실행 시 gravity_control 채널에 variet_agent, lifetimepd, deriva 등 타 프로젝트 알림 유입. 6개 프로젝트 42개 세션의 file_changed가 모두 전달됨
- **원인**: `watcher.py`가 brain/ 전체를 recursive 감시하면서 모든 세션의 .md 변경을 이벤트로 방출. `collector.py` `_forward_events_loop`도 프로젝트 필터 없이 모든 이벤트를 Gateway로 전달
- **해결**: (1) `watcher.py``_is_my_session()` 필터 추가 — register/ 파일 기반으로 MY 프로젝트 세션만 이벤트 방출. (2) `collector.py``_get_session_project()` + 이벤트 전달 필터 추가
- **주의**: 미등록 세션(새로 시작된 대화)은 allow-through 방식. register 파일은 60초 캐시로 I/O 절감
### [2026-03-16] pending 파일 139개 누적 — 정리 로직 부재
- **증상**: `bridge/pending/` 디렉토리에 auto_resolved 109개 + pending 30개 = 139개 파일 누적. 새 pending 전달 지연
- **원인**: Extension이 `auto_resolved`/`expired`로 상태 변경한 pending 파일을 아무도 삭제 안 함. Bot은 gateway 모드라 로컬 파일 접근 불가, Collector는 response가 온 pending만 삭제
- **해결**: `collector.py` `_forward_pending_loop`에서: (1) auto_resolved/expired 상태 → Gateway 전달 후 즉시 로컬 삭제, (2) 10분 이상된 forwarded pending 주기적 자동 삭제
- **주의**: startup_pending은 정리 대상에서 제외 (mtime 기반 변경 감지가 필요하므로)
### [2026-03-16] diff_review가 brain/ artifact에도 트리거 — task.md "코드 리뷰"
- **증상**: AI가 task.md만 수정한 경우에도 "코드 리뷰: task.md" pending이 생성되어 사용자 혼동
- **원인**: Extension의 diff_review 감지 로직이 write_to_file/replace_file_content로 수정된 **모든** 파일을 추적. brain/ 경로의 task.md, implementation_plan.md 등 AG 내부 artifact도 포함됨
- **해결**: `extension.ts` diff_review 감지 시 `.gemini/antigravity/brain/` 경로 파일을 필터링하여 제외. 코드 파일만 남으면 diff_review 생성, brain artifact만이면 skip
- **주의**: 코드 파일 + brain artifact가 혼합된 경우에는 코드 파일에 대해서만 diff_review 생성
### [2026-03-17] NPM WebSocket 프록시 — Upgrade 헤더 미전달
- **증상**: `wss://ag.variet.net/ws` 연결 시 HTTP 400 `No WebSocket UPGRADE hdr: None`
- **원인**: Nginx Proxy Manager(openresty) 프록시 호스트에 WebSocket Support 미활성화 → `Upgrade` 헤더가 백엔드(aiohttp)로 전달되지 않음
- **해결**: NPM 대시보드 → Proxy Hosts → `ag.variet.net` → Edit → **Websockets Support** 체크 → Save
- **주의**: NPM은 WebSocket 토글을 켜야 `proxy_set_header Upgrade $http_upgrade` + `proxy_set_header Connection $connection_upgrade`가 자동 추가됨. 새 프록시 호스트 생성 시 반드시 확인
### [2026-03-17] Extension ws 모듈 미번들 — WS 연결 실패 가능
- **증상**: Extension WS 연결 시도 시 `[WS] WebSocket module not available` → 파일 fallback만 동작
- **원인**: `ws` npm 패키지가 `.vscodeignore``node_modules/**`에 의해 VSIX에서 제외됨. AG Electron에 `ws` 미포함. `globalThis.WebSocket`은 Node.js 22+에서만 사용 가능
- **해결**: (1) `.vscodeignore``!node_modules/ws/**` 추가하여 VSIX에 ws 번들, (2) 설치 후 수동으로 `node_modules/ws/`를 설치 경로에 복사
- **주의**: `package.json``ws` dependency 추가 후 `npx vsce package` 시에도 `.vscodeignore``!node_modules/ws/**` 없으면 번들 안 됨. `--no-dependencies` 플래그와 무관
### [2026-03-17] WS Auth 실패 — 워크스페이스 settings 빈 값 override
- **증상**: Extension이 Hub에 연결 성공하지만 `Auth failed: Auth required` 반복. `registrationCode`가 항상 empty
- **원인**: `.vscode/settings.json``"gravityBridge.registrationCode": ""`(빈 문자열)이 설정되어, 유저 설정(`%APPDATA%/Antigravity/User/settings.json`)의 올바른 값을 워크스페이스 설정이 **덮어쓰기**. VS Code 설정 우선순위: workspace > user
- **해결**: `.vscode/settings.json``registrationCode`에 올바른 값 설정
- **주의**: VS Code `config.get()`은 워크스페이스에 빈 문자열이 있으면 유저 설정의 값을 무시함. 빈 값도 "설정됨"으로 취급. `hubUrl`은 워크스페이스에 정상 값이라 동작했지만 `registrationCode`만 빈 값이라 불일치 발생
### [2026-03-17] WS auth_fail 무한 재연결 — _cleanup() close 이벤트
- **증상**: `Auth failed` 후 "Don't reconnect" 주석에도 불구하고 60초마다 재연결 반복
- **원인**: `_cleanup()``ws.close()` → close 이벤트 → `_onDisconnect()``_scheduleReconnect()` 체인 트리거. `shouldReconnect`를 false로 설정하지 않아 재연결 차단 안 됨
- **해결**: `auth_fail` 핸들러에서 `this.shouldReconnect = false``_cleanup()` **이전에** 설정
- **주의**: `_cleanup()`은 WS를 닫으면서 이벤트 핸들러를 트리거하므로, 상태 변경은 반드시 `_cleanup()` 호출 전에 수행할 것
### [2026-03-17] initStepProbe workspaceUri 누락 — 세션 감지 완전 불능
- **증상**: POLL alive만 출력되고 SESSION-FILTER/SNAPSHOT 전혀 없음. Discord에 아무것도 도착 안 함
- **원인**: `initStepProbe()` 호출 시 `workspaceUri``diffReviewMetadata` 미전달. `as BridgeContext` 캐스트가 누락 필드를 무시. `ctx.workspaceUri.replace()`에서 매 5초 TypeError. 에러가 `console.log`로만 기록되어 extension.log에 안 보임
- **해결**: `extension.ts` L1131에 `workspaceUri`, `diffReviewMetadata: new Map()` 추가
- **주의**: TypeScript `as` 캐스트는 런타임 검증 없음. 필수 필드 누락도 컴파일 에러 없이 통과. 에러 핸들러가 `ctx.logToFile` 대신 `console.log` 사용하면 extension.log에 안 남음
### [2026-03-17] WS dual-write — 채팅/승인 이중 발송 ### [2026-03-17] WS dual-write — 채팅/승인 이중 발송
- **증상**: Discord 메시지가 2개씩 도착 (동일 내용) - **증상**: Discord 메시지가 2개씩 도착
- **원인**: `writeChatSnapshot`/`writePendingApproval`이 WS 전송 후 파일도 동시에 씀 (Phase 0 dual-write). Watcher가 파일도 읽어서 Discord로 보냄 → 같은 메시지 2번 전달 - **원인**: `writeChatSnapshot`/`writePendingApproval`이 WS 전송 후 파일도 동시에 씀
- **해결**: WS 연결 시 `return`으로 파일 쓰기 건너뛰기. 파일은 fallback 전용으로 변경 - **해결**: WS 연결 시 `return`으로 파일 쓰기 건너뛰기
- **주의**: `writePendingApproval` 수정 시 diff_review metadata 캐싱 + memory dedup 로직이 WS 경로에서도 실행되어야 함 - **주의**: `writePendingApproval` 수정 시 diff_review metadata 캐싱 + memory dedup 로직이 WS 경로에서도 실행되어야 함
### [2026-03-17] Hub WS auto-approve Discord 알림 누락
- **증상**: auto-approve 활성화 상태에서 승인 요청이 자동 처리되지만 Discord에 아무 알림 없음 (텍스트만 전달)
- **원인**: `_auto_approve_via_hub()` (WS 경로)에서 Discord embed 미전송. 파일 기반 auto-approve (L617)은 "🤖 자동 승인됨" embed 전송하지만 Hub WS 경로 누락
- **해결**: `_auto_approve_via_hub()`에 Discord embed 전송 추가 (파일 경로와 동일 포맷)
- **주의**: bot.py는 서버에서 실행됨. 로컬 수정 후 반드시 git push → 서버 pull + 재시작
### [2026-03-17] Hub WS ApprovalRequest 생성 누락 필드 — 모든 승인 실패
- **증상**: Hub WS로 전달된 모든 pending 승인 요청이 Discord에 표시되지 않음 (채팅은 정상)
- **원인**: `_hub_on_pending()`에서 `ApprovalRequest()` 생성 시 `conversation_id``timestamp` 필수 인자 누락 → TypeError. `try/except`에 잡혀 로그만 남고 무시
- **해결**: `data.get("conversation_id", "")`, `data.get("timestamp", time.time())` 추가
- **주의**: 서버 로그(`docker logs gravity-gateway`)에서만 에러 확인 가능. 로컬 extension.log에는 `[PENDING-WS] sent` 성공으로 보임. **서버 배포 후 반드시 서버 로그로 검증할 것**
### [2026-03-17] ApprovalView Hub WS 응답 미전송 — Discord 승인 클릭 무효
- **증상**: Discord에서 승인/거부 버튼을 클릭해도 AG에 전달되지 않음. AG가 계속 대기 상태
- **원인**: `ApprovalView` 버튼 콜백이 `bridge.write_response()`만 호출 → Docker 컨테이너 내부 파일시스템에만 기록. Hub WS로 연결된 Extension은 이 파일을 읽을 수 없음
- **해결**: `ApprovalView``hub` 파라미터 추가. 모든 버튼 콜백에서 `hub.send_response_to_pending_owner()` 호출하여 WS로 Extension에 직접 전달
- **주의**: ~~파일 기반 로컬 모드도 여전히 동작 (fallback). Hub가 None이면 파일만 사용. 양쪽 모두 호출하는 dual-write 방식~~**v0.4.4에서 수정**: Hub 연결 시 file bridge 스킵 (이전 dual-write가 이중 전달의 원인이었음)
### [2026-03-17] WS 응답 파일 경유 — 자동승인이 AG에 안 도착
- **증상**: Discord "🤖 자동 승인됨" 표시되지만 AG는 계속 대기. Hub WS 응답이 Extension에 도착해도 AG가 진행 안 함
- **원인**: Extension `onResponse`가 WS 응답을 `response/{rid}.json` 파일로 쓴 뒤 `processResponseFile`이 읽는 구조. WS pending 경로는 `pending/{rid}.json` 파일을 안 쓰므로 `processResponseFile``sessionId`/`stepIndex` 메타데이터를 못 찾아 `tryApprovalStrategies` 실패
- **해결**: `onResponse`에서 파일 경유 제거, `tryApprovalStrategies()` 직접 호출. `getApprovalContext()`/`resetPendingState()` export
- **주의**: WS 경로와 파일 경로의 pending/response 생명주기가 완전히 다름. WS pending은 파일 없음 → response 처리도 파일 없이 해야 함
### [2026-03-17] WS+File Dual-Write — 명령어/응답 이중 전달
- **증상**: Discord 메시지가 AG에 2번 전달, 승인 응답 처리 후 새 승인 요청이 도착하지 않음
- **원인**: `bot.py:_write_command()``ApprovalView` 콜백이 Hub WS **AND** file bridge 양쪽으로 동시 전송. Extension에서 WS callback + file watcher 양쪽으로 수신하여 `sendPromptToAgentPanel` 2회 실행. 응답도 `resetPendingState()``processResponseFile()`가 동시 실행되어 state 충돌
- **해결**: Hub 연결 시 `return`으로 file bridge 스킵 (명령어, 응답 모두). `else` 분기로 fallback 처리
- **주의**: **Hub WS 연결 시 file bridge는 완전히 비활성화**해야 함. "양쪽 모두 쓰기"는 이중 전달의 근본 원인
### [2026-03-17] WS 명령어 에코 릴레이 — Discord 메시지 2번 표시
- **증상**: Discord에서 메시지 입력 → 같은 메시지가 "👤 사용자 (AG 직접 입력)"으로 다시 Discord에 표시
- **원인**: `handleWSCommand`에서 AG에 텍스트 전달 시 `recentDiscordSentTexts`에 마킹하지 않음 → step-probe가 USER_INPUT step 감지 시 Discord 발신 메시지를 새 사용자 입력으로 오인하여 릴레이
- **해결**: `handleWSCommand``ctx.recentDiscordSentTexts.set(text.trim(), Date.now())` 추가
- **주의**: 파일 기반 `_processCommandFile`에는 이미 마킹 있었음 (L178). WS 경로 추가 시 동일 패턴 적용 필수
### [2026-03-17] writeRegistration 이중 쓰기 — WS 전송 후 파일도 작성
- **증상**: WS 연결 상태에서도 `bridge/register/` 디렉토리에 등록 파일이 계속 생성됨
- **원인**: `writeRegistration()` (step-probe.ts L162)이 WS 전송 후 `return` 없이 파일 쓰기도 실행. `writeChatSnapshot`/`writePendingApproval`은 WS→return 패턴인데 `writeRegistration`만 누락
- **해결**: WS 전송 후 `return` 추가하여 파일 쓰기 건너뛰기 (v0.4.5)
- **주의**: 새 WS 전송 함수 추가 시 반드시 file fallback과 상호 배타적 `return` 확인
### [2026-03-17] ApprovalView Hub 응답 실패 시 silent loss — fallback 없음 ### [2026-03-17] ApprovalView Hub 응답 실패 시 silent loss — fallback 없음
- **증상**: Extension이 pending 생성 후 WS 연결 끊김 → Discord에서 승인 클릭 → AG에 전달 안 됨 (무한 대기) - **증상**: Extension이 pending 생성 후 WS 연결 끊김 → Discord 승인 클릭 → AG에 전달 안 됨
- **원인**: `ApprovalView` approve/reject/choice 콜백이 `if self.hub:``send_response_to_pending_owner()` 실행. 반환값 미확인. Hub가 있으면 file bridge를 아예 건너뛰므로 Hub 전달 실패 시 응답 소실 - **원인**: `ApprovalView`가 Hub 전달 실패 시 file bridge를 건너뜀
- **해결**: `delivered = await hub.send_response_to_pending_owner()` 반환값 확인 → `False``bridge.write_response()` fallback (4곳 + `_auto_approve_via_hub` 1곳, 총 5곳) - **해결**: `send_response_to_pending_owner()` 반환값 확인 → `False`file bridge fallback (5곳)
- **주의**: `send_response_to_pending_owner``pending_owners`에 conn_id가 없으면 `False` 반환 (Extension 재연결/disconnect 시). Hub 존재 ≠ 전달 성공 - **주의**: `send_response_to_pending_owner``pending_owners`에 conn_id가 없으면 `False` 반환. Hub 존재 ≠ 전달 성공
---
## 핵심 작업 규칙 (과거 이슈에서 반복된 패턴)
> 아래는 과거 이슈에서 반복적으로 나타난 패턴을 규칙으로 정리한 것입니다.
| # | 규칙 | 관련 이슈 (archive 참조) |
|---|------|--------------------------|
| 1 | **Hub WS와 file bridge는 상호 배타적**`if hub: ws + return` / `else: file` | WS dual-write, _auto_approve 이중 쓰기 |
| 2 | **WS 경로 추가 시 file-bridge의 모든 분기를 포팅** | diff_review WS regression |
| 3 | **AG RPC `{}` 응답은 실패로 간주** — 메서드명 틀려도 에러 없이 `{}` 반환 | AcknowledgeCascadeCodeEdit |
| 4 | **ResolveOutstandingSteps는 CANCEL 동작** — 승인에 절대 사용 금지 | Step probe reject |
| 5 | **Extension 코드 수정 후 반드시 VSIX 빌드 + AG 풀 재시작** | Extension 버전 미배포 |
| 6 | **HTML 패치 변경 시 V8 CachedData 삭제 필수** | V8 CachedData, CSP |
| 7 | **`bridge/pending/` 조작 시 반드시 `project_name` + `conversation_id` 필터** | 크로스 프로젝트 DEDUP MERGE |
| 8 | **`processResponseFile` 상태 리셋은 `sawRunningAfterPending=true`만** | processResponseFile 무한 루프 |
| 9 | **fs.watch Windows 불안정 — 반드시 polling fallback 병행** | fs.watch silent fail |
| 10 | **diff_review는 VS Code 커맨드만 유효** — RPC 3개 전략 모두 실패 확정 | diff_review RPC dead-end |

View File

@@ -32,6 +32,7 @@
| @types/vscode | VS Code Extension API 타입 | | @types/vscode | VS Code Extension API 타입 |
| @types/node | Node.js 타입 | | @types/node | Node.js 타입 |
| typescript | 컴파일러 | | typescript | 컴파일러 |
| ws | WebSocket Hub 연결 (`.vscodeignore``!node_modules/ws/**` 필수) |
| antigravity-sdk | AG RPC 호출 (로컬 임베드 `sdk/`) | | antigravity-sdk | AG RPC 호출 (로컬 임베드 `sdk/`) |
## 패키지 관리 ## 패키지 관리
@@ -67,7 +68,10 @@
| 변수명 | 용도 | 기본값 | | 변수명 | 용도 | 기본값 |
|--------|------|--------| |--------|------|--------|
| BRAIN_PATH | AG 브레인 경로 | `~/.gemini/antigravity/brain` | | BRAIN_PATH | AG 브레인 경로 | `~/.gemini/antigravity/brain` |
| BOT_MODE | `local` / `remote` / `gateway` | `local` | | BOT_MODE | `local` / ~~`remote`~~ / `gateway` | `local` |
> [!WARNING]
> `BOT_MODE=remote` (Collector 모드)는 **deprecated**입니다. `gateway` 모드 + Extension WS를 사용하세요.
| DEBOUNCE_SECONDS | Watcher 디바운스 간격 | `5` | | DEBOUNCE_SECONDS | Watcher 디바운스 간격 | `5` |
| PROJECT_NAME | 프로젝트 이름 | `gravity_control` | | PROJECT_NAME | 프로젝트 이름 | `gravity_control` |
@@ -79,7 +83,7 @@
| GATEWAY_API_KEY | REST API 인증 키 | (미설정 시 인증 미사용) | | GATEWAY_API_KEY | REST API 인증 키 | (미설정 시 인증 미사용) |
| GRAVITY_HUB_SECRET | WS Hub JWT 서명 시크릿 (64char hex) | (미설정 시 인증 생략) | | GRAVITY_HUB_SECRET | WS Hub JWT 서명 시크릿 (64char hex) | (미설정 시 인증 생략) |
| GRAVITY_REGISTRATION_CODE | Extension 등록 코드 (32char hex) | (미설정 시 인증 생략) | | GRAVITY_REGISTRATION_CODE | Extension 등록 코드 (32char hex) | (미설정 시 인증 생략) |
| REMOTE_BRIDGE_URL | Collector 원격 URL | (remote 모드 전용) | | REMOTE_BRIDGE_URL | ~~Collector 원격 URL~~ | ⚠️ deprecated (remote 모드 전용) |
## Extension VS Code 설정 ## Extension VS Code 설정

View File

@@ -1,5 +1,10 @@
"""Collector — local relay between Extension (file-based) and Gateway (HTTP). """Collector — local relay between Extension (file-based) and Gateway (HTTP).
.. deprecated::
Extension이 WebSocket으로 Hub에 직접 연결하므로 Collector는 더 이상 필요하지 않습니다.
BOT_MODE=gateway + Extension WS 연결을 사용하세요.
이 모듈은 하위 호환을 위해 유지되며, 향후 제거될 수 있습니다.
The Collector runs on the local PC alongside the AG IDE. The Collector runs on the local PC alongside the AG IDE.
It bridges the gap between the Extension (which writes to local bridge/ files) It bridges the gap between the Extension (which writes to local bridge/ files)
and the remote Gateway (which manages Discord). and the remote Gateway (which manages Discord).

View File

@@ -0,0 +1,5 @@
# Devlog — 2026-03-18
| # | 시간 | 작업 | 커밋 | 상태 |
|---|------|------|------|------|
| 001 | 06:09~06:26 | known-issues 정리/아카이빙 + Collector 폐기 마킹 + 문서 보강 (architecture, tech-stack, conventions) | `69feafc` | ✅ |

View File

@@ -51,8 +51,14 @@ async def main():
# Get the running loop # Get the running loop
loop = asyncio.get_running_loop() loop = asyncio.get_running_loop()
# ── Collector mode: no Discord bot, just relay local ↔ Gateway ── # ── Collector mode (DEPRECATED): no Discord bot, just relay local ↔ Gateway ──
if Config.BOT_MODE == "remote": if Config.BOT_MODE == "remote":
logger.warning("=" * 50)
logger.warning("⚠️ Collector mode (BOT_MODE=remote) is DEPRECATED")
logger.warning("Extension이 WebSocket으로 Hub에 직접 연결합니다.")
logger.warning("BOT_MODE=gateway로 전환하세요.")
logger.warning("=" * 50)
from bridge import LocalTransport, RemoteTransport from bridge import LocalTransport, RemoteTransport
from collector import CollectorBridge from collector import CollectorBridge