Files
recordingtest/docs/contracts/engine-bridge.md
minsung 2a4f1d3fa4 Implement engine-bridge PoC v1 (#9)
- Add Recordingtest.EngineBridge library (IEngineSnapshot, HmEgSnapshot
  skeleton, MetadataLoader, CandidateFinder, CatalogWriter).
- Add Recordingtest.EngineBridge.Probe console exe that dumps
  hmeg-types.json and hmeg-candidates.json to docs/engine-catalog.
- Add Recordingtest.EngineBridge.Tests (xUnit, 6 tests).
- Add probe design doc with plugin-masquerade recommendation.
- Static analysis only; SUT is never executed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:48:58 +09:00

78 lines
4.4 KiB
Markdown

# Sprint Contract — engine-bridge (PoC v1)
**Owner:** Generator
**Depends on:** sut-prober (assemblies.json), SUT PDB 동봉
**Issue:** #9
## Goal
HmEG 3D 엔진 내부 상태(선택된 객체, 카메라, 씬 그래프)를 recordingtest에서 읽을 수 있는 경로를 확보한다. PoC v1은 **정적 탐색 + API 초안 + in-process probe 설계 문서**까지. 실제 SUT attach 및 런타임 검증은 v2로 연기(샌드박스 제약).
## Definition of Done
- [ ] `Recordingtest.EngineBridge` 라이브러리 + `Recordingtest.EngineBridge.Probe` 콘솔 exe
- [ ] **정적 분석**: `System.Reflection.MetadataLoadContext``EG-BIM Modeler/HmEG.dll`, `HmGeometry*.dll`, `Editor*.dll`을 로드해 public/internal 타입 열거 (SUT 실행 금지)
- [ ] **후보 식별**: 다음 키워드를 포함하는 타입·프로퍼티·메서드를 카탈로그화:
- `Select` / `Selection` / `Picked`
- `Camera` / `View` / `Viewport` / `EyePoint`
- `Scene` / `Document` / `World` / `Root`
- `Render` / `Draw` / `Frame`
- [ ] 출력: `docs/engine-catalog/hmeg-types.json`, `hmeg-candidates.json`
- `hmeg-types.json`: 어셈블리별 `{ assembly, typeName, isPublic, namespace }`
- `hmeg-candidates.json`: 후보별 `{ category, assembly, typeName, memberKind(Property|Method|Event), memberName, signature }`
- **결정성**: 정렬된 출력, 2회 실행 후 git diff 비어야 함
- [ ] **API 초안**: `IEngineSnapshot` 인터페이스 + DTOs:
```csharp
public interface IEngineSnapshot {
IReadOnlyList<string> SelectedObjectIds { get; }
CameraState Camera { get; }
SceneSummary Scene { get; }
bool IsRenderComplete { get; }
}
public sealed record CameraState(double[] EyePoint, double[] Target, double[] Up, double Fov);
public sealed record SceneSummary(int ObjectCount, string? DocumentPath);
```
- 실제 구현체 `HmEgSnapshot`은 **skeleton**(throw NotImplementedException)으로 두되, 리플렉션 접근 지점(타입 이름)을 상수로 정의하고 정적 분석 카탈로그에서 실제 존재 확인
- [ ] **Probe 설계 문서** `docs/engine-bridge-probe-design.md`:
- in-process injection 옵션 3가지 (AssemblyLoadContext attach vs. CLR profiler vs. inline MSIL patching) 장단점 + 권고
- 렌더 완료 신호 후보 (property polling vs. event subscription) + 예상 레이턴시
- AutomationPeer 대체 경로와의 비교
- [ ] xUnit 테스트 ≥ 5:
- `MetadataLoader_LoadsHmegAssembly_WithoutExecution` — MetadataLoadContext 사용 확인
- `CandidateFinder_FindsSelectionRelatedTypes` — 실제 HmEG.dll 로드 후 `Selection` 키워드 포함 타입이 1개 이상
- `CatalogSerializer_OutputsSorted_Idempotent` — 2회 생성 시 byte-identical
- `IEngineSnapshot_DefaultInstance_ThrowsNotImplemented` — skeleton 확인
- `CandidateCategories_AllFourPresent` — Select/Camera/Scene/Render 4개 카테고리가 카탈로그에 존재
- [ ] `dotnet build` green + `dotnet test` all pass
- [ ] SUT 폴더 쓰기 접근 없음 (grep으로 확인)
- [ ] 실행 경로: `dotnet run --project src/Recordingtest.EngineBridge.Probe -- --sut "EG-BIM Modeler" --out docs/engine-catalog`
## Out of scope (v2 이후)
- 실제 SUT 프로세스 attach / 리플렉션 호출 실행
- 런타임 값 캡처
- player 통합
- AutomationPeer 자동 부착
## Interfaces
- **Inputs:** SUT 폴더 경로
- **Outputs:** `docs/engine-catalog/*.json`, `docs/engine-bridge-probe-design.md`
- **Side effects:** 없음 (MetadataLoadContext는 순수 메타데이터 로드)
## Evaluation plan
1. `dotnet build recordingtest.sln` green
2. `dotnet test tests/Recordingtest.EngineBridge.Tests` — 5 pass
3. `dotnet run --project src/Recordingtest.EngineBridge.Probe -- --sut "EG-BIM Modeler"` exit 0
4. `hmeg-candidates.json` 카테고리 4개 전부 존재, 각 카테고리 엔트리 ≥ 1
5. 2회 실행 후 git diff 비어있음
6. `IEngineSnapshot` 인터페이스 + 상수가 존재하며, 상수 타입 이름이 실제 카탈로그에 포함됨을 확인하는 테스트 1개
7. Probe 설계 문서가 3개 옵션 비교 + 권고를 포함
## Risks
- HmEG 내부는 obfuscation이 걸려있을 수 있음 → 발견된 타입 수가 적으면 휴리스틱 강화 필요
- Selection 타입이 `internal`이면 PoC v1에서도 메타데이터로는 보임 (접근 가능). 런타임 접근은 v2.
- MetadataLoadContext는 의존 어셈블리 resolver 필요 → `PathAssemblyResolver(new[] { sutRoot, dotnetRuntimeDir })` 세팅 필수.