fix(extension): diff_review 2-strategy deploy + 8s pending delay

- Deploy AcknowledgeCascadeCodeEdit RPC strategy (was in source but never compiled)
- Add 8s setTimeout delay for diff_review pending (AI response arrives on Discord first)
- Capture closure variables for delayed pending creation safety
- known-issues: diff_review pending ordering fix
This commit is contained in:
Variet Worker
2026-03-16 14:22:41 +09:00
parent 15f6a743a4
commit f302984721
6 changed files with 86 additions and 41 deletions

View File

@@ -556,3 +556,10 @@
- **원인**: 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 도착
- **증상**: Discord에 diff_review 승인 버튼이 먼저 표시되고, AI 응답 텍스트가 나중에 도착. 유저가 승인 클릭 후에야 마지막 대화 내용을 확인할 수 있음
- **원인**: RUNNING→IDLE 전환 시 AI 응답 snapshot과 diff_review pending이 같은 poll tick에 생성. `pending_approval_scanner`(3초)가 `chat_snapshot_scanner`보다 먼저 fire하여 버튼이 먼저 Discord에 전달됨
- **해결**: diff_review pending 생성을 `setTimeout(8000)`으로 지연. 변수는 closure로 캡처 (`capturedSessionId`, `capturedStepCount`, 파일 목록). tracking 배열은 즉시 리셋
- **주의**: 8초는 snapshot_scanner + Collector + Gateway + Bot 전체 경로의 전파 시간을 고려한 값. 너무 짧으면 여전히 버튼이 먼저 도착

View File

@@ -3,4 +3,4 @@
| # | 시간 | 작업 | 커밋 | 상태 |
|---|------|------|------|------|
| 001 | 07:30~11:10 | 승인 상태 관리 근본 원인 분석 + v0.3.12 수정 (sawRunningAfterPending gate) + approval-flow.md 시스템 Flow 문서 + known-issues 2건 추가 | `2d9fe96` | ✅ |
| 002 | 13:25~13:48 | DOM Observer 전체 분석 + step_type 매핑 버그 수정 (write→code_edit) + diff_review 핸들러 리팩토링 (AcknowledgeCascadeCodeEdit RPC + openReviewChanges fallback) + known-issues 3추가 | `d521dd5` | 🔧 |
| 002 | 13:25~14:20 | diff_review 핸들러 2-strategy 리팩토링 + 배포 불일치 발견/수정 + pending 순서 8초 지연 + 1차 테스트 (버튼 OK, RPC 미배포→재배포) + known-issues 2| `` | 🔧 |

View File

@@ -1,8 +1,8 @@
# DOM Observer 분석 + diff_review 수정
# DOM Observer 분석 + diff_review 수정 + 배포
- **시간**: 2026-03-16 13:25~13:48
- **시간**: 2026-03-16 13:25~14:20
- **Commit**: ``
- **Vikunja**: 미정
- **Vikunja**: #384 diff_review 원격 승인 테스트 → 진행중
## 분석 결과
@@ -22,8 +22,20 @@ extension.ts 3,166줄 전체를 5개 기능 영역으로 분류:
1. `AcknowledgeCascadeCodeEdit` RPC (UI 조작 불필요)
2. `openReviewChanges` + 파일 포커스 + `agentAcceptAllInFile` (fallback)
- pending에 `modified_files`(전체경로)와 `edit_step_indices`(step 번호) 포함
- diff_review pending 생성을 8초 지연 (AI 응답이 먼저 Discord 도착)
## 테스트 결과 (1차)
- ✅ Discord에 Accept all / Reject all 버튼 표시 확인
- ❌ AcknowledgeCascadeCodeEdit RPC 미실행 — 소스 수정 후 컴파일+배포 누락 발견
- ❌ AI 응답이 승인 버튼보다 늦게 Discord에 도착
## 수정 및 배포
- Extension 재컴파일+배포 (2-strategy diff_review 핸들러 포함)
- diff_review pending 8초 지연 (`setTimeout`) 추가
- known-issues 2건 추가 (isDirty 실패, pending 순서)
## 미완료
- diff_review 실제 테스트 (AG 재시작 후 Accept all 버튼 동작 확인 필요)
- `AcknowledgeCascadeCodeEdit` RPC가 stepIndices 없이도 전체 수락하는지 확인 필요
- **AG 풀 재시작 후 2차 E2E 테스트** 필요
- AcknowledgeCascadeCodeEdit RPC 성공 확인
- AI 응답 → 승인 버튼 순서 확인
- DOM Observer 제거 리팩토링 → diff_review 동작 확인 후 진행

View File

@@ -2432,25 +2432,38 @@ function setupMonitor() {
// ── Diff review detection: if session just went IDLE and files were modified ──
if (wasRunning && !isRunning && pendingModifiedFiles.length > 0) {
const fileList = pendingModifiedFiles.slice(0, 5).join(', ');
logToFile(`[DIFF-REVIEW] IDLE with ${pendingModifiedFiles.length} modified files: ${fileList}`);
const fileCount = pendingModifiedFiles.length;
// Capture variables for delayed closure (poll loop may change them)
const capturedSessionId = activeSessionId;
const capturedStepCount = currentCount;
const capturedModFiles = pendingModifiedFilePaths.slice(0, 20);
const capturedEditSteps = pendingEditStepIndices.slice(0, 20);
logToFile(`[DIFF-REVIEW] IDLE with ${fileCount} modified files: ${fileList}`);
// Reset tracking arrays immediately (so next session starts fresh)
pendingModifiedFiles = [];
pendingModifiedFilePaths = [];
pendingEditStepIndices = [];
// Delay diff_review pending by 8s so AI response snapshot arrives
// on Discord before the approval buttons (snapshot scanner needs time
// to relay the response text to Discord ahead of the approval embed)
setTimeout(() => {
logToFile(`[DIFF-REVIEW] deferred pending creation (8s) for: ${fileList}`);
writeChatSnapshot(`📝 **코드 리뷰 대기**\n\n수정된 파일: ${fileList}\n\nAG에서 Accept all / Reject all로 확인해주세요.`);
writePendingApproval({
conversation_id: activeSessionId,
conversation_id: capturedSessionId,
command: `코드 리뷰: ${fileList}`,
description: `${pendingModifiedFiles.length}개 파일이 수정되었습니다`,
description: `${fileCount}개 파일이 수정되었습니다`,
step_type: 'diff_review',
step_index: currentCount,
step_index: capturedStepCount,
source: 'diff_review_detect',
buttons: [
{ text: 'Accept all', index: 0 },
{ text: 'Reject all', index: 1 },
],
modified_files: pendingModifiedFilePaths.slice(0, 20),
edit_step_indices: pendingEditStepIndices.slice(0, 20),
modified_files: capturedModFiles,
edit_step_indices: capturedEditSteps,
});
pendingModifiedFiles = []; // reset after notification
pendingModifiedFilePaths = [];
pendingEditStepIndices = [];
}, 8000);
}
wasRunning = isRunning;
}

File diff suppressed because one or more lines are too long

View File

@@ -2401,25 +2401,38 @@ function setupMonitor() {
// ── Diff review detection: if session just went IDLE and files were modified ──
if (wasRunning && !isRunning && pendingModifiedFiles.length > 0) {
const fileList = pendingModifiedFiles.slice(0, 5).join(', ');
logToFile(`[DIFF-REVIEW] IDLE with ${pendingModifiedFiles.length} modified files: ${fileList}`);
const fileCount = pendingModifiedFiles.length;
// Capture variables for delayed closure (poll loop may change them)
const capturedSessionId = activeSessionId;
const capturedStepCount = currentCount;
const capturedModFiles = pendingModifiedFilePaths.slice(0, 20);
const capturedEditSteps = pendingEditStepIndices.slice(0, 20);
logToFile(`[DIFF-REVIEW] IDLE with ${fileCount} modified files: ${fileList}`);
// Reset tracking arrays immediately (so next session starts fresh)
pendingModifiedFiles = [];
pendingModifiedFilePaths = [];
pendingEditStepIndices = [];
// Delay diff_review pending by 8s so AI response snapshot arrives
// on Discord before the approval buttons (snapshot scanner needs time
// to relay the response text to Discord ahead of the approval embed)
setTimeout(() => {
logToFile(`[DIFF-REVIEW] deferred pending creation (8s) for: ${fileList}`);
writeChatSnapshot(`📝 **코드 리뷰 대기**\n\n수정된 파일: ${fileList}\n\nAG에서 Accept all / Reject all로 확인해주세요.`);
writePendingApproval({
conversation_id: activeSessionId,
conversation_id: capturedSessionId,
command: `코드 리뷰: ${fileList}`,
description: `${pendingModifiedFiles.length}개 파일이 수정되었습니다`,
description: `${fileCount}개 파일이 수정되었습니다`,
step_type: 'diff_review',
step_index: currentCount,
step_index: capturedStepCount,
source: 'diff_review_detect',
buttons: [
{ text: 'Accept all', index: 0 },
{ text: 'Reject all', index: 1 },
],
modified_files: pendingModifiedFilePaths.slice(0, 20),
edit_step_indices: pendingEditStepIndices.slice(0, 20),
modified_files: capturedModFiles,
edit_step_indices: capturedEditSteps,
} as any);
pendingModifiedFiles = []; // reset after notification
pendingModifiedFilePaths = [];
pendingEditStepIndices = [];
}, 8000);
}
wasRunning = isRunning;
} catch (e: any) {