# Known Issues & Lessons Learned > **�씠 �뙆�씪��� SSOT(Single Source of Truth)�엯�땲�떎.** > �뵒踰꾧퉭�씠�굹 援ы쁽 �쟾�뿉 **諛섎뱶�떆** �씠 �뙆�씪�쓣 �솗�씤�븯�꽭�슂. > �꽭�뀡 醫낅즺 �떆 �깉濡� 諛쒓껄�맂 �씠�뒋瑜� �씠 �뙆�씪�뿉 異붽���빀�땲�떎. # Known Issues & Lessons Learned > **씠 뙆씪 SSOT(Single Source of Truth)엯땲떎.** > 뵒踰꾧퉭씠굹 援ы쁽 쟾뿉 **諛섎뱶떆** 씠 뙆뙆씪쓣 솗씤븯꽭슂. > 꽭뀡 醫낅즺 떆 깉濡 諛쒓껄맂 씠뒋瑜 씠 뙆뙆씪뿉 異붽빀땲떎. > [!TIP] > 빐寃 셿猷뚮맂 怨쇨굅 씠뒋뒗 [`known-issues-archive.md`](file:///c:/Users/Variet-Worker/Desktop/gravity_control/.agents/references/known-issues-archive.md)뿉 蹂닿릺뼱 엳뒿땲떎. > 鍮꾩듂븳 臾몄젣媛 옱諛쒗븯硫 archive뿉꽌 寃깋븯꽭슂. ### [2026-04-16] [Extension] ★ AG Native 세션 AI 응답이 Discord에 전혀 전달되지 않음 (미해결, #632) - **증상**: Discord에 **명령 승인 신호만 전달**되고, AI의 대화 응답/답변 텍스트는 전혀 전달되지 않음. 수십 세션에 걸쳐 지속 발생. - **원인 1 (SDK 경로)**: `GetCascadeTrajectorySteps(cascadeId=세션ID)` → `500 trajectory not found`. AG Native 세션은 Cascade trajectory API에 등록되지 않아 step-probe의 RT-CAPTURE가 불가능. `stepCount`가 항상 1, `delta`는 항상 0이므로 응답 캡처 루프 진입 자체가 안 됨. - **원인 2 (DOM 경로)**: Observer `scanChatBodies()`가 `[data-testid="conversation-view"]`, `[data-step-index]`, `.markdown-body`, `.prose` 등을 탐색하지만, **AG Native 렌더러에는 이 셀렉터가 전부 존재하지 않음** (DOM dump 확인: hasConversationView=false, hasStepIndex=false, hasMarkdownBody=false, hasProse=false, dataTestIds=[]) - **결과**: 버튼 감지(scan→/pending)는 `button` 태그 직접 탐색이므로 정상 작동하나, AI 응답 텍스트 추출 경로는 SDK/DOM 양쪽 모두 구조적으로 차단됨 - **해결 방향**: AG Native 채팅 패널의 실제 DOM 구조를 deep-inspect로 분석하여, AI 응답 컨테이너의 올바른 셀렉터(class/attribute)를 찾아 `scanChatBodies()` 수정 필요. SDK 경로는 AG 구조적 한계로 사용 불가. - **주의**: AG Native 렌더러는 `data-testid`, `data-step-index` 등 Cascade 전용 속성을 사용하지 않음. DOM 분석 시 반드시 AG 패널이 활성화된 상태에서 dump를 취득해야 함 (설정 페이지와 혼동 금지) - **Vikunja**: #632 ### [2026-04-16] [Extension] 터미널 출력(stdout) 텍스트가 명령어로 Discord에 전송 (v0.5.50) - **증상**: Discord에 `cmd="No extension.log found"`, `cmd="AG CLI not found..."`, `cmd="Log found: C:\..."` 등 터미널 **출력** 텍스트가 명령어로 전송됨 - **원인**: Observer가 code 블록 2개를 감지: (1) 프롬프트+명령어 → JUNK_CODE_RE로 스킵, (2) 터미널 출력 → 유효한 code로 판단 → description에 포함. http-bridge enrichment에서 description에 prompt marker(`>`)가 없으면 rawDesc 전체를 enrichedCmd로 채택 - **해결 (v0.5.50)**: `promptMatch` 실패 시(description에 `>` 없음) → 터미널 OUTPUT으로 판단하여 `terminal_output` 사유로 즉시 필터. 실제 명령어는 항상 `…\project > command` 프롬프트를 포함 - **주의**: enrichment은 반드시 prompt marker가 있는 경우에만 수행. description에 `>` 없으면 code 블록의 출력 텍스트 ### [2026-04-15] [Extension] Observer fallback 컨텍스트가 채팅/UI 텍스트를 명령어로 추출 (v0.5.46) - **증상**: Discord에 `cmd="실 동작검증을 해봐야하는데"`, `cmd="variet.gravity-bridge"` 등 사용자 채팅/AI 응답 텍스트가 명령어로 전송됨 - **원인**: v0.5.45에서 `PROMPT_ONLY_RE`가 `code/pre` 요소 스킵 성공했으나, `extractContextFromNearby()`의 fallback(`span/div/p` 수집)이 여전히 작동하여 DOM 트리의 채팅 본문/UI 라벨을 명령어로 추출 - **해결 (v0.5.46)**: Observer v13에 `_promptOnlySkipped` 플래그 — code 요소가 모두 prompt-only이면 fallback 비활성화. http-bridge에 generic button + no-context일 때 무조건 필터 - **주의**: 프롬프트 스킵과 fallback 비활성화는 항상 연동해야 함. VSIX 설치 누락 방지를 위해 빌드 후 즉시 `code --install-extension` 확인 필수 ### [2026-04-15] [Extension] PROMPT_ONLY_RE regex fixes — prompt-only terminal text leaking as enriched cmd (v0.5.45) - **증상**: Discord에 `cmd="…\gravity_control >"` (실제 명령어 없는 빈 터미널 프롬프트)가 전송됨. 명령어가 포함된 경우는 정상 작동 - **원인 1 (Observer)**: `PROMPT_ONLY_RE` 의 `\\\\s`(4중 backslash)가 template literal 안의 regex 리터럴에서 "literal backslash+s"가 되어 whitespace class가 아닌 문자열 매칭 - **원인 2 (http-bridge)**: `PROMPT_ONLY_RE = /^[\s\\\/]*[\w_.-]+\s*[>»$#]\s*$/` — AG 터미널 프롬프트가 `…`(U+2026 ellipsis)로 시작하는데 첫 문자 클래스에 포함 안 됨 - **해결 (v0.5.45, `d2c44fe`)**: Observer `\\s`→`\s`, http-bridge 패턴을 `/^.*[>»$#]\s*$/`로 단순화 - **검증**: 11개 테스트 케이스 전체 통과 --- ### [2026-04-14] [Extension] Observer template literal 정규식 이스케이핑 오류 — "Running N commands" 스킵 미작동 - **증상**: v9에서 `Running N commands` 그룹 헤더를 스킵하는 정규식 `/^Running\s*\d+\s*commands?$/i`를 추가했으나, 실제로 "Running2 commands" 텍스트를 전혀 매칭하지 못하여 여전히 Discord에 `cmd="Running2 commands"`가 전송됨 - **원인**: `observer-script.ts`의 전체 코드가 TypeScript template literal (`` ` `` ... `` ` ``) 안에 있으므로, 정규식 리터럴의 백슬래시가 2중 해석됨: - TS 소스 `\\\\s` (4중) → template literal 출력 `\\s` → **브라우저에서 regex 리터럴 `\\s` = 리터럴 백슬래시+s** ❌ - TS 소스 `\\s` (2중) → template literal 출력 `\s` → **브라우저에서 regex 리터럴 `\s` = whitespace class** ✅ - TS 소스 `\s` (1중) → template literal에서 이스케이프 소멸 → **출력 `s`** ❌ - **영향 범위**: `NOISE_CODE_RE`, `cleanLines()` (word boundary `\b`, newline `\n`), `cleanButtonText()` (whitespace `\s`), port 탐색 regex `\d`, "Running N commands" 스킵 regex 전부 미작동이었음 - 단, `NOISE_RE` (new RegExp() 사용)는 문자열 이스케이핑이므로 4중 백슬래시가 올바름 (string → RegExp는 별도 이스케이핑 레이어) - **해결**: 모든 정규식 리터럴 (`/pattern/flags`) 안의 `\\\\s` → `\\s`, `\\\\d` → `\\d`, `\\\\b` → `\\b`, `\\\\n` → `\\n` 으로 수정 (v0.5.41, `8e89209`) - **주의**: **template literal 안에서 정규식 특수문자를 쓸 때 반드시 구분:** - `new RegExp('pattern')` 문자열: `\\\\s` (4중) — string 이스케이핑(1번)+regex 이스케이핑(1번) = 총 2번 - `/pattern/` 정규식 리터럴: `\\s` (2중) — template literal 이스케이핑(1번)만 = 총 1번 - **검증법**: `node -e "var f = require('./extension/out/observer-script.js').generateApprovalObserverScript; require('fs').writeFileSync('tmp.js', f(0)); console.log(require('fs').readFileSync('tmp.js','utf8').match(/Running.{10}/g));"` 으로 생성된 코드 확인 --- ### [2026-04-13] [Extension] Observer v8 "Running N commands" 그룹 헤더를 승인 버튼으로 오인 — Discord 빈 내용+잘못된 버튼 - **증상**: Discord 승인 요청에 command="Running2 commands", description 비어있음, 버튼도 "Running2 commands / Always run" 형태. 실제 코드/명령어 내용이 전혀 표시되지 않음 - **원인 1**: `observer-script.ts`의 `isActionBtn()`에 `/Running\\s*\\d*\\s*command/i` 패턴이 있어 AG UI의 그룹 헤더 버튼("Running 3 commands")을 승인 버튼으로 분류. `scan()`이 이 버튼을 먼저 만나고 `break`로 나가 실제 "Always run"/"Cancel" 버튼은 처리 안 됨 - **원인 2**: `extractStepContext()`가 `data-step-index` 속성 없으면 `cleanButtonText(btn)` = "Running2 commands"를 그대로 반환. AG Native에는 `data-step-index`/`data-testid` 속성이 없음 (DOM 덤프로 확인) - **원인 3**: `http-bridge.ts`의 "Run/Always run" 필터가 step-probe 미활성(activeSessionId 비어있음) 시에도 DOM observer 신호를 차단 - **해결**: observer v9 (v0.5.40): 1. `isActionBtn()`에서 "Running N commands" 패턴 제거 2. `scan()`에서 `^Running\\s*\\d+\\s*commands?$` 명시적 스킵 3. `extractContextFromNearby()` 추가: `data-step-index` 없이 DOM 트리를 20레벨까지 올라가며 `pre`/`code` 블록에서 실제 명령어 추출 4. `collectSiblingButtons()` 범위를 parent → grandparent → great-grandparent로 확대, 그룹 헤더 스킵 5. `http-bridge.ts`의 "Run" 필터에 `ctx.activeSessionId` 체크 추가 — step-probe 미활성 시 DOM observer 허용 - **주의**: AG Native UI의 "Running N commands"는 아코디언/그룹 헤더이며, 실제 승인 버튼은 하위 레벨의 "Run"/"Always run"/"Cancel". DOM 구조상 버튼 탐색 시 그룹 헤더를 반드시 스킵해야 함 ### [2026-04-13] [Extension] HTTP Bridge UTF-8 인코딩 깨짐 — 한글 description 손실 - **증상**: pending/ 파일의 description 필드에서 한글이 `[AI ]`처럼 깨져서 저장됨. Discord로 전달되는 승인 요청 본문도 깨짐 - **원인**: Node.js HTTP 서버의 `req.on('data', chunk)` 콜백에서 chunk가 Buffer 타입으로 전달되는데, `body += chunk`로 string 결합 시 Buffer의 기본 인코딩(latin1)이 사용되어 multi-byte UTF-8 문자가 손실됨 - **해결**: 모든 POST 핸들러(`/pending`, `/dump-html`, `/chat`, `/deep-inspect-result`, `/test-rpc`)에 `req.setEncoding('utf8')` 추가 (v0.5.39) - **주의**: Node.js HTTP 서버에서 POST body를 문자열로 수집할 때는 반드시 `req.setEncoding('utf8')`을 호출하거나, Buffer를 배열로 모은 후 `Buffer.concat().toString('utf8')`로 변환해야 함 ### [2026-04-13] [Extension] Observer noise 필터 미작동 — textContent가 아이콘 텍스트를 줄바꿈 없이 합침 - **증상**: pending description에 `Thought for 1s`, `chevron_right` 등 Material 아이콘명과 UI 노이즈가 그대로 남아있음 - **원인**: DOM `textContent`는 block 요소 사이에 newline을 삽입하지 않아 `[AI 본문 요약]Thought for 1schevron_right[결행 명령]`처럼 한 줄로 합쳐짐. `cleanLines()`의 줄 단위 noise 필터(`^pattern$`)가 매칭 실패. 또한 `codeText` 추출에는 `cleanLines()`가 아예 미적용 - **해결**: `cleanLines()`에 인라인 pre-strip 추가 — icon명 18종을 regex로 먼저 `\n`으로 치환 후 줄 단위 필터 적용. `codeText`에도 `cleanLines()` 적용 (v0.5.39) - **주의**: DOM에서 텍스트 추출 시 `textContent`는 레이아웃 무시, `innerText`는 detached 노드에서 미작동. 노이즈 필터링은 줄 단위뿐 아니라 인라인 패턴 제거도 병행해야 함 ### [2026-04-13] [Extension] html-patcher String.replace() `$'` 특수 패턴으로 인라인 스크립트 SyntaxError - **증상**: Observer v8 인라인 스크립트가 workbench.html에 삽입되었으나 렌더러에서 전혀 실행되지 않음 (BEACON 핑 0건). V8 캐시 삭제 + AG 재시작 후에도 동일 - **원인**: `html-patcher.ts`에서 `html.replace('', '\n' + inlineBlock + '\n')`를 사용. 인라인 스크립트의 NOISE_RE 정규식에 `')$', 'i'`가 있는데, `$'`는 JS `String.replace()`의 특수 대체 패턴(match 뒤의 텍스트)으로 해석됨. 이로 인해 `` 뒤의 원본 HTML 구조(``, `