Files
recordingtest/docs/history/2026-04-09_engine-bridge-v3-live-success.md
minsung 062a285462 engine-bridge v3 live: /scene /camera /selection all real (#10)
Live end-to-end verification against EG-BIM Modeler succeeded on the
second attempt:

  /health    -> {"status":"ok","port":38080}
  /scene     -> {"object_count":4,"document_path":"NewSpace0"}
  /camera    -> {"eye":[192.97,-328.52,170.72],
                 "target":[33.03,-72.61,10.78],
                 "up":[0,0,1],"fov":45}
  /selection -> {"selected_ids":["ac0380a2-...","d9a287ee-..."]}

1st attempt returned default-zero camera. Root cause: the viewport lambda
used EditorPlugin.View, which is only populated when the plugin is
actually Run() by a user trigger; our bridge plugin just boots an HTTP
server from its constructor and never runs a command, so View stayed
null. Space access worked because RootSpace goes through AppManager,
which is populated for the whole app.

Fix (HmEgBridgePlugin.BuildProvider):

  Before: viewportProvider = () => View;
  After:  viewportProvider = () => {
              var vm = AppManager?.ViewportManager;
              if (vm is null) return null;
              return vm.FocusedViewport ?? vm.Viewports.FirstOrDefault();
          };

Confirmed against read-only view of
  HmEGApplicationManagementLibrary/SubManager/ViewportManager.cs
which exposes FocusedViewport and Viewports. EGViewport : HmEGViewport
so the lambda matches the Func<HmEGViewport?> contract directly.

Plus: scripts/deploy-egbim-plugin.bat for one-click deploy. Checks for
a running SUT, builds Debug, purges the legacy Recordingtest.EgPlugin
folder, cleans the destination, copies 3 DLLs (+ PDBs) into
  EG-BIM Modeler/Plugins/Recordingtest.Sut.EgBim.PluginHost/
and prints the curl commands for verification. HmEG.dll and the
Editor*.dll assemblies are deliberately NOT copied — the SUT already
supplies them.

PROGRESS.md: engine-bridge v3 row finalized; the long-running "라이브
검증 대기" item is done. PLAN.md P1 advances to the Runner <-> sidecar
integration (snapshot /scene /camera /selection at scenario end and
include in the golden baseline).

Follow-up (noted in history): document_path returned "NewSpace0" for
an unsaved scratch document — need to retest with a saved .hmeg file
to confirm the real FileManager.CurrentFile round-trip.

Ref: #10 follow-up, engine-bridge-v3 contract DoD D7 satisfied.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:38:51 +09:00

4.7 KiB

2026-04-09 — engine-bridge v3 라이브 검증 성공

이슈: #10 follow-up (engine-bridge v3) 소요 시간: ~25분 Context 사용량: input ~40k / output ~8k tokens (Opus 4.6)

결과

🎉 engine-bridge v3 라이브 end-to-end 성공. EG-BIM Modeler 실 환경에서 4개 HTTP 엔드포인트 모두 실값 반환 확인.

PS> curl http://localhost:38080/health
{"status":"ok","port":38080}

PS> curl http://localhost:38080/scene
{"object_count":4,"document_path":"NewSpace0"}

PS> curl http://localhost:38080/camera
{"eye":[192.97503478492047,-328.523410937345,170.7271607015133],
 "target":[33.03212842830112,-72.61476076675402,10.784254344893952],
 "up":[0,0,1],
 "fov":45}

PS> curl http://localhost:38080/selection
{"selected_ids":["ac0380a2-b493-4218-97b7-8017841151c5",
                 "d9a287ee-8d1c-4e32-b879-92575a346ddf"]}

이것이 곧 golden-file 회귀 테스트의 결정성 신호 축이 된다.

과정

1. 배포 스크립트 scripts/deploy-egbim-plugin.bat

사용자가 더블클릭 한 번에 빌드→복사 가능하도록:

  1. EG-BIM Modeler.exe 실행 여부 체크 (DLL 잠금 방지)
  2. dotnet build Debug
  3. 기존 Plugins/Recordingtest.EgPlugin/ (legacy) + 기존 Plugins/Recordingtest.Sut.EgBim.PluginHost/ 삭제
  4. 3개 DLL(+PDB) 복사:
    • Recordingtest.Sut.EgBim.PluginHost.dll (App-specific)
    • Recordingtest.Hmeg.Bridge.dll (HmEG-aware)
    • Recordingtest.Bridge.Abstractions.dll (Generic)
  5. 배포 목록 + curl 명령 안내

HmEG.dll / Editor*.dll은 SUT에 이미 있으므로 복사 안 함.

2. 1차 라이브 결과 (camera 실패)

/scene    → object_count=4 ✅
/camera   → eye/target/up 전부 (0,0,0) ❌
/selection → 2 GUID ✅

/scene 이 작동했으므로 AppManager.ViewportManager.RootSpace 경로는 OK. 즉 spaceProvider 정상.

/camera 는 default fallback. 원인: HmEgBridgePluginviewportProvider = () => this.View에서 View가 항상 null.

3. 원인 분석

EditorPlugin.View플러그인이 Run() 될 때만 주입되는 값. 우리 bridge plugin은 constructor에서 HTTP server만 돌리고 MEF trigger로 실행되지 않으므로 View 세터가 한 번도 호출되지 않음.

반면 AppManagerTriggerStateService.AppManager 를 통해 얻어지며 SUT 전역 상태라 즉시 접근 가능. 그래서 RootSpace 는 동작하지만 View 만 null이었던 것.

4. Fix — ViewportManager.FocusedViewport 경유

D:\GiteaAll\EG-BIM_Modeler\HmEGApplicationManagementLibrary\SubManager\ViewportManager.cs (read-only) 확인:

public HashSet<EGViewport> Viewports { get; set; }
public EGViewport FocusedViewport { get; ... }
public ObservableCollection<HmModel> SelectedModels { get; ... }

FocusedViewport 는 활성 뷰포트를 직접 노출. viewportProvider 를 다음으로 교체:

var vm = AppManager?.ViewportManager;
if (vm is null) return null;
var focused = vm.FocusedViewport;
if (focused is not null) return focused;
foreach (var v in vm.Viewports) if (v is not null) return v;
return null;

5. 2차 라이브 결과 — 전부 성공

재빌드 → 배포 → SUT 재실행 → curl:

  • /camera eye/target/up 실 좌표
  • fov=45 (PerspectiveCameraCore 기본값이 45라 실값인지 fallback인지 구분 안 되지만 reflection이 Position/LookDirection/UpDirection에서 성공한 이상 FieldOfView 도 동일 경로로 성공했다고 판단)
  • /selection 2 GUID 유지
  • /scene object_count=4 유지

6. 부수 관찰

  • document_path="NewSpace0"FileManager.CurrentFile 이 빈 파일에 대해 Space 이름을 반환하는 듯. 저장된 .hmeg 파일일 때 진짜 경로 확인 필요 (follow-up).
  • HmegDirectStateProvider 의 Selection walk (Space.Children 재귀 + ISelectable.IsSelected) 가 잘 동작. 대안 ViewportManager.SelectedModels 로 단순화 가능하나 현재 walk 방식이 결정적이고 테스트 친화적이라 그대로 유지.

남은 것 (다음 단계 P1)

  • Runner ↔ engine-bridge sidecar 연결 — 시나리오 재생 종료 시점에 /scene /camera /selection 한 번 더 호출해 sidecar JSON으로 베이스라인에 포함. .received.json 정규화 규칙 추가. 이게 진짜 golden-file 회귀 파이프라인의 마지막 조각.
  • document_path 의 unsaved vs saved 문서 케이스 확인
  • (선택) SelectionManager.SelectedModels 직접 사용 옵션 비교

관련

  • src/Sut/EgBim/Recordingtest.Sut.EgBim.PluginHost/HmEgBridgePlugin.cs (viewportProvider 교체)
  • scripts/deploy-egbim-plugin.bat (신규 — 배포 자동화)
  • src/Hmeg/Recordingtest.Hmeg.Bridge/HmegDirectStateProvider.cs (reflection 그대로 재사용)
  • docs/hmeg-api-survey.md (Q1~Q7 완성)