diff --git a/README.md b/README.md index b0ad78f..4b92480 100644 --- a/README.md +++ b/README.md @@ -12,18 +12,45 @@ [회귀 시점] → 입력 리플레이 → 결과 파일 B → normalize → diff(A, B) ``` +## 3계층 아키텍처 + +본 도구는 **EG-BIM Modeler 외 다양한 WPF 응용**을 대상으로 하고, 사용자 WPF 응용군 대다수가 자체 3D 엔진 **HmEG**를 공유한다. 따라서 코드는 엄격히 3계층으로 분리된다 (의존 방향 단방향, 자세한 규칙은 [CLAUDE.md §8.1](CLAUDE.md)): + +``` +App-specific (e.g. EgBim) ──→ HmEG-aware ──→ Generic + (특정 앱만) (HmEG 호스팅 앱 공통) (임의 WPF 앱) +``` + +`Recordingtest.Architecture.Tests` 가 `Assembly.GetReferencedAssemblies()` 검사로 빌드 시점에 규칙을 강제한다. 새 SUT를 추가할 때는 App-specific 계층에 플러그인 진입점 + 어댑터만 작성하고 Generic + HmEG-aware 전부 재사용. + ## 모듈 구성 +### Generic tier — 임의 WPF 응용 + | 모듈 | 책임 | 상태 | |------|------|------| +| [Recordingtest.Bridge.Abstractions](src/Recordingtest.Bridge.Abstractions/) | `IEngineStateProvider`/`CameraSnapshot`/`SceneSnapshot` 등 SUT-중립 인터페이스 | ✓ | | [Recordingtest.SutProber](src/Recordingtest.SutProber/) | SUT 정적 probe (plugin/Json/assembly 카탈로그) | PoC pass | | [Recordingtest.Recorder](src/Recordingtest.Recorder/) | 입력 캡처 (UIA element path + offset + 키/마우스/포커스) | PoC pass | -| [Recordingtest.Player](src/Recordingtest.Player/) | 시나리오 재생, 비동기 동기화 | PoC pass | +| [Recordingtest.Player](src/Recordingtest.Player/) | 시나리오 재생, 비동기 동기화, null-target fallback | PoC pass | | [Recordingtest.Normalizer](src/Recordingtest.Normalizer/) | 결과 파일 정규화 (timestamp/GUID/path/float/order) | PoC pass | | [Recordingtest.DiffReporter](src/Recordingtest.DiffReporter/) | approved vs received diff 리포트 | PoC pass | -| [Recordingtest.EngineBridge.Client](src/Recordingtest.EngineBridge.Client/) + [Recordingtest.EgPlugin](src/Recordingtest.EgPlugin/) | HmEG 내부 상태 sidecar (MEF plugin masquerade + HttpListener) | v2 pass | | [Recordingtest.Runner](src/Recordingtest.Runner/) | 5-모듈 E2E 파이프라인 + 실패 triage | PoC pass | +### HmEG-aware tier — HmEG 호스팅 앱 공통 + +| 모듈 | 책임 | 상태 | +|------|------|------| +| [Recordingtest.Hmeg.Bridge](src/Hmeg/Recordingtest.Hmeg.Bridge/) | `HmegDirectStateProvider` — HmEG 공개 API(Space/HmEGViewport/ISelectable)로 상태 읽기. 앱에 람다로 진입점 주입 | v3 wired | +| [Recordingtest.Hmeg.Catalog](src/Hmeg/Recordingtest.Hmeg.Catalog/) | HmEG 정적 분석 카탈로그 | PoC pass | +| [Recordingtest.Hmeg.Bridge.Client](src/Hmeg/Recordingtest.Hmeg.Bridge.Client/) | `/scene` `/camera` `/selection` HTTP 클라이언트 | v2 pass | + +### App-specific tier — 현재 SUT: EG-BIM Modeler + +| 모듈 | 책임 | 상태 | +|------|------|------| +| [Recordingtest.Sut.EgBim.PluginHost](src/Sut/EgBim/Recordingtest.Sut.EgBim.PluginHost/) | MEF 진입점(`EditorPlugin` 상속), `BridgeHttpServer` 부팅, `HmegDirectStateProvider` 람다에 `RootSpace`/`View`/`AppManager.FileManager.CurrentFile` 주입 | v3 wired | + ## 작업 사이클 — Planner / Generator / Evaluator Anthropic harness design 원칙을 채택. 같은 에이전트가 생성과 평가를 겸하지 않는다. @@ -39,20 +66,52 @@ Anthropic harness design 원칙을 채택. 같은 에이전트가 생성과 평 - **시나리오 포맷**: YAML/JSON (git diff 친화적) - **베이스라인**: `*.approved.{ext}` / `*.received.{ext}` +## 주요 이정표 + +- **2026-04-08 — 첫 E2E 성공** 🎉 Smoke 2회차에서 수동 테스트 시나리오 → 재생 → SUT에 Box geometry 생성 확인 (box-v5-clean.yaml). +- **2026-04-08 — Raw 시나리오 E2E 성공** 🎉 수동 cleanup 없이 recorder 원본 `box-v6.yaml`이 그대로 재생되어 Box 생성 (이슈 #14). Player에 null-target fallback, SUT foreground 능동 대기, 선두 alt+tab 노이즈 자동 skip, 스텝 간 타이밍 보존 추가. +- **2026-04-09 — 3-tier 분리 완료** — Generic / HmEG-aware / App-specific 물리적 분리, `Recordingtest.Architecture.Tests`가 의존 그래프 강제. 같은 날 engine-bridge v3 EgBim 람다 실 wire-up (코드 쪽 완료, 라이브 검증 대기). +- **126 단위 테스트** green (Recorder/Player/Normalizer/DiffReporter/Runner/Hmeg.* /Sut.EgBim.* /Architecture) + +자세한 과정은 [docs/history/](docs/history/), 결정 근거는 [docs/contracts/](docs/contracts/) + [docs/hmeg-api-survey.md](docs/hmeg-api-survey.md) 참고. + +## Gap 현황 (주요) + +- **Gap A~H** (smoke 1~2회차) — 전부 fix (#11/#12/#13/#14) +- **Gap I (recorder root-cause)** — EG-BIM Modeler의 CommandBox 등 핵심 입력 컨트롤이 AutomationPeer를 노출하지 않아 UIA 외부에서 본질적으로 식별 불가. **deferred**. 현재는 Player null-target fallback(Type→OS 포커스 / Click→raw_coord)이 공식 우회 전략. 근본 해소는 generic WPF DLL injection 또는 SUT-side AutomationPeer 부착 PoC가 선결. + ## 디렉터리 ``` recordingtest/ -├── src/ # 모듈별 C# 프로젝트 -├── scenarios/ # 시나리오 YAML +├── src/ +│ ├── Recordingtest.Bridge.Abstractions/ # Generic — 인터페이스 +│ ├── Recordingtest.Recorder/ # Generic +│ ├── Recordingtest.Player/ # Generic +│ ├── Recordingtest.Normalizer/ # Generic +│ ├── Recordingtest.DiffReporter/ # Generic +│ ├── Recordingtest.Runner/ # Generic +│ ├── Recordingtest.SutProber/ # Generic +│ ├── Hmeg/ +│ │ ├── Recordingtest.Hmeg.Bridge/ # HmEG-aware +│ │ ├── Recordingtest.Hmeg.Catalog/ # HmEG-aware +│ │ ├── Recordingtest.Hmeg.Bridge.Client/ # HmEG-aware +│ │ └── Recordingtest.Hmeg.Catalog.Probe/ # HmEG-aware CLI +│ └── Sut/ +│ └── EgBim/ +│ └── Recordingtest.Sut.EgBim.PluginHost/ # App-specific +├── tests/ # 같은 계층 구조로 미러링 + Architecture.Tests +├── scenarios/ # 시나리오 YAML (box-v*.yaml) ├── docs/ -│ ├── contracts/ # Sprint Contracts + evaluations -│ ├── history/ # 작업 히스토리 -│ ├── sut-catalog/ # sut-prober 산출물 -│ └── guides/ # smoke test, deploy 가이드 -├── CLAUDE.md # 에이전트 운영 지침 -├── PROGRESS.md # 완료 상태 -└── PLAN.md # 우선순위 큐 +│ ├── contracts/ # Sprint Contracts + evaluations +│ ├── history/ # 작업 히스토리 +│ ├── sut-catalog/ # sut-prober 산출물 +│ ├── engine-catalog/ # HmEG 후보 카탈로그 (정적 분석) +│ ├── hmeg-api-survey.md # HmEG public API 조사 메모 +│ └── guides/ # smoke test, deploy 가이드 +├── CLAUDE.md # 에이전트 운영 지침 + §8.1 3-tier 규칙 +├── PROGRESS.md # 완료 상태 (세션 간 공유 메모리) +└── PLAN.md # 우선순위 큐 ``` ## 저장소 diff --git a/docs/history/2026-04-09_readme-refresh-and-push.md b/docs/history/2026-04-09_readme-refresh-and-push.md new file mode 100644 index 0000000..fbd6593 --- /dev/null +++ b/docs/history/2026-04-09_readme-refresh-and-push.md @@ -0,0 +1,24 @@ +# 2026-04-09 — README 갱신 + 누적 커밋 push + +**이슈**: 없음 (세션 마무리 문서 작업) +**소요 시간**: ~5분 +**Context 사용량**: input ~15k / output ~3k tokens (Opus 4.6) + +## 작업 + +- `README.md`를 3-tier 아키텍처 반영해 전면 갱신 + - 3계층(Generic / HmEG-aware / App-specific) 의존 방향 다이어그램 + 강제 규칙 + - 모듈 표를 계층별로 재구성 (12개 csproj, 이동 후 경로) + - 주요 이정표 섹션: 2026-04-08 첫 E2E, Raw 시나리오 E2E, 2026-04-09 3-tier 분리, 126 tests + - Gap 현황 (A~H 완료, Gap I deferred + Player fallback 전략) + - 디렉터리 트리를 실제 3-tier 구조로 갱신 +- 누적 5개 커밋을 origin으로 push: + - `70bf570` player: raw scenario replay without manual cleanup (#14) + - `98d8014` player: active foreground wait + - `a771352` recorder: focus poller PoC for Gap I-1 (deferred) + - `f6b6e74` 3-tier split (step 1) + engine-bridge v3 scaffold + - `03fb504` BREAKING: 3-tier split step 2 + engine-bridge v3 EgBim lambdas wired + +## 관련 + +- `README.md`