fix(bridge): 5 bug fixes for approval signal drop and Discord relay

- DEDUP: add conversation_id guard to prevent cross-session step_index collision
- step_probe: suppress pending when projectName=default (empty window)
- watchCommandsDir: add 3s polling fallback (fs.watch silent fail on Windows)
- auto toggle: write chat_snapshot confirmation back to Discord
- bot on_message: add message ID dedup for Gateway event replay
This commit is contained in:
2026-03-15 08:18:26 +09:00
parent 1f96997831
commit 40e3cd550f
7 changed files with 136 additions and 25 deletions

View File

@@ -440,3 +440,27 @@
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이 가장 확실한 방어