Set up AI dev environment for recordingtest (#2)

- CLAUDE.md with collaboration rules and Planner/Generator/Evaluator cycle
- .claude/ agents, commands, skills, hooks per Claude Code conventions
- Sprint Contracts for sut-prober, normalizer, recorder, player, diff-reporter
- SUT catalog (EG-BIM Modeler, 187 plugins) and .gitignore excluding SUT tree
- PROGRESS.md / PLAN.md as shared agent handoff state
- Solution scaffold targeting sut-prober PoC

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
minsung
2026-04-07 13:57:20 +09:00
parent a48a8a2d1d
commit 7ffbb1f757
47 changed files with 1886 additions and 11 deletions

View File

@@ -0,0 +1,44 @@
# Sprint Contract — diff-reporter
**Owner:** Generator
**Depends on:** normalizer (정규화된 입력)
**Issue:** #2
## Goal
`*.approved``*.received` 쌍을 받아 의미 있는 diff를 생성하고, 실패 지점을 시각화한다. `diff-triager` 서브에이전트가 읽을 수 있는 구조화 출력도 제공.
## Definition of Done
- [ ] `Recordingtest.DiffReporter` 라이브러리 + CLI
- [ ] 입력: `--approved <path> --received <path> --out <dir>`
- [ ] JSON/텍스트 파일은 라인·객체 단위 의미 diff, 바이너리는 hex 요약 diff
- [ ] 출력: `diff.json`(구조화), `diff.md`(사람용), `diff.html`(옵션, side-by-side)
- [ ] `diff.json` 스키마: `{ file, hunks[], summary: { added, removed, changed } }`
- [ ] 동일 파일 비교 시 "identical"로 단정, exit code 0
- [ ] 차이 존재 시 exit code 1 + 요약을 stdout 1줄
- [ ] diff-triager 에이전트가 `diff.json`만 읽어 bucket 분류 가능 (통합 테스트 1개)
## Interfaces
- **Inputs:** 두 파일 경로
- **Outputs:** `diff.json`, `diff.md`, (옵션) `diff.html`
- **Side effects:** 없음
## Out of scope
- 정규화 자체 (normalizer)
- triage 분류 로직 (diff-triager 에이전트)
- 자동 approve (`/approve` 커맨드)
## Evaluation plan
1. 동일 파일 2개 → identical 판정
2. 1필드만 바뀐 JSON → `diff.json.hunks.length == 1`
3. 바이너리 파일 diff → hex summary 출력
4. diff-triager에 통합: normalization gap 케이스에서 bucket=`normalization_gap` 분류 확인
## Risks
- 큰 파일(수십 MB 모델)에서 성능 — 스트리밍 diff 필요
- JSON 스키마 변경 시 triager 하위 호환성

View File

@@ -0,0 +1,43 @@
# Sprint Contract — normalizer
**Owner:** Generator
**Depends on:** sut-prober (Json 카탈로그)
**Issue:** #2
## Goal
SUT 저장 파일(Json 설정 + 모델 파일)의 비결정적 필드를 정규화해 golden-file 비교를 결정적으로 만든다. 규칙은 **프로파일 단위로 버전 관리**되고 단위 테스트를 동반한다.
## Definition of Done
- [ ] `Recordingtest.Normalizer` 라이브러리가 `Normalize(input, profile)` API 제공
- [ ] 기본 프로파일 `default` 포함 규칙 최소 5개: 타임스탬프 마스킹, GUID 치환, 절대 경로 → `<REPO>`/`<USER>`, 부동소수점 epsilon(1e-6), JSON 객체 키 정렬
- [ ] 프로파일은 `profiles/*.yaml`로 선언, 코드 변경 없이 규칙 추가 가능
- [ ] 각 규칙마다 `tests/Normalizer.Tests/` 아래 before/after 샘플 1쌍 이상
- [ ] 동일 입력으로 두 번 정규화해도 같은 바이트 출력 (idempotent)
- [ ] 정규화 로그(sidecar) `normalization.log` 생성 — 어떤 규칙이 몇 번 적용됐는지 기록
- [ ] `json-configs.json` 카탈로그의 "suspected fields" 전수를 default 프로파일로 덮는다
## Interfaces / contracts
- **Inputs:** 파일 경로 + 프로파일 이름
- **Outputs:** 정규화된 바이트 스트림 + sidecar 로그
- **Side effects:** sidecar 로그 쓰기만
## Out of scope
- 바이너리 `.hme`/`.egm` 파서 (별도 contract)
- SUT 내부 호출
- 정규화 규칙 자동 학습
## Evaluation plan
1. `dotnet test tests/Normalizer.Tests` 전부 pass
2. `json-configs.json`의 모든 suspected field가 default 프로파일 규칙에 커버됨 (매핑 테이블 검증)
3. 동일 입력 2회 정규화 바이트 diff 없음
4. 샘플 `Settings.json` 정규화 전/후 비교에서 타임스탬프·경로가 마스킹됨
## Risks
- epsilon 선택이 SUT 실제 정밀도와 충돌 가능 → 구성 가능해야 함.
- 컬렉션 순서 정렬이 SUT 의미를 바꿀 수 있음 → 정렬 대상은 명시적 화이트리스트.

44
docs/contracts/player.md Normal file
View File

@@ -0,0 +1,44 @@
# Sprint Contract — player
**Owner:** Generator
**Depends on:** recorder 스키마 확정
**Issue:** #2
## Goal
recorder가 생성한 시나리오 yaml을 SUT에 재생해 결과 저장 파일을 생성한다. 타이밍은 고정 sleep 금지, UIA/이벤트 기반 동기화.
## Definition of Done
- [ ] `Recordingtest.Player` 콘솔이 `--scenario <path> [--output-dir <path>]` 받음
- [ ] 각 step 재생 전 `wait_for`(uia 이벤트/엘리먼트 property) 대기 구현
- [ ] `target.uia_path`로 엘리먼트 재탐색 후 `offset_norm`으로 좌표 계산해 입력 전달
- [ ] 재생 중 예외 발생 시 시나리오 스텝 index + 엘리먼트 탐색 실패 이유를 아티팩트로 기록
- [ ] 체크포인트 step에서 현재 저장 파일을 `<output-dir>/checkpoint-<n>.*`로 복사
- [ ] 재생 완료 시 exit code 0, 실패 시 non-zero + 아티팩트 경로 출력
- [ ] 동일 시나리오 10회 재생 시 9회 이상 성공 (flaky 허용 상한)
## Interfaces
- **Inputs:** 시나리오 yaml, 아티팩트 출력 디렉터리
- **Outputs:** checkpoint 저장 파일, 실패 아티팩트(스크린샷, UIA 덤프, 로그)
- **Side effects:** SUT 프로세스 실행/종료
## Out of scope
- 정규화 (normalizer의 몫)
- diff (diff-reporter의 몫)
- 리포트 집계 (test-runner의 몫)
## Evaluation plan
1. recorder로 만든 간단 시나리오(Box 생성 저장)를 10회 재생 → 9회 이상 완료 파일 생성
2. 의도적으로 잘못된 `uia_path`를 넣어 실패 → 아티팩트에 탐색 실패 이유 기록 확인
3. 체크포인트 2개 시나리오 재생 → 각 checkpoint 파일 존재 확인
4. 고정 sleep 호출 grep으로 0건 확인
## Risks
- plugin 로드 지연 → 첫 step 전 "plugin ready" 신호 필요
- 시작 상태 초기화 (임시 프로젝트 파일 삭제) 미비 시 누적 오염
- 재생 중 모달 대화상자 출현 시 대응 정책 필요

View File

@@ -0,0 +1,47 @@
# Sprint Contract — recorder
**Owner:** Generator
**Depends on:** FlaUI 승인, sut-prober(UIA 힌트용 카탈로그)
**Issue:** #2
## Goal
사용자가 EG-BIM Modeler에서 수동 테스트하는 동안 입력(키·마우스·창 이벤트)을 캡처해 element-aware 시나리오 파일을 생성한다.
## Definition of Done
- [ ] `Recordingtest.Recorder` 콘솔 실행 시 SUT에 attach하고 입력 캡처 시작
- [ ] 캡처되는 이벤트: 키 다운/업, 마우스 클릭/드래그/휠, 포커스 변경
- [ ] 각 이벤트는 `{ ts, kind, uia_path, offset_norm, raw_coord, value }` 형식으로 기록
- [ ] 3D 뷰포트(SharpDX surface) 클릭 시 uia_path는 호스팅 엘리먼트, `offset_norm``[0..1]` 정규화 좌표
- [ ] 출력: `scenarios/<name>.yaml` 스키마 준수 (`scenario-author` 규격 일치)
- [ ] 비밀번호/토큰 마스킹 규칙 1개 이상 (예: focus된 element가 `PasswordBox`이면 `value``<MASKED>`)
- [ ] 캡처 중 SUT 성능에 눈에 띄는 영향 없음 (60 FPS 유지; 경고만)
- [ ] 캡처 종료 시 요약(이벤트 수, 소요 시간, uia_path 미결 건수)
## Interfaces
- **Inputs:** `--output scenarios/<name>.yaml`, `--attach <pid or window title>`
- **Outputs:** 시나리오 yaml
- **Side effects:** 전역 Win32 hook 등록/해제
## Out of scope
- 리플레이 (player의 몫)
- 3D 엔진 상태 캡처 (engine-bridge 사용 예정)
- 자동 이름 추정 / 자연어 변환 (scenario-author)
## Evaluation plan
1. SUT를 수동 실행 후 recorder attach → Box 명령 버튼 클릭 → Box 생성 드래그 → 저장
2. 출력 yaml 파싱 + 스키마 검증
3. 클릭 이벤트의 `uia_path``Button[@Name*='Box']` 형태 포함 확인
4. 드래그 이벤트의 `offset_norm``[0..1]` 범위 확인
5. `PasswordBox`에 더미 입력 → `<MASKED>` 기록 확인
6. 종료 후 hook 해제 확인 (재실행 시 double-hook 안 남음)
## Risks
- IME(한글) 조합 키 이벤트 손실 → 클립보드 우회 필요 가능
- 해상도/DPI 변경 시 `raw_coord`는 유효성 상실 → `offset_norm` 우선 사용
- Win32 hook은 UI thread 블록 가능 → 별도 스레드 + 큐 필수

View File

@@ -0,0 +1,48 @@
# Sprint Contract — sut-prober
**Owner:** Generator (일반 세션)
**Depends on:** 없음
**Issue:** #2
## Goal
EG-BIM Modeler SUT의 **정적** 구조(플러그인·설정·어셈블리)를 덤프해 `docs/sut-catalog/`에 베이스라인 가능한 카탈로그를 생성한다. SUT는 실행하지 않는다.
## Definition of Done
- [ ] `dotnet run --project src/Recordingtest.SutProber` 실행으로 카탈로그 3종이 생성된다: `plugins.json`, `json-configs.json`, `assemblies.json`
- [ ] `plugins.json``EG-BIM Modeler/Plugins/Eg*Plugin/` 187개(±) 전부를 담고, 각 항목은 `{ name, path, dlls[], size_bytes }` 형식
- [ ] `json-configs.json``EG-BIM Modeler/Json/*.json` 각 파일별 `{ name, top_level_keys[], suspected_nondeterministic_fields[] }`
- [ ] `assemblies.json``HmEG*.dll`, `Editor*.dll`, `HmGeometry*.dll``{ name, size, has_pdb }`
- [ ] 출력은 **정렬되어 있어** 두 번 실행해도 동일 (decimal/텍스트 diff 없음)
- [ ] `EG-BIM Modeler/` 폴더에 대한 쓰기 접근이 없다 (코드 리뷰로 확인)
- [ ] 경로는 repo root 상대 경로로 기록(절대 경로 금지)
## Interfaces / contracts
- **Inputs:** `EG-BIM Modeler/` (read-only), CLI 인자 `--sut <path>` (기본 `EG-BIM Modeler`)
- **Outputs:** `docs/sut-catalog/plugins.json`, `docs/sut-catalog/json-configs.json`, `docs/sut-catalog/assemblies.json`
- **Side effects:** 없음 (로그 제외)
## Out of scope
- SUT 실행 / 리플렉션 / 동적 분석
- PDB 파싱 (engine-bridge의 몫)
- UIA 트리 덤프 (recorder 또는 별도 PoC의 몫)
## Evaluation plan
evaluator는 다음을 수행:
1. `dotnet build` 성공
2. `dotnet run --project src/Recordingtest.SutProber -- --sut "EG-BIM Modeler"` 실행, exit code 0 확인
3. 세 카탈로그 파일 존재 확인 + JSON 파싱 유효성
4. `plugins.json` 엔트리 수 ≥ 180
5. 두 번째 실행 후 세 파일 `git diff` 결과가 비어있음을 확인 (결정성)
6. `grep -r "EG-BIM Modeler" src/Recordingtest.SutProber/` 결과에 `File.Write|File.Delete|File.Create` 호출 없음 확인
## Risks / open questions
- .NET 버전 합의 필요 (`net8.0` 제안). SUT와 다를 수 있으나 prober는 독립 프로세스이므로 무관.
- 플러그인 폴더 구조가 일정한지 샘플 확인 필요.
- 경로 구분자(Windows `\`) 정규화 정책 — 출력에서 `/`로 통일 권장.

View File

@@ -0,0 +1,19 @@
# 2026-04-07 이슈 #2 — AI 기반 AutomationPeer 부착 옵션 기록
- **이슈**: kimminsung/recordingtest#2
- **소요 시간**: ~3분
- **Context 사용량**: ~70k tokens
## 결정/기록
SUT 커스텀 컨트롤에 AutomationPeer를 부착하는 작업을 AI로 자동화하는 보조 전략을 메모리에 남김. Golden-file이 1차 전략이지만, element-aware 레코딩 보강이 필요해질 때 꺼낼 카드.
### 핵심
- 패턴 정형화로 80% AI 자동 생성 가능
- ControlType/패턴 매핑과 `AutomationProperties.Name`은 사람 리뷰 필요
- SUT 저장소엔 별도 브랜치/PR로 제안, 직접 커밋 금지
- recordingtest 저장소에는 가이드/스크립트만, SUT 코드 변경은 fork/PR로 분리
## 산출물
- 메모리: `project_recordingtest_automationpeer_ai.md`
- MEMORY.md 인덱스 갱신

View File

@@ -0,0 +1,21 @@
# 2026-04-07 이슈 #2 — CLAUDE.md에 PROGRESS/PLAN 협업 규칙 추가
- **이슈**: kimminsung/recordingtest#2
- **소요 시간**: ~3분
- **Context 사용량**: ~76k tokens
## 변경 내용
`CLAUDE.md` 에 §0 "세션 시작 시 필독" 섹션 신설. 여러 에이전트 협업을 위한 공유 메모리로 `PROGRESS.md`(끝난 일)와 `PLAN.md`(할 일) 운영 규칙 명시.
### 핵심 규칙
- 세션 시작: PROGRESS.md + PLAN.md 먼저 read
- 시작 시: PROGRESS.md에 in progress 표시
- 종료 시: PROGRESS.md(done 이동) + PLAN.md(완료 제거/다음 단계) + history 파일 (3종 세트)
- 충돌 시 최신 커밋 기준 머지, 모호하면 사용자에 질문
§7 Claude 작업 원칙에도 같은 내용 반영.
## 다음 단계
PROGRESS.md / PLAN.md 실제 파일은 셋업 단계에서 작성 예정 (현재는 CLAUDE.md 규칙만 정의).

View File

@@ -0,0 +1,26 @@
# 2026-04-07 이슈 #2 — CLAUDE.md 작성
- **이슈**: kimminsung/recordingtest#2
- **소요 시간**: ~5분
- **Context 사용량**: ~63k tokens
## 작업 내용
프로젝트 셋업 전, recordingtest(WPF 입력 회귀 자동화 도구)의 운영 지침인 `CLAUDE.md`를 루트에 작성. 셋업은 미실시.
## 포함 섹션
1. 프로젝트 정체성 / SUT 개요
2. 핵심 전략 — Golden-file 회귀
3. 아키텍처 구성요소(8개 모듈) 우선순위
4. 기술 스택 가이드 (FlaUI, Win32 hook, JSON/YAML, LFS)
5. 설계 원칙 8개 (결정성, element-aware, 타이밍, marshaling, 체크포인트, 아티팩트, 침습 최소화, 마스킹)
6. 환경 제약 (세션0, DPI, GPU)
7. 작업 흐름 규칙 (히스토리 필수)
8. 디렉터리 구조(예정)
9. 비목표
10. 결정 로그 위치
## 다음 단계
사용자 승인 후 실제 솔루션/프로젝트 셋업 진행.

View File

@@ -0,0 +1,28 @@
# 2026-04-07 이슈 #2 — SUT (EG-BIM Modeler) 폴더 분석
- **이슈**: kimminsync/recordingtest#2
- **소요 시간**: ~5분
- **Context 사용량**: ~82k tokens
## 분석 대상
`d:/MYCLAUDE_PROJECT/recordingtest/EG-BIM Modeler/` — SUT 실행파일 일습.
## 핵심 발견
- WPF + .NET, 3D 엔진 `HmEG.dll`, 렌더 SharpDX D3D11
- MEF plugin `Plugins/Eg*Plugin/` 수십~100개+
- **PDB 동봉** → 리플렉션/엔진 침습 비용 ↓
- `Json/` 폴더에 텍스트 설정 다수 — golden-file 1차 타깃으로 적합
- 자체 저장 포맷 `.hme`/`.egm` — 파서·정규화 규칙 필요
- 3D 뷰포트는 D3D surface로 UIA 사각지대 확정
## 전략 반영
- sut-prober 첫 PoC: `Plugins/` 스캔 + `Json/` 스냅샷
- engine-bridge: HmEG 리플렉션으로 카메라/씬그래프 접근
- 모델 포맷 파서 모듈 분리
## 산출물
- 메모리: `project_sut_egbim_modeler.md`
- MEMORY.md 인덱스 갱신

View File

@@ -0,0 +1,68 @@
# 2026-04-07 이슈 #2 — .claude/ 에이전트·커맨드·스킬·훅 셋업
- **이슈**: kimminsung/recordingtest#2
- **소요 시간**: ~15분
- **Context 사용량**: ~95k tokens
## 작업 내용
Claude Code 공식 포맷 조사(claude-code-guide 에이전트) 후, recordingtest 운영에 필요한 커스터마이즈를 `.claude/` 하위에 생성.
### Subagents — `.claude/agents/*.md`
- **sut-explorer** — EG-BIM Modeler 정적 분석(플러그인/Json/어셈블리). SUT 실행 금지.
- **diff-triager** — 회귀 실패 분류(real bug / intentional / normalization gap / env drift / flaky).
- **scenario-author** — 자연어 → 시나리오 YAML 생성.
### Slash commands — `.claude/commands/*.md`
- **/sut-probe** — sut-explorer 위임, 카탈로그 생성.
- **/regress** — 회귀 실행 + 실패 자동 triage.
- **/approve** — received → approved 승격, 사유 강제.
- **/handoff** — PROGRESS/PLAN/history 3종 세트 갱신.
- **/progress** — PROGRESS.md/PLAN.md 요약 출력.
### Skills — `.claude/skills/<name>/SKILL.md`
- **golden-file-normalizer** — 정규화 규칙 카테고리/원칙/저작 가이드.
- **flaui-cookbook** — FlaUI 런칭/대기/엘리먼트 캡처/3D 뷰포트 폴백/함정.
### Hooks — `.claude/settings.json` + `.claude/hooks/*.sh`
- **SessionStart** → `session-start-progress.sh`: PROGRESS.md/PLAN.md 자동 주입.
- **PreToolUse(Bash)** → `guard-sut-launch.sh`: EG-BIM Modeler.exe 실행 경고.
- **PreToolUse(Edit|Write)** → `guard-sut-folder.sh`: SUT 폴더 수정 차단(exit 2).
- **Stop** → `stop-handoff-reminder.sh`: 오늘 history 파일/PROGRESS/PLAN 누락 시 /handoff 권장.
## 원칙
- 포맷은 claude-code-guide 조사 결과를 따름(frontmatter: name/description/allowed-tools/tools/model).
- SUT 폴더는 **read-only** — 훅으로 강제.
- 실제 모듈(src/*)은 아직 미생성 — /regress 등은 건드릴 파일이 없으면 early-exit.
## 산출물
```
.claude/
├── agents/
│ ├── sut-explorer.md
│ ├── diff-triager.md
│ └── scenario-author.md
├── commands/
│ ├── sut-probe.md
│ ├── regress.md
│ ├── approve.md
│ ├── handoff.md
│ └── progress.md
├── skills/
│ ├── golden-file-normalizer/SKILL.md
│ └── flaui-cookbook/SKILL.md
├── hooks/
│ ├── session-start-progress.sh
│ ├── guard-sut-launch.sh
│ ├── guard-sut-folder.sh
│ └── stop-handoff-reminder.sh
└── settings.json (hooks 섹션 추가)
```
## 다음 단계
- PROGRESS.md / PLAN.md 실제 파일 작성 (셋업 단계에서)
- src/ 모듈 scaffold
- 훅 bash 스크립트 실제 동작 검증

View File

@@ -0,0 +1,34 @@
# 2026-04-07 이슈 #2 — Golden-file 회귀 전략 채택
- **이슈**: kimminsung/recordingtest#2
- **소요 시간**: ~5분
- **Context 사용량**: ~58k tokens
## 결정
사용자 제안 채택: **수동 테스트 입력 레코딩 → 리플레이 후 저장 파일을 베이스라인과 diff** 하는 golden-file 회귀 방식을 1차 검증 수단으로 삼는다. (ApprovalTests 패턴과 동형)
## 근거
- SUT(WPF+MEF+HmEG)에 AutomationPeer/probe 부착 협조 비용 회피
- 결과물 파일 자체가 검증 기준 → 직관적, 사용자가 시나리오 작성 가능
- 픽셀 비교 의존도 ↓ → viewport-verifier 우선순위 하향
## 성립 조건 / 함정
1. **결정성**: 저장 파일의 타임스탬프/GUID/경로/부동소수점/순서 → 정규화 파이프라인 필수
2. **입력 재현 정확도**: 타이밍·포커스·IME·3D 드래그 픽셀 증폭
3. **비교 범위**: 저장 파일만 vs +중간 체크포인트 vs +엔진 상태 sidecar
4. **베이스라인 관리**: `*.approved`/`*.received` 워크플로, 큰 파일 LFS
5. **진단**: 단계별 스냅샷으로 갈라진 지점 이분 탐색
## 모듈 우선순위 재조정
핵심: **recorder + player + 정규화 모듈 + diff-reporter**
보조: engine-bridge(sidecar JSON 덤프 용도)
후순위: viewport-verifier(픽셀 비교)
## 다음 단계
- 저장 파일 포맷 조사 (텍스트/바이너리, 정규화 가능 영역)
- recorder PoC 범위 정의

View File

@@ -0,0 +1,41 @@
# 2026-04-07 이슈 #2 — Planner/Evaluator 에이전트 & Sprint Contract 도입
- **이슈**: kimminsung/recordingtest#2
- **소요 시간**: ~10분
- **Context 사용량**: ~108k tokens
## 배경
Anthropic "Harness Design for Long-Running Agent Applications" 기사를 읽고, 핵심 원칙을 recordingtest에 반영.
## 추가된 것
### 에이전트
- `.claude/agents/planner.md` — 요청 → Sprint Contract + PLAN.md 엔트리. 구현 금지.
- `.claude/agents/evaluator.md` — 완료된 모듈을 Sprint Contract 기준으로 독립 채점. 자기 작업 평가 금지.
### 커맨드
- `.claude/commands/contract.md``/contract <name>`
- `.claude/commands/evaluate.md``/evaluate <name>`
### CLAUDE.md
- §0.1 "작업 사이클 — Planner → Generator → Evaluator" 섹션 신설
- Sprint Contract / DoD 객관성 / 독립 평가 원칙 명시
- 컨텍스트 위생: compaction 대신 reset, Stop hook 경고 준수, scaffolding audit 상시 항목
- 디렉터리 구조에 `docs/contracts/`, `PROGRESS.md`, `PLAN.md` 추가
### 메모리
- `project_recordingtest_harness_design.md` 신규
- MEMORY.md 인덱스 갱신
## 원칙 요약
1. 생성자와 평가자는 같은 에이전트가 겸하지 않는다.
2. DoD는 객관적으로 검증 가능해야 한다.
3. 컨텍스트가 차면 요약하지 말고 파일에 쏟고 리셋.
4. evaluator fail → PROGRESS.md에 done으로 넘기지 않는다.
5. `.claude/` 비계는 주기적으로 감사·축소.
## 다음 단계
PROGRESS.md / PLAN.md 실제 부트스트랩 (첫 번째 Sprint Contract 작성부터).

View File

@@ -0,0 +1,26 @@
# 2026-04-07 이슈 #2 — 구현 고려사항 정리
- **이슈**: kimminsung/recordingtest#2
- **소요 시간**: ~5분
- **Context 사용량**: ~52k tokens
## 정리한 고려사항 카테고리
1. **레코딩/리플레이 안정성** — 좌표 vs element, 타이밍, 포커스/Z-order, IME
2. **WPF/MEF 특성** — Custom AutomationPeer, plugin 비동기 로드, Dispatcher marshaling
3. **3D 뷰포트(HmEG) 검증** — 픽셀 비교 한계, 엔진 내부 상태 검증, 픽킹 안정성
4. **환경/재현성** — DPI, 멀티모니터, 시계/랜덤 격리, CI 세션 0 제약
5. **테스트 자산 관리** — JSON/YAML 시나리오, 베이스라인 이미지 LFS, 모듈화
6. **진단/디버깅** — 실패 아티팩트(스샷·UIA 덤프·엔진 상태), 영상 녹화, diff 오버레이
7. **보안/안전** — 입력 마스킹, 권한 일치
8. **거버넌스** — SUT 코드 변경 협조(AutomationPeer/probe), 유지보수 비용
## 핵심 인사이트
- 픽셀 비교보다 **엔진 내부 상태(engine-bridge)** 가 훨씬 안정적 → 우선순위 상향
- **SUT 팀 협조** 가 기술적 난제보다 큰 장애물 (AutomationPeer/probe 부착)
- WPF는 세션 0에서 못 돌므로 CI는 대화형 세션 agent 필요
## 다음 단계
위 고려사항을 sut-prober PoC 설계에 반영.

View File

@@ -0,0 +1,41 @@
# 2026-04-07 이슈 #2 — 리서치 및 Agent 분해
- **이슈**: kimminsung/recordingtest#2 — 요구사항 컨텍스트 엔지니어링과 AI 개발환경 셋팅
- **소요 시간**: ~15분
- **Context 사용량**: ~45k tokens
## 작업 내용
WPF + MEF 플러그인 + 자체 HmEG 3D 엔진으로 구성된 SUT를 대상으로 한 입력 회귀 테스트 자동화 도구의 접근법을 웹 리서치하고, 단계별 agent로 분해하여 메모리에 저장.
### 리서치 결론
- **UIA 1순위**: FlaUI (.NET native, WPF 정밀 제어). WinAppDriver는 정체, Appium은 그 래퍼.
- **3D 뷰포트**: UIA 불가 → 좌표 입력 + 픽셀/이미지 비교 + 엔진 in-process hook 하이브리드.
- **MEF plug-in**: 각 plugin 프로젝트에 custom `AutomationPeer` 부착, plugin 상태를 probe로 노출.
- **레코딩**: Win32 low-level hook + UIA element path + offset 동시 저장(해상도 내성).
### Agent 분해(예정)
1. sut-prober — UIA 트리 덤프, MEF plugin 목록
2. recorder — element-aware 입력 캡처
3. player — 재생/동기화
4. viewport-verifier — 3D 스크린샷 비교
5. engine-bridge — HmEG 상태 노출
6. test-runner — 시나리오 실행/리포트
7. diff-reporter — 실패 시각화
## 산출물
- 메모리: `project_recordingtest_goal.md`, `project_recordingtest_plan.md`
- 본 히스토리 파일
## 다음 단계
`sut-prober` PoC부터 시작 — 사용자 결정 대기.
## 참고 링크
- [FlaUI vs WinAppDriver 2026](https://www.testsprite.com/use-cases/en/the-most-accurate-alternatives-to-winappdriver)
- [WPF Custom AutomationPeer](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/ui-automation-of-a-wpf-custom-control)
- [TestComplete WPF Record/Replay](https://support.smartbear.com/testcomplete/docs/app-testing/desktop/wpf/index.html)

View File

@@ -0,0 +1,51 @@
# 2026-04-07 이슈 #2 — 병렬 스캐폴드 + Sprint Contracts 일괄
- **이슈**: kimminsung/recordingtest#2
- **소요 시간**: ~20분
- **Context 사용량**: ~130k tokens
## 작업 내용
"병렬화 가능한 부분 병렬 구현" 요청에 따라, 독립 파일들을 한 세션에서 병렬 Write로 일괄 생성.
### 부트스트랩 문서
- `PROGRESS.md` — 공유 상태 파일 확장 (Done/In progress/Blocked/Scaffolding review)
- `PLAN.md` — P0~P3 우선순위 큐 + 작업 규칙
### Sprint Contracts (5건)
`docs/contracts/` 하위:
- `sut-prober.md` — 187개 플러그인 카탈로그 + json-configs + assemblies 덤프
- `normalizer.md` — 기본 프로파일 5규칙, idempotent
- `recorder.md` — element-aware 입력 캡처, IME·마스킹 포함
- `player.md` — 10회 중 9회 성공, 고정 sleep 금지
- `diff-reporter.md` — JSON/텍스트 의미 diff, triager 연동
각 contract는 planner 에이전트 규격(Goal / DoD / Interfaces / Out of scope / Evaluation plan / Risks)을 준수하며, DoD 항목은 모두 객관적으로 검증 가능.
### SUT 카탈로그 v0
- `docs/sut-catalog/catalog.md` — 어셈블리·UI스택·Json 설정·저장 포맷·영향 요약
- `docs/sut-catalog/plugins.md` — 187개 플러그인 전체 목록 (사전순)
### 솔루션 스캐폴드 (sut-prober PoC)
- `recordingtest.sln`
- `Directory.Build.props` (net8.0, nullable, warnings-as-errors)
- `src/Recordingtest.SutProber/` 4개 파일:
- `Recordingtest.SutProber.csproj`
- `Program.cs` — CLI 진입, `--sut`/`--out` 인자
- `PluginScanner.cs` — 정렬된 플러그인 엔트리 스캔
- `JsonConfigScanner.cs` — Json/*.json top-level 키 + 의심 필드 휴리스틱
- `AssemblyScanner.cs` — HmEG*/Editor*/HmGeometry* 어셈블리 + PDB 존재
**주의**: sut-prober 구현은 contract를 **선제적으로 맞추지는 않음** — 빌드·실행·evaluator 검증은 별도 Generator 세션의 몫. 현재는 컴파일 가능한 뼈대 수준.
## 병렬화 전략
- 파일 간 의존성 0인 것들만 병렬 Write
- Edit는 기존 파일 의존 → 순차 처리
- 에이전트 스폰 대신 단일 세션 다중 도구 호출로 context 오버헤드 최소화
## 다음 단계
1. **Generator 세션**에서 sut-prober 빌드/실행 → 카탈로그 산출물 생성
2. **Evaluator 세션**에서 `/evaluate sut-prober` → contract DoD 채점
3. pass 시 PROGRESS.md → PLAN.md 제거 → P1 항목 착수

100
docs/sut-catalog/catalog.md Normal file
View File

@@ -0,0 +1,100 @@
# SUT Catalog (v0, 정적 분석)
> 수동 관찰 기반 초기 카탈로그. `sut-prober` PoC 완료 시 기계 생성 파일로 교체된다.
> 마지막 갱신: 2026-04-07
## 개요
- **이름**: EG-BIM Modeler
- **위치**: `EG-BIM Modeler/` (git 제외)
- **실행파일**: `EG-BIM Modeler.exe` (.NET / WPF)
- **구성**: `.deps.json`, `.runtimeconfig.json`, `.pdb` 동봉
## 핵심 어셈블리
| 이름 | 역할 | PDB |
|------|------|-----|
| `HmEG.dll` | 자체 3D 엔진 | ✅ (`HmEG.pdb`, `HmEG.xml`) |
| `HmGeometry.dll` / `HmGeometry.V2.dll` | 지오메트리 커널 | ✅ |
| `HmTriangle.dll` | 삼각분할 | ✅ |
| `HmPG.dll` | (추정) 페러미터 그래프/프로파일 | - |
| `HmCommonUI.dll`, `HmCommonBridge.dll` | 공통 UI / 네이티브 브릿지 | - |
| `Editor02.HmEGAppManager.dll` | 앱 생명주기 / plugin 매니저 (MEF 로드 추정) | ✅ |
| `Editor03.PluginInterface.dll` | Plugin 기본 계약 | ✅ |
| `Editor04.CommandControl.dll` | 명령 파이프라인 UI | ✅ |
| `Editor05.CommandCore.dll` | 명령 실행 코어 | ✅ |
| `Editor06.CommandCustom.dll` | 커스텀 명령 | ✅ |
| `Editor07.WidgetPluginInterface.dll` | 위젯 플러그인 계약 | ✅ |
| `EditorCore.dll` | Editor 코어 | ✅ |
| `Editor01.Localization.dll` | 다국어 | ✅ |
| `Editor.AI01.HttpConnector.dll` | AI 연동 | ✅ |
## 렌더링
- **SharpDX** (D3D9/D3D11/DXGI/Direct2D, Mathematics, D3DCompiler)
- 3D 뷰포트는 D3D surface → **UIA 사각지대**
- `assimp.dll` / `AssimpNet.dll` → 메시 임포트
- `freetype6.dll`, `SharpFont.dll` → 폰트
- `SharpVectors.*` → SVG 지원
## UI 스택
- `MahApps.Metro`, `ControlzEx`, `Dragablz`
- `CommunityToolkit.Mvvm`
- `Microsoft.Xaml.Behaviors`, `System.Windows.Interactivity`
- `System.Windows.Controls.WpfPropertyGrid`
- `Microsoft.Web.WebView2.*` (WebView2 패널)
## 유틸/공용
- `Serilog` + `Serilog.Sinks.File`, `log4net`
- `Newtonsoft.Json`, `Google.Protobuf`, `MemoryPack.Core`
- `UnitsNet`, `FluentScheduler`, `System.Reactive`, `Flurl.Http`
- `BaronSoftware.Auth.dll` — 인증/라이선스 추정 (**레코딩 시 민감정보 주의**)
## Json 설정 (텍스트 golden-file 1차 타깃)
`EG-BIM Modeler/Json/`:
- `Settings.json`, `DefaultSettings.json`
- `CategoryCommands.json`, `DefaultCategoryCommands.json`
- `CommandAlias.json`, `DefaultCommandAlias.json`
- `KeyShortCut.json`, `DefaultKeyShortCut.json`
- `MouseSnap.json`, `DefaultMouseSnap.json`
- `StartupCommand.json`, `DefaultStartupCommand.json`
- `Units.json`, `DefaultUnits.json`
- `Materials.json`
- `RecentFiles.json`**확실히 비결정적** (최근 사용 파일 경로)
### 비결정성 후보 필드 (정규화 대상)
- `RecentFiles.json` 전체
- 모든 `Settings.json` 내부의 경로·창 크기·마지막 실행 시간
- GUID·타임스탬프 (포맷 확인 필요)
## 저장 파일 포맷
- `lmd.hme` — 자체 모델 포맷 (`.hme`)
- `jversion.egm` — 버전/메타 파일
- **바이너리 추정** — 별도 포맷 분석 contract 필요
## 로컬라이제이션
- `ko-KR`, `en-US`, `ja-JP`, `es-ES` 리소스 폴더
- `Editor01.Localization.dll` 경유
## MEF Plugin
- 위치: `EG-BIM Modeler/Plugins/Eg*Plugin/`
- **총 187개** (2026-04-07 스냅샷)
- 카테고리: 생성(Box, Circle, Arc, Curve, Cone, Cylinder …), Boolean(Union/Intersection/Difference), Array(Linear/Polar/Crv), Align, Check(Border/Disjointed/Duplicated/NonManifold/Self-Intersection/Overlap/ZeroArea/ZeroCurve), Audit, Block(Edit), Chamfer, Clash, Cap, Cut, DeleteFaces, Import/Export 등
- 전체 목록: [plugins.md](plugins.md)
## recordingtest 영향 요약
1. **1차 검증 타깃**: `Json/` 텍스트 파일 (정규화 쉬움)
2. **2차**: `.hme`/`.egm` 파서 필요
3. **3D 뷰포트**: 좌표 입력 + engine-bridge
4. **Plugin 카탈로그**: sut-prober 자동 덤프
5. **PDB 풍부** → engine-bridge 리플렉션 비용 낮음
6. **인증/라이선스**: 자동화 테스트 환경에서 로그인 상태 유지/마스킹 필요

199
docs/sut-catalog/plugins.md Normal file
View File

@@ -0,0 +1,199 @@
# EG-BIM Modeler Plugin List
- **스냅샷 일시**: 2026-04-07
- **총 개수**: 187
- **경로**: `EG-BIM Modeler/Plugins/`
> 자동 생성 전 수동 덤프. `sut-prober` PoC 완료 시 `plugins.json`으로 교체된다.
## 전체 목록 (사전순)
```
Eg3DFacePlugin
Eg3DMImportExporter
EgAddToGroupPlugin
EgAlignPlugin
EgAlignSelectedVerticesPlugin
EgAlignVerticesPlugin
EgAnglePlugin
EgArcPlugin
EgAreaCentroidPlugin
EgAreaPlugin
EgArrayCrvPlugin
EgArrayLinearPlugin
EgArrayPlugin
EgArrayPolarPlugin
EgAuditPlugin
EgBlockEditPlugin
EgBlockPlugin
EgBooleanDifferencePlugin
EgBooleanIntersectionPlugin
EgBooleanUnionPlugin
EgBoundingBoxPlugin
EgBoxPlugin
EgBuildSectionPlugin
EgCPlanePlugin
EgCapPlugin
EgChamferPlugin
EgChangeColorPlugin
EgCheckBorderEdgePlugin
EgCheckDisjointedMeshPlugin
EgCheckDuplicatedVertexPlugin
EgCheckNonManifoldEdgePlugin
EgCheckSelfIntersectionPlugin
EgCheckSelfOverlapPlugin
EgCheckZeroAreaPlugin
EgCheckZeroCurvePlugin
EgCirclePlugin
EgClashPlugin
EgCloseCrvPlugin
EgClosestPtPlugin
EgConePlugin
EgConvertTextToBlockAttributePlugin
EgCopyPlugin
EgCopyToClipboardPlugin
EgCrvEndPlugin
EgCrvStartPlugin
EgCurvePlugin
EgCurveThroughPtPlugin
EgCutPlugin
EgCylinderPlugin
EgDeleteFacesPlugin
EgDeletePlugin
EgDeleteSubCrvPlugin
EgDeselByUidsPlugin
EgDimAnglePlugin
EgDirPlugin
EgDistancePlugin
EgDividePlugin
EgDomainPlugin
EgDotPlugin
EgDupBorderPlugin
EgDupEdgePlugin
EgDupMeshHoleBoundaryPlugin
EgEditTheGradingElevationPlugin
EgEllipsePlugin
EgEllipsoidPlugin
EgEvaluatePtPlugin
EgExplodeBlockPlugin
EgExplodePlugin
EgExportByPathPlugin
EgExtendPlugin
EgExtractMeshFacePlugin
EgExtractNonManifoldMeshEdgesPlugin
EgExtractPtPlugin
EgExtrudeAlongCrvPlugin
EgExtrudePlugin
EgFillMeshHolePlugin
EgFilletEdgePlugin
EgFilletPlugin
EgFilterByFaceCountPlugin
EgFilterByLayerPlugin
EgFilterByLengthPlugin
EgFilterByModelTypePlugin
EgFilterBySpatialBoxPlugin
EgFilteringWithXYPlanePlugin
EgFindTextPlugin
EgFlipPlugin
EgGroupPlugin
EgHandleCurvePlugin
EgHidePlugin
EgHyperbolaPlugin
EgImportByPathPlugin
EgInsertPlugin
EgInterpCrvPlugin
EgIsolatePlugin
EgJoinPlugin
EgLengthPlugin
EgLinePlugin
EgLineSmoothPlugin
EgLoftPlugin
EgMarginLinePlugin
EgMatchPropertiesPlugin
EgMergeFacesPlugin
EgMeshIntersectPlugin
EgMeshPatchPlugin
EgMeshPolylinePlugin
EgMirrorPlugin
EgModelClearPlugin
EgMovePlugin
EgObjectDescriptionPlugin
EgOffsetMeshPlugin
EgOffsetPlugin
EgOneLayerOffPlugin
EgOneLayerOnPlugin
EgOpenURLPlugin
EgOrientPlugin
EgParabolaPlugin
EgPastePlugin
EgPatchPlugin
EgPipePlugin
EgPlanarDifferencePlugin
EgPlanarIntersectionPlugin
EgPlanarUnionPlugin
EgPlanePlugin
EgPlaneThroughPtPlugin
EgPointPlugin
EgPointsOffPlugin
EgPointsOnPlugin
EgPointsPlugin
EgPolygonCountPlugin
EgPolygonPlugin
EgPolylinePlugin
EgProfileSweepPlugin
EgProjectPlugin
EgProjectionPointPlugin
EgPyramidPlugin
EgRLeaderEditPlugin
EgRebuildPlugin
EgRectanglePlugin
EgReduceMeshPlugin
EgRemoveFromGroupPlugin
EgRemoveSelfIntersectionPlugin
EgRepairCrvTopologyPlugin
EgRevolvePlugin
EgRibbonPlugin
EgRoadSectionPlugin
EgRotate3DPlugin
EgRotatePlugin
EgScale1DPlugin
EgScale2DPlugin
EgScalePlugin
EgScreenShotPlugin
EgSelBoxPlugin
EgSelByUidsPlugin
EgSelColorPlugin
EgSelLayerPlugin
EgSelNamePlugin
EgSelectedLayersOffPlugin
EgSetDisplayModePlugin
EgSetFocusedViewportPlugin
EgSetGroupNamePlugin
EgSetObjectNamePlugin
EgSetViewmodePlugin
EgShearPlugin
EgShowPlugin
EgSlabPlugin
EgSlopePlugin
EgSnipCrvPlugin
EgSpherePlugin
EgSplitDisjointMeshPlugin
EgSplitPlugin
EgSrfPtPlugin
EgSubCrvPlugin
EgSurfaceQuadRemeshPlugin
EgSweep1Plugin
EgSweep2Plugin
EgTextPlugin
EgTorusPlugin
EgTrimPlugin
EgTruncatedPyramidPlugin
EgTubePlugin
EgUnGroupPlugin
EgUngroupAllPlugin
EgUnifyNormalPlugin
EgVerticalScalePlugin
EgVolumeCentroidPlugin
EgZoomPlugin
HMEGImportExport
```