3-tier split (step 1) + engine-bridge v3 scaffold + HmegDirectStateProvider

Lays down the Generic / HmEG-aware / App-specific separation that lets us
target other HmEG-hosting WPF applications later, and lands the v3 engine
state provider on top of it.

Architecture rule (CLAUDE.md §8.1, new): every module belongs to exactly one
of three tiers — Generic / HmEG-aware / App-specific (e.g. EgBim). Dependency
direction is strictly App-specific → HmEG-aware → Generic. Generic must not
reference HmEG.dll; HmEG-aware must not reference any per-app assembly.

This commit is the first incremental step:

  + src/Recordingtest.Bridge.Abstractions/  (Generic, new csproj)
      IEngineStateProvider, CameraSnapshot, SceneSnapshot,
      NullEngineStateProvider — extracted from EgPlugin so the generic core
      owns the contract. Zero SUT references.

  + src/Hmeg/Recordingtest.Hmeg.Bridge/      (HmEG-aware, new csproj)
      HmegDirectStateProvider — IEngineStateProvider implemented against
      the HmEG public API (Space, HmEGViewport, ISelectable, ModelBase.Uid).
      Decoupled from any specific host app via Func<Space?>/Func<HmEGViewport?>
      lambdas; the EgBim plugin host supplies them. Reusable for any other
      WPF application that hosts HmEG.

      Selection traversal walks Space.Children and collects ModelBase.Uid
      for nodes whose ISelectable.IsSelected is true. We deliberately type
      nodes as object + late-bound Uid lookup to avoid pulling MemoryPack
      into the dependency graph.

  + tests/Hmeg/Recordingtest.Hmeg.Bridge.Tests/
      5 unit tests covering null lambdas, throwing lambdas, document path
      provider, and constructor null arg validation.

  + src/Recordingtest.EgPlugin/ChainedEngineStateProvider.cs
      Wraps two providers; falls back from Hmeg.Direct to the existing
      Reflection accessor when the primary returns empty/default. Lets us
      land the new wire-up before the EgBim adapter Q1~Q7 lookups are
      filled in. 7 new tests.

  + src/Recordingtest.EgPlugin/IAppManagerAccessor.cs
      Reflection accessor abstraction (preserved as the v3 fallback). Looks
      up Editor.AppManager.AppManager via well-known Instance/Current
      property names. Unit-testable through a fake.

  ~ src/Recordingtest.EgPlugin/IEngineStateProvider.cs
      Type definitions removed (now in Bridge.Abstractions); only the
      reflection-based provider remains. ReflectionEngineStateProvider
      delegates everything to IAppManagerAccessor.

  ~ src/Recordingtest.EgPlugin/HmEgBridgePlugin.cs
      BuildProvider() picks ChainedEngineStateProvider(Hmeg.Direct,
      Reflection). The HmEG-aware lambdas are stubs (return null) until the
      next step wires the EgBim adapter; the chain falls through to the
      reflection path so behaviour matches v2 for now.

  + docs/contracts/engine-bridge-v3.md       — Sprint Contract
  + docs/contracts/generic-sut-split.md      — Sprint Contract for the
      remaining mass-rename / folder move (step 2, deferred).
  + docs/hmeg-api-survey.md                  — Read-only survey of the HmEG
      public API (Space, ModelBase, HmEGViewport, IHmCamera, IPlugin) used
      to design HmegDirectStateProvider. Open Q1~Q7 listed.

Tests: 94 → 115 passing, 0 failing. The new HmEG-aware test project copies
HmEG.dll next to its output (Private=true) since it runs out-of-process.

Step 2 (deferred to next session): mass-rename
  src/Recordingtest.EgPlugin → src/Sut/EgBim/Recordingtest.Sut.EgBim.PluginHost + .Adapter
  src/Recordingtest.EngineBridge → src/Hmeg/Recordingtest.Hmeg.Catalog
  src/Recordingtest.EngineBridge.Client → split (Generic + Hmeg)
plus Recordingtest.Architecture.Tests to enforce the §8.1 dependency rule.

Ref: #10 follow-up, #14 follow-up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
minsung
2026-04-09 09:53:27 +09:00
parent a771352bcb
commit f6b6e7449e
24 changed files with 1743 additions and 32 deletions

View File

@@ -8,9 +8,13 @@
1. **훅 동작 검증** — SessionStart/Stop/Guard 3개 shell 스크립트를 실제로 트리거시켜 확인
- 의존: jq 설치 여부 확인
## P0.5 — 아키텍처 정렬
3a. **3-tier 분리 refactor 2단계** (`docs/contracts/generic-sut-split.md`) — 1단계(신규 모듈 신설)는 commit `pending`로 완료. 2단계는 기존 `EgPlugin`/`EngineBridge`/`EngineBridge.Client` **rename + 폴더 이동** + ArchitectureTests. 단일 BREAKING 커밋. CLAUDE.md §8.1 규칙 준수.
## P1 — 라이브 검증 (사용자 환경 필요)
4. **engine-bridge v3**`ReflectionEngineStateProvider` 실매핑. v2의 plugin masquerade + HttpListener 위에 카메라/선택/씬그래프 상태를 reflection으로 노출. 골든파일 sidecar JSON. `/contract engine-bridge-v3`.
4. **engine-bridge v3 라이브 검증**`HmegDirectStateProvider` wire-up 완료. EgBim adapter의 Space/Viewport 람다를 실값으로 매핑 (`Editor03.PluginInterface` 또는 SUT-side AppManager 진입점 필요 — Q1~Q7). 라이브에서 `curl /scene /camera /selection` 으로 확인.
5. ~~recorder Gap I-1~~**deferred**. UIA poller PoC 결과 본질적 한계 확인 (AutomationPeer 부재 컨트롤은 못 봄). generic WPF DLL injection 또는 AutomationPeer AI 부착 PoC가 선결.
## Follow-ups (non-blocking)