Smoke test 1회차 발견된 integration gap 수정 (recorder/player) #11

Closed
opened 2026-04-07 17:23:55 +09:00 by kimminsung · 1 comment
Owner

배경

2026-04-07 smoke test 1회차 — EG-BIM Modeler 라이브 환경에서 recorder attach → Box 명령 수동 수행 → player 재생 시도. 결과:

  • recorder: 3375 이벤트 → 113 스텝으로 collapse (정상)
  • player가 113개 전부 skip — target 필드 100% null
  • unresolved_paths=0 카운터가 거짓 (실제로 해석을 시도하지 않은 경우를 0으로 집계)

단위 테스트는 IElementSnapshot fake 기반이라 실제 UIA 호출 경로를 커버하지 못함 — 전형적 integration gap.

발견된 gap 4개

# 위치 문제
1 recorder target 필드 100% null. UIA resolver가 호출 안 되거나 결과가 버려짐. unresolved_paths=0 카운터 부정확
2 recorder type value가 문자 아닌 Win32 VK 코드 (예: 162=LCtrl, 67=C)
3 player StepKind enum에 Wheel/Focus 누락 → recorder가 쓴 yaml 파싱 실패
4 player target null 시 무조건 (0,0) 클릭/드래그 — 데스크톱 파괴 위험

수정 요구사항

recorder

  • Win32 hook 이벤트 → 각 이벤트에서 실제로 UIA resolver를 호출해 element path와 offset_norm을 채움
  • unresolved_paths 카운터는 "resolver 호출했으나 null" 케이스만 세는 것이 아니라 "호출 시도했으나 실패"를 명확히 구분
  • Key event: Win32 VK 코드를 KeyInterop.KeyFromVirtualKey 또는 유사 API로 문자/키명으로 변환. 필요 시 raw VK는 별도 필드로 보존
  • integration test 추가 (fake Win32 event stream + fake UIA resolver가 실제 호출됨을 검증)

player

  • StepKind enum에 Wheel, Focus 추가. recorder와 schema 공유 또는 검증 기반 문서화
  • target null 스텝은 안전하게 skip + warning 로그 (또는 에러 종료 옵션)
  • Wheel/Focus 처리: PoC 수준에서 no-op + 로그, 이후 IPlayerHost.Wheel(point, delta) / IPlayerHost.Focus(uiaPath) 추가
  • Scenario 스키마 단일 소스화(DRY) 방안 제안: 공유 Recordingtest.Model 라이브러리로 recorder/player가 같은 DTO 참조

사이클

  1. Generator 세션 (recorder + player 동시 작업)
  2. Evaluator 세션
  3. Smoke 2회차 재시도

비용 추정

150250k tokens (recorder 조사 포함)

Related: #2, #6, #7

## 배경 2026-04-07 smoke test 1회차 — EG-BIM Modeler 라이브 환경에서 recorder attach → Box 명령 수동 수행 → player 재생 시도. 결과: - recorder: 3375 이벤트 → 113 스텝으로 collapse (정상) - **player가 113개 전부 skip** — target 필드 100% null - `unresolved_paths=0` 카운터가 거짓 (실제로 해석을 시도하지 않은 경우를 0으로 집계) 단위 테스트는 `IElementSnapshot` fake 기반이라 실제 UIA 호출 경로를 커버하지 못함 — 전형적 integration gap. ## 발견된 gap 4개 | # | 위치 | 문제 | |---|------|------| | 1 | recorder | `target` 필드 100% null. UIA resolver가 호출 안 되거나 결과가 버려짐. `unresolved_paths=0` 카운터 부정확 | | 2 | recorder | `type` value가 문자 아닌 Win32 VK 코드 (예: 162=LCtrl, 67=C) | | 3 | player | `StepKind` enum에 `Wheel`/`Focus` 누락 → recorder가 쓴 yaml 파싱 실패 | | 4 | player | target null 시 무조건 (0,0) 클릭/드래그 — 데스크톱 파괴 위험 | ## 수정 요구사항 ### recorder - Win32 hook 이벤트 → 각 이벤트에서 **실제로 UIA resolver를 호출**해 element path와 offset_norm을 채움 - `unresolved_paths` 카운터는 "resolver 호출했으나 null" 케이스만 세는 것이 아니라 "호출 시도했으나 실패"를 명확히 구분 - Key event: Win32 VK 코드를 `KeyInterop.KeyFromVirtualKey` 또는 유사 API로 문자/키명으로 변환. 필요 시 raw VK는 별도 필드로 보존 - integration test 추가 (fake Win32 event stream + fake UIA resolver가 실제 호출됨을 검증) ### player - `StepKind` enum에 `Wheel`, `Focus` 추가. recorder와 schema 공유 또는 검증 기반 문서화 - target null 스텝은 **안전하게 skip** + warning 로그 (또는 에러 종료 옵션) - `Wheel`/`Focus` 처리: PoC 수준에서 no-op + 로그, 이후 `IPlayerHost.Wheel(point, delta)` / `IPlayerHost.Focus(uiaPath)` 추가 - Scenario 스키마 단일 소스화(DRY) 방안 제안: 공유 `Recordingtest.Model` 라이브러리로 recorder/player가 같은 DTO 참조 ## 사이클 1. Generator 세션 (recorder + player 동시 작업) 2. Evaluator 세션 3. Smoke 2회차 재시도 ## 비용 추정 ~150~250k tokens (recorder 조사 포함) Related: #2, #6, #7
Author
Owner

Smoke gap fix — Verdict: pass

Generator (139fbbc)

근본 원인: Main 스레드가 MTA여서 UIA3 호출이 조용히 실패 + 키 이벤트의 (0,0) 좌표로 resolver 호출도 null. [STAThread] 누락이 진짜 원인이었음.

수정:

  • [STAThread] 추가
  • 키 이벤트는 resolver 호출 스킵 (좌표 무의미)
  • 카운터 분리: unresolved_paths / no_resolver_attempt / null_target_steps
  • KeyTranslator.cs — Win32 VK → 문자/키명 번역 (printable → "BOX", modifier+letter → "ctrl+c")
  • DragCollapser가 printable key 런을 단일 type 스텝으로 묶음
  • player StepKindWheel/Focus 추가
  • player null-target guard — (0,0) 클릭 대신 로그+skip

Evaluator — 모든 gap 통과

# 원래 Gap Fix Regression trap
1 target 100% null STA + key skip + 3 카운터 DragCollapser_PrintableKeys_CollapseIntoSingleTypeStep
2 VK 코드 생값 KeyTranslator.cs full table Value == "BOX" assertion
3 player enum 누락 Wheel/Focus 추가 SmokeRegressionTests yaml parse
4 (0,0) 클릭 null guard + skip 로그 PlayerEngine_NullTarget_SkipsWithoutCalling

Regression trap 검증: git show HEAD~1로 이전 코드 vs 새 테스트 assertion 비교 → 모든 새 테스트가 fix 전에 실패함을 확인.

테스트: 53 → 60 pass, build 0/0.

비용

단계 Tokens
Generator ~94k
Evaluator ~39k
Orchestrator 분담 ~20k
합계 ~153k

다음 단계

Smoke test 2회차 — EG-BIM Modeler에서 Box 명령 재녹화 → 재생. 이번에는 target 필드가 채워지고 "BOX" 문자열이 yaml에 나와야 정상.

closing.

## Smoke gap fix — Verdict: **pass** ✅ ### Generator (`139fbbc`) **근본 원인**: Main 스레드가 **MTA**여서 UIA3 호출이 조용히 실패 + 키 이벤트의 (0,0) 좌표로 resolver 호출도 null. `[STAThread]` 누락이 진짜 원인이었음. **수정**: - `[STAThread]` 추가 - 키 이벤트는 resolver 호출 스킵 (좌표 무의미) - 카운터 분리: `unresolved_paths` / `no_resolver_attempt` / `null_target_steps` - `KeyTranslator.cs` — Win32 VK → 문자/키명 번역 (printable → `"BOX"`, modifier+letter → `"ctrl+c"`) - `DragCollapser`가 printable key 런을 단일 `type` 스텝으로 묶음 - player `StepKind` 에 `Wheel`/`Focus` 추가 - player null-target guard — (0,0) 클릭 대신 로그+skip ### Evaluator — 모든 gap 통과 | # | 원래 Gap | Fix | Regression trap | |---|---------|-----|----------------| | 1 | target 100% null | STA + key skip + 3 카운터 | `DragCollapser_PrintableKeys_CollapseIntoSingleTypeStep` | | 2 | VK 코드 생값 | `KeyTranslator.cs` full table | `Value == "BOX"` assertion | | 3 | player enum 누락 | `Wheel`/`Focus` 추가 | `SmokeRegressionTests` yaml parse | | 4 | (0,0) 클릭 | null guard + skip 로그 | `PlayerEngine_NullTarget_SkipsWithoutCalling` | Regression trap 검증: `git show HEAD~1`로 이전 코드 vs 새 테스트 assertion 비교 → 모든 새 테스트가 fix 전에 실패함을 확인. **테스트**: 53 → 60 pass, build 0/0. ### 비용 | 단계 | Tokens | |------|--------| | Generator | ~94k | | Evaluator | ~39k | | Orchestrator 분담 | ~20k | | **합계** | **~153k** | ### 다음 단계 **Smoke test 2회차** — EG-BIM Modeler에서 Box 명령 재녹화 → 재생. 이번에는 target 필드가 채워지고 "BOX" 문자열이 yaml에 나와야 정상. closing.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: kimminsung/recordingtest#11