# 2026-04-09 — 3-tier 분리 1단계 (incremental) **이슈**: #10 follow-up (engine-bridge v3) + 사용자 디렉티브 (Generic / HmEG-aware / App-specific 분리) **소요 시간**: ~70분 **Context 사용량**: input ~205k / output ~38k tokens (Opus 4.6, 1M context, 동일 세션 누적) ## 작업 CLAUDE.md §8.1 의 3-tier 규칙을 incremental하게 코드에 반영. 기존 `EgPlugin`/`EngineBridge` mass-rename은 2단계로 미루고, **새 계층 모듈을 신설**해 wire-up까지 끝냄. ### 신설 (Generic 계층) - `src/Recordingtest.Bridge.Abstractions/` (csproj, net8.0) - `IEngineStateProvider`, `CameraSnapshot`, `SceneSnapshot`, `NullEngineStateProvider` - SUT 어셈블리 참조 0개. CI 안전. - 기존 `Recordingtest.EgPlugin`의 `IEngineStateProvider`/`CameraSnapshot`/`SceneSnapshot`/`NullEngineStateProvider` 정의 제거 → Bridge.Abstractions로 위임 (`using Recordingtest.Bridge;`) ### 신설 (HmEG-aware 계층) - `src/Hmeg/Recordingtest.Hmeg.Bridge/` (csproj, net8.0-windows + WPF + HmEG.dll 직접 참조) - `HmegDirectStateProvider : IEngineStateProvider` - 람다 주입: `Func`, `Func`, `Func?` - `GetSelectedIds`: Space 트리 walk → `ISelectable.IsSelected` 노드의 `Uid` 수집. `ModelBase` 직접 타입 참조 회피 (MemoryPack 의존 차단), 대신 `object` + 패턴 매칭 + 늦은 바인딩 `Uid` 프로퍼티 읽기 - `GetCamera`: `viewport.CameraCore`에서 `Position`/`LookDirection`/`UpDirection`/`FieldOfView`를 reflection으로 읽어 `CameraSnapshot`. Target = Eye + LookDir. - `GetScene`: `space.ItemsCount` + 외부 documentPathProvider 람다 - 모든 호출 try/catch → safe default 폴백 - `tests/Hmeg/Recordingtest.Hmeg.Bridge.Tests/` (csproj, HmEG.dll Private=true로 출력 폴더 복사) - `HmegDirectStateProviderTests` 5개 (null lambdas / throwing lambdas / document path / null arg) ### EgPlugin wire-up - `HmEgBridgePlugin.BuildProvider()` 신설: ``` HmegDirectStateProvider (1순위, lambdas는 일단 null 반환) ↓ default → ReflectionEngineStateProvider (2순위, EgBim AppManager 후보 탐색) ``` 체인: `ChainedEngineStateProvider` - `ChainedEngineStateProvider` 신설 — primary 결과가 default/empty면 fallback 호출. signal별 판정: - SelectedIds 빈 리스트 - Camera Eye=(0,0,0) AND Target=(0,0,0) - Scene ObjectCount=0 AND DocumentPath=null - RenderComplete: primary always wins - 단위 테스트 7개 (`ChainedEngineStateProviderTests`) EgBim adapter(Q1~Q7 답)가 채워지면 `BuildProvider`의 두 람다만 실값으로 바꾸면 라이브 검증으로 이어진다. ### sln/build/test - `dotnet sln add` 로 3개 신규 csproj 등록 - `Recordingtest.Bridge.Abstractions` - `Recordingtest.Hmeg.Bridge` - `Recordingtest.Hmeg.Bridge.Tests` - `dotnet build` 성공 (HmEG.dll의 ModelBase가 MemoryPack 의존성을 transitively 요구해서 1차 빌드 실패 → ModelBase 직접 참조 제거로 우회) - `dotnet test recordingtest.sln`: **0 failures, 115 passed** (94 → 115, +21) ## 분류 라벨 (현재 시점) | 모듈 | 계층 | 비고 | |---|---|---| | `Recordingtest.Bridge.Abstractions` ✨ | **Generic** | 신설 | | `Recordingtest.Hmeg.Bridge` ✨ | **HmEG-aware** | 신설, HmEG.dll만 참조 | | `Recordingtest.EgPlugin` | **App-specific (EgBim)** | rename 대기. Bridge.Abstractions + Hmeg.Bridge 참조하도록 갱신됨 | | 기타 generic 모듈 (Recorder/Player/Normalizer/...) | **Generic** | 변경 없음 | ## 2단계 (다음 세션) `docs/contracts/generic-sut-split.md` D1~D9 잔여: - `src/Recordingtest.EgPlugin/` → `src/Sut/EgBim/Recordingtest.Sut.EgBim.PluginHost/` + `.Adapter/` - `src/Recordingtest.EngineBridge/` → `src/Hmeg/Recordingtest.Hmeg.Catalog/` - `src/Recordingtest.EngineBridge.Client/` → 분할 (generic HTTP + HmEG-shaped) - 네임스페이스 일괄 rename - `Recordingtest.Architecture.Tests` 추가 (의존 그래프 검증) - 단일 BREAKING 커밋 ## 라이브 검증 (Q1~Q7 후) EgBim adapter에서 다음 람다를 실값으로 채운다: ```csharp spaceProvider = () => /* AppManager.Instance.ActiveSpace */ ; viewportProvider = () => /* AppManager.Instance.ActiveViewport (HmEGViewport 캐스트) */ ; documentPathProvider = () => /* AppManager.Instance.ActiveDocumentPath */ ; ``` → `curl http://localhost:38080/scene` 등으로 검증. ## 미커밋 본 세션 누적 (다음 단계에서 통합 커밋): - `Recordingtest.Bridge.Abstractions/` (신규) - `Hmeg/Recordingtest.Hmeg.Bridge/` (신규) - `tests/Hmeg/Recordingtest.Hmeg.Bridge.Tests/` (신규) - `Recordingtest.EgPlugin/` 갱신 (`HmEgBridgePlugin`, `IEngineStateProvider`, `ChainedEngineStateProvider` 신규, csproj ProjectReference 추가) - `Recordingtest.EgPlugin.Tests/` 갱신 (`ChainedEngineStateProviderTests` 신규, using 정리) - `recordingtest.sln` - `CLAUDE.md` §8.1 (직전 단계) - `docs/contracts/generic-sut-split.md`, `docs/contracts/engine-bridge-v3.md`, `docs/hmeg-api-survey.md` - `PROGRESS.md`, `PLAN.md` - 본 history + `2026-04-09_engine-bridge-v3-scaffold.md` ## 관련 - `src/Recordingtest.Bridge.Abstractions/IEngineStateProvider.cs` - `src/Hmeg/Recordingtest.Hmeg.Bridge/HmegDirectStateProvider.cs` - `src/Recordingtest.EgPlugin/HmEgBridgePlugin.cs` - `src/Recordingtest.EgPlugin/ChainedEngineStateProvider.cs` - `tests/Hmeg/Recordingtest.Hmeg.Bridge.Tests/HmegDirectStateProviderTests.cs` - `tests/Recordingtest.EgPlugin.Tests/ChainedEngineStateProviderTests.cs`