Commit Graph

11 Commits

Author SHA1 Message Date
minsung
03fb504eea BREAKING: 3-tier split step 2 + engine-bridge v3 EgBim lambdas wired
Completes the Generic / HmEG-aware / App-specific separation started in
f6b6e74. The legacy EgPlugin / EngineBridge / EngineBridge.Client /
EngineBridge.Probe modules are moved into their proper tiers, namespaces
and csproj/sln entries are renamed, and the HmegDirectStateProvider
lambdas are finally populated with real handles from the EgBim plugin
host. A new Recordingtest.Architecture.Tests project enforces the tier
rule at build time.

Moves (git mv + csproj/RootNamespace/AssemblyName rename + sln):

  src/Recordingtest.EgPlugin
    -> src/Sut/EgBim/Recordingtest.Sut.EgBim.PluginHost
  src/Recordingtest.EngineBridge
    -> src/Hmeg/Recordingtest.Hmeg.Catalog
  src/Recordingtest.EngineBridge.Client
    -> src/Hmeg/Recordingtest.Hmeg.Bridge.Client
  src/Recordingtest.EngineBridge.Probe
    -> src/Hmeg/Recordingtest.Hmeg.Catalog.Probe

  tests/Recordingtest.EgPlugin.Tests
    -> tests/Sut/EgBim/Recordingtest.Sut.EgBim.PluginHost.Tests
  tests/Recordingtest.EngineBridge.Tests
    -> tests/Hmeg/Recordingtest.Hmeg.Catalog.Tests
  tests/Recordingtest.EngineBridge.IntegrationTests
    -> tests/Hmeg/Recordingtest.Hmeg.Catalog.IntegrationTests

Namespace rename applied across all .cs files and csproj RootNamespace:

  Recordingtest.EgPlugin           -> Recordingtest.Sut.EgBim.PluginHost
  Recordingtest.EngineBridge       -> Recordingtest.Hmeg.Catalog
  Recordingtest.EngineBridge.Client -> Recordingtest.Hmeg.Bridge.Client
  Recordingtest.EngineBridge.Probe -> Recordingtest.Hmeg.Catalog.Probe

New: tests/Recordingtest.Architecture.Tests/

  DependencyGraphTests walks Assembly.GetReferencedAssemblies() for each
  tier and fails if a forbidden reference leaks in:
    - Generic modules must not reference HmEG or any app-specific DLL
    - HmEG-aware modules must not reference app-specific DLLs
    - Recordingtest.Hmeg.Bridge must reference HmEG (positive check)
  11 tests, all passing. Prevents future drift from CLAUDE.md §8.1.

Engine-bridge v3 wire-up (HmEgBridgePlugin.BuildProvider):

  Previously the HmegDirectStateProvider lambdas returned null and the
  chain fell through to reflection. They now call directly into the
  EditorPlugin base class that HmEgBridgePlugin inherits:

    spaceProvider    = () => RootSpace
                           // AppManager.ViewportManager.RootSpace
    viewportProvider = () => View
                           // EGViewport : Control, HmEGViewport
    documentPathProvider = () => AppManager?.FileManager?.CurrentFile

  Every lambda is wrapped in try/catch so plugin construction still
  cannot throw back into the SUT. Editor02.HmEGAppManager.dll added as
  a reference on Recordingtest.Sut.EgBim.PluginHost.csproj — app-
  specific tier, which is allowed by the architecture tests.

Entry points were confirmed from read-only review of the SUT sources at
  D:\GiteaAll\EG-BIM_Modeler\EditorPluginInterface\EditorPlugin.cs
  D:\GiteaAll\EG-BIM_Modeler\HmEGApplicationManagementLibrary\HmEGAppManager.cs
  D:\GiteaAll\EG-BIM_Modeler\HmEGApplicationManagementLibrary\SubManager\FileManager.cs

closing out Q1/Q2/Q6/Q7 from docs/hmeg-api-survey.md.

Tests: 115 -> 126 (+11 Architecture), 0 failures.

Next step: live verification of /scene /camera /selection with a real
SUT session; any discrepancy in HmegDirectStateProvider reflection will
be tightened after observing real HmEG camera field names.

Ref: #10 follow-up, #14 follow-up, docs/contracts/generic-sut-split.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 10:39:13 +09:00
minsung
f6b6e7449e 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>
2026-04-09 09:53:27 +09:00
minsung
a771352bcb recorder: focus poller PoC for Gap I-1 (deferred, #14)
Adds a background focus poller that periodically calls
Automation.FocusedElement() and stamps the path onto key_down RawEvents,
so DragCollapser can fill type-step targets without relying on the stale
post-hoc Resolve() pass. Plumbing:

  Program.cs   — focus poller Task + diagnostic counters
  LowLevelHook — volatile CurrentFocusedPath, stamped on key_down
  RawEvent     — FocusedElementPath already existed (focus_change)
  DragCollapser— typeFocusPath captured at first printable key_down,
                 takes precedence over lastFocusPath/lastMousePath

Result on box-v7.yaml live recording: null_target_steps unchanged (13).
Root cause: EG-BIM Modeler's CommandBox and similar input controls lack
AutomationPeer, so UIA-based focus tracking — from any external process —
cannot see them. The WPF-internal Keyboard.FocusedElement is in-process
only and unreachable from the recorder.

Deferred. The plumbing stays in place because the same stamping path can
be reused by a future generic WPF DLL-injection probe. Player's existing
null-target fallback (Type→OS focus, Click→raw_coord) remains the official
strategy and successfully replays box-v7 end-to-end.

See docs/history/2026-04-08_gap-i1-deferred.md for analysis and future
options (generic WPF injection / AutomationPeer AI attachment).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:49:08 +09:00
minsung
98d801442b player: active foreground wait replaces fixed 600ms sleep (#14)
BringSutToForeground() now polls GetForegroundWindow() == SUT hwnd at 25ms
intervals up to 2s, followed by a 100ms tail settle, instead of the brittle
fixed 600ms sleep. First-attempt replay of box-v6.yaml is now reliable
(previously dropped the opening "BOX" keystrokes on a cold start).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 19:39:05 +09:00
minsung
70bf5703b3 player: raw scenario replay without manual cleanup (#14)
First time box-v6.yaml (raw recorder output, 676 lines) replays end-to-end
and actually creates a Box in the SUT — no AI post-editing of target paths
or offsets required. This is the counterpart to #13's recorder-side fixes:
the player now absorbs the remaining record→replay gaps instead of demanding
a hand-cleaned scenario.

Changes (all in Recordingtest.Player):

- PlayerEngine: null-target fallbacks
  - Type with null target → host.Type() against current focus
  - Click with null target + raw_coord → click at screen-absolute raw_coord
  - Other null targets still skipped
- PlayerEngine: strip leading alt+tab hotkey steps (recording-startup noise
  that fights the player's own foreground switch)
- PlayerEngine: preserve recorded inter-step timing, clamped 150ms–3s,
  routed through new IPlayerHost.Delay so the engine itself stays Sleep-free
  (keeps the existing "no fixed sleep" DoD test passing)
- PlayerEngine: per-step console log for live debugging
- UiaPlayerHost: BringSutToForeground() — SetForeground + Focus + 600ms
  settle, called from Program.cs before engine.Run
- Step model: add RawCoord (int[]) and Ts (long?) fields, auto-mapped from
  YAML raw_coord / ts keys

Tests updated:
- PlayerEngine_NullTarget_SkipsWithoutCalling → _Fallback_Issue14
  (verifies the new Click-with-raw_coord and Type behavior)
- FakePlayerHost (both player.tests and runner.tests) implement Delay

Live smoke: box-v6.yaml raw replay produced the expected Box geometry on
the 2nd attempt; 1st attempt dropped the initial "BOX" keystrokes, tracked
as a follow-up (foreground settle is still threshold-sensitive at 600ms).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 19:26:41 +09:00
minsung
a0609f8f0e Orchestrate engine-bridge v2 + smoke test guide (#10)
- Plugin masquerade pass (11 tests), drop-in via HmEG.PluginLoader (no MEF)
- Smoke test guide covers recorder/player/runner/plugin end-to-end manual steps
- PROGRESS.md Done rows, PLAN.md pivoted to v3 reflection mapping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:12:59 +09:00
minsung
4cee3c2d86 Orchestrate engine-bridge PoC v1 evaluation (#9)
- Static HmEG catalog via MetadataLoadContext, 13 assemblies, 11k+ candidates
- IEngineSnapshot API draft + probe design doc (plugin masquerade recommended)
- All DoD pass on first iteration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:53:10 +09:00
minsung
13dc4109d8 Orchestrate test-runner PoC evaluation (#8)
- 5-module E2E integration runner, 6 tests, all DoD pass
- PROGRESS.md Done row, PLAN.md pivoted to live smoke test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:23:46 +09:00
minsung
836afea5ee Orchestrate P1 UI automation evaluations (#6, #7)
- recorder v1 (fail) → v2 (pass): drag state machine, focus events, ts/raw_coord
- player pass with caveats: reliability untestable in sandbox
- PROGRESS.md Done rows + follow-ups for live SUT smoke test
- PLAN.md P1 pivoted to test-runner + live smoke test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:37:14 +09:00
minsung
e3d2ff6c77 Orchestrate P1 evaluations and update progress (#3, #4, #5)
- sut-prober evaluation (pass)
- diff-reporter evaluation (pass with 1 partial follow-up)
- normalizer evaluations v1 (fail) + v2 (pass)
- PROGRESS.md Done rows for #3, #4, #5 + Follow-ups
- PLAN.md P0 reduced to hook verification

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:20:55 +09:00
minsung
7ffbb1f757 Set up AI dev environment for recordingtest (#2)
- CLAUDE.md with collaboration rules and Planner/Generator/Evaluator cycle
- .claude/ agents, commands, skills, hooks per Claude Code conventions
- Sprint Contracts for sut-prober, normalizer, recorder, player, diff-reporter
- SUT catalog (EG-BIM Modeler, 187 plugins) and .gitignore excluding SUT tree
- PROGRESS.md / PLAN.md as shared agent handoff state
- Solution scaffold targeting sut-prober PoC

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