# Stream D — Legacy `OtOpcUa.Host` Removal Procedure > Sequenced playbook for the next session that takes Phase 2 to its full exit gate. > All Stream A/B/C work is committed. The blocker is structural: the 494 v1 > `OtOpcUa.Tests` instantiate v1 `Host` classes directly, so they must be > retargeted (or archived) before the Host project can be deleted. ## Decision: Option A or Option B ### Option A — Rewrite the 494 v1 tests to use v2 topology **Effort**: 3-5 days. Highest fidelity (full v1 test coverage carries forward). **Steps**: 1. Build a `ProxyMxAccessClientAdapter` in a new `OtOpcUa.LegacyTestCompat/` project that implements v1's `IMxAccessClient` by forwarding to `Driver.Galaxy.Proxy.GalaxyProxyDriver`. Maps v1 `Vtq` ↔ v2 `DataValueSnapshot`, v1 `Quality` enum ↔ v2 `StatusCode` u32, the v1 `OnTagValueChanged` event ↔ v2 `ISubscribable.OnDataChange`. 2. Same idea for `IGalaxyRepository` — adapter that wraps v2's `Backend.Galaxy.GalaxyRepository`. 3. Replace `MxAccessClient` constructions in `OtOpcUa.Tests` test fixtures with the adapter. Most tests use a single fixture so the change-set is concentrated. 4. For each test class: run; iterate on parity defects until green. Expected defect families: timing-sensitive assertions (IPC adds ~5ms latency; widen tolerances), Quality enum vs StatusCode mismatches, value-byte-encoding differences. 5. Once all 494 pass: proceed to deletion checklist below. **When to pick A**: regulatory environments that need the full historical test suite green, or when the v2 parity gate is itself a release-blocking artifact downstream consumers will look for. ### Option B — Archive the 494 v1 tests, build a smaller v2 parity suite **Effort**: 1-2 days. Faster to green; less coverage initially, accreted over time. **Steps**: 1. Rename `tests/ZB.MOM.WW.OtOpcUa.Tests/` → `tests/ZB.MOM.WW.OtOpcUa.Tests.v1Archive/`. Add `false` so CI doesn't run them; mark every class with `[Trait("Category", "v1Archive")]` so a future operator can opt in via `--filter`. 2. New `tests/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.E2E/` project (.NET 10): - `ParityFixture` spawns Galaxy.Host EXE per test class with `OTOPCUA_GALAXY_BACKEND=mxaccess` pointing at the dev box's live Galaxy. Pattern from `HostSubprocessParityTests`. - 10-20 representative tests covering the core paths: hierarchy shape, attribute count, read-Manufacturer-Boolean, write-Operate-Float roundtrip, subscribe-receives-OnDataChange, Bad-quality on disconnect, alarm-event-shape. 3. The four 2026-04-13 stability findings get individual regression tests in this project. 4. Once green: proceed to deletion checklist below. **When to pick B**: typical dev velocity case. The v1 archive is reference, the new suite is the live parity bar. ## Deletion checklist (after Option A or B is green) Pre-conditions: - [ ] Chosen-option test suite green (494 retargeted OR new E2E suite passing on this box) - [ ] `phase-2-compliance.ps1` runs and exits 0 - [ ] `Get-Service aaGR, aaBootstrap` → Running - [ ] `Driver.Galaxy.Host` x86 publish output verified at `src/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host/bin/Release/net48/` - [ ] Migration script tested: `scripts/migration/Migrate-AppSettings-To-DriverConfig.ps1 -AppSettingsPath src/ZB.MOM.WW.OtOpcUa.Host/appsettings.json -DryRun` produces a well-formed DriverConfig - [ ] Service installer scripts dry-run on a test box: `scripts/install/Install-Services.ps1 -InstallRoot C:\OtOpcUa -ServiceAccount LOCALHOST\testuser` registers both services and they start Steps: 1. Delete `src/ZB.MOM.WW.OtOpcUa.Host/` (the legacy in-process Host project). 2. Edit `ZB.MOM.WW.OtOpcUa.slnx` — remove the legacy Host `` line; keep all v2 project lines. 3. Migrate the dev `appsettings.json` Galaxy sections to `DriverConfig` JSON via the migration script; insert into the Configuration DB for the dev cluster's Galaxy driver instance. 4. Run the chosen test suite once more — confirm zero regressions from the deletion. 5. Build full solution (`dotnet build ZB.MOM.WW.OtOpcUa.slnx`) — confirm clean build with no references to the deleted project. 6. Commit: `git rm -r src/ZB.MOM.WW.OtOpcUa.Host` followed by the slnx + cleanup edits in one atomic commit titled "Phase 2 Stream D — retire legacy OtOpcUa.Host". 7. Run `/codex:adversarial-review --base v2` on the merged Phase 2 diff. 8. Record `exit-gate-phase-2-final.md` with: Option chosen, deletion-commit SHA, parity test count + duration, adversarial-review findings (each closed or deferred with link). 9. Open PR against `v2`, link the exit-gate doc + compliance script output + parity report. 10. Merge after one reviewer signoff. ## Rollback If Stream D causes downstream consumer failures (ScadaBridge / Ignition / SystemPlatform IO clients seeing different OPC UA behavior), the rollback is `git revert` of the deletion commit — the whole v2 codebase keeps Galaxy.Proxy + Galaxy.Host installed alongside the restored legacy Host. Production can run either topology. `OtOpcUa.Driver.Galaxy.Proxy` becomes dormant until the next attempt. ## Why this can't one-shot in an autonomous session - The parity-defect debug cycle is intrinsically interactive: each iteration requires running the test suite against live Galaxy, inspecting the diff, deciding if the difference is a legitimate v2 improvement or a regression, then either widening the assertion or fixing the v2 code. That decision-making is the bottleneck, not the typing. - The legacy-Host deletion is destructive — needs explicit operator authorization on a real PR review, not unattended automation. - The downstream consumer cutover (ScadaBridge, Ignition, AppServer) lives outside this repo and on an integration-team track; "Phase 2 done" inside this repo is a precondition, not the full release.