# 2026-04-08 이슈 #13 — smoke 2차 gap fix (Generator + orchestrator 수습) - **이슈**: #13 - **소요 시간**: ~40분 (Generator 3회 시도 중 첫 2번 API 529 overload, 3번째가 실질 완료 후 529로 종료되어 orchestrator가 history/commit만 수습) - **Context 사용량**: ~500k tokens (orchestrator 누적) ## 요약 Smoke 2회차 후속 4개 gap 중 E/F/G 수정. Generator 서브에이전트가 세 번째 시도에서 약 30회 tool 호출 후 Anthropic API 529 overload로 조기 종료되었으나, 실제 코드 작성은 사실상 완료된 상태였음. Orchestrator가 빌드/테스트 검증 후 history/commit 단계만 수습. ## 수정 내역 ### Gap E — Hotkey named key (단위 테스트 추가) `src/Recordingtest.Player/UiaPlayerHost.cs`: - `internal sealed record ParsedHotkey(IReadOnlyList Modifiers, VirtualKeyShort? Main)` 신규 - `internal static ParsedHotkey ParseHotkey(string keys)` 메서드로 기존 switch body 추출 - `Hotkey(string keys)` 는 이제 `ParseHotkey` 호출 후 press/release만 수행 - 신규 테스트: `tests/Recordingtest.Player.Tests/HotkeyParseTests.cs` — **8 tests** (enter/tab/a/ctrl+c/ctrl+shift+s/f5/alt+f4/empty) ### Gap F — recorder focus_change SUT 필터 `src/Recordingtest.Recorder/FocusEventFilter.cs` 신규: ```csharp public static bool ShouldAccept(int candidatePid, int sutPid) { if (sutPid <= 0) return true; // unknown SUT: permissive if (candidatePid <= 0) return false; // unknown element pid: drop return candidatePid == sutPid; } ``` `Program.cs`의 `automation.RegisterFocusChangedEvent` 콜백에서 element.ProcessId 확인 후 `FocusEventFilter.ShouldAccept` 호출 — false면 큐 쓰기 skip. 신규 테스트: `tests/Recordingtest.Recorder.Tests/FocusEventFilterTests.cs` — **4 tests** (same/different/unknownCandidate/unknownSut) ### Gap G — viewport picking foreign-process fallback `src/Recordingtest.Recorder/WindowPointResolver.cs` 신규: - `IWindowPointSource` 인터페이스 (`GetProcessIdAt`, `GetElementAt`, `GetElementFromSutScope`) - `WindowPointResolver.Resolve(source, x, y, sutPid)` — primary element의 process가 SUT가 아니면 SUT-scoped fallback 시도, fallback null이면 primary 유지 (last resort) `Program.cs` 내부 `FlaUiPointSource` 구현체로 wire. `GetElementFromSutScope`는 현재 mainWindow 기반 best-effort hit-test (라이브 SUT 없이 완전 검증 불가 → **honest partial**). 신규 테스트: `tests/Recordingtest.Recorder.Tests/WindowPointResolverTests.cs` — **5 tests** (samePid/differentPid/unknownPid/zeroPid/fallbackNull) ## 테스트 결과 | 프로젝트 | Before | After | |---------|--------|-------| | Player.Tests | 16 | **24** | | Recorder.Tests | 17 | **26** | | 기타 | 변경 없음 | | | **합계** | **77** | **94** | Build: 0 warn / 0 err. 모든 테스트 green. ## Honest partial — Gap G `FlaUiPointSource.GetElementFromSutScope`는 라이브 SUT 환경에서만 완전 검증 가능. Pure `WindowPointResolver` 로직은 fake-backed로 완전히 테스트됨. smoke 3회차에서 실환경 검증 예정. ## Regression trap - HotkeyParseTests: 각 테스트가 pre-refactor의 `p.Length == 1` 체크만으로는 실패 — named key entries 필수 - FocusEventFilterTests: 기존 `Program.cs`에는 이 static이 없었으므로 compile trap - WindowPointResolverTests: 기존에 없던 새 타입 → compile trap + behavior assertion ## 커밋 (wip) Generator가 커밋 전 529로 터져서 orchestrator가 대신 커밋. ## Anthropic API 주의 3회 연속 시도 중 2회 즉시 529, 3회째는 작업 거의 완료 후 529로 종료. 서브에이전트 세션의 "중단 후 부분 작업 보존" 동작이 유용함을 실증 — 파일이 디스크에 이미 쓰인 상태라 orchestrator가 이어받아 마무리 가능.