Catch-all commit for pending work on the task-galaxy-e2e branch that
wasn't part of the FOCAS migration. Grouping by topic so future per-topic
commits can be cherry-picked if needed.
TwinCAT
- src/.../Driver.TwinCAT/AdsTwinCATClient.cs + TwinCATDriverFactoryExtensions.cs:
factory-registration extensions + ADS client refinements.
- src/.../Driver.TwinCAT.Cli/Commands/BrowseCommand.cs: new browse command
for the TwinCAT test-client CLI.
- tests/.../Driver.TwinCAT.IntegrationTests/TwinCAT3SmokeTests.cs + TwinCatProject/:
fixture scaffold with a minimal POU + README pointing at the TCBSD/ESXi
VM for e2e.
- docs/Driver.TwinCAT.Cli.md + docs/drivers/TwinCAT-Test-Fixture.md:
documentation for the above.
- docs/v3/twincat-backlog.md: forward-looking backlog seed.
Admin UI + fleet status
- src/.../Admin/Components/Pages/Clusters/DriversTab.razor + Hosts.razor:
UI refresh for fleet-status rendering.
- src/.../Admin/Hubs/FleetStatusHub.cs + FleetStatusPoller.cs +
Admin/Program.cs: SignalR hub + poller plumbing for live fleet data.
- tests/.../Admin.Tests/FleetStatusPollerTests.cs: poller coverage.
Server + redundancy runtime (Phase 6.3 follow-ups)
- src/.../Server/Hosting/RedundancyPublisherHostedService.cs: HostedService
that owns the RedundancyStatePublisher lifecycle + wires peer reachability.
- src/.../Server/Redundancy/ServerRedundancyNodeWriter.cs: OPC UA
variable-node writer binding ServiceLevel + ServerUriArray to the
publisher's events.
- src/.../Server/Program.cs + Server.csproj: hosted-service registration.
- tests/.../Server.Tests/ServerRedundancyNodeWriterTests.cs +
Server.Tests.csproj: coverage for the above.
Configuration
- src/.../Configuration/Validation/DraftValidator.cs +
tests/.../Configuration.Tests/DraftValidatorTests.cs: draft-validation
refinements.
E2E scripts (shared infrastructure)
- scripts/e2e/README.md + _common.ps1 + test-all.ps1: shared helpers + the
all-drivers test-all runner.
- scripts/e2e/test-opcuaclient.ps1: OPC UA Client e2e runner.
Docs
- docs/v2/implementation/phase-6-{1,2,3,4}*.md + exit-gate-phase-{3,7}.md:
phase-gate + implementation doc updates.
- docs/v2/plan.md: top-level plan refresh.
- docs/v2/redundancy-interop-playbook.md: client interop playbook for the
Phase 6.3 redundancy-runtime work.
Two orphan FOCAS docs remain on disk but deliberately unstaged —
docs/v2/focas-deployment.md and docs/v2/implementation/focas-simulator-plan.md
describe the now-retired Tier-C topology and should either be rewritten
or deleted in a follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10 KiB
Phase 3 Exit Gate — Driver Fleet (reconstructed retroactively)
Status: CLOSED (reconstructed 2026-04-23). The original plan split the driver work across Phases 3 / 4 / 5 (Modbus alone → four PLC drivers → two specialty drivers). In execution, all seven non-Galaxy drivers shipped under one umbrella against
Core.Abstractions+Core's generic driver-hosting machinery. This doc captures the closure retroactively; no forward work remains under these three original phase numbers.Plan doc: none — phases 3/4/5 were intentionally not split out into separate plan docs once it was clear the capability-interface contract introduced in Phase 1 (
Core.Abstractions— plan decision #4) was stable enough that each driver could land as its own stream rather than as a gated mini-phase. Seedocs/v2/plan.md§6 for the now-consolidated migration strategy.
Scope
All seven drivers in the v2 target list (Decision #5) minus Galaxy (closed
separately under Phase 2). The Galaxy Proxy+Host+Shared split exited under
exit-gate-phase-2-final.md; this gate does not re-cover it.
What shipped
Drivers
| Driver | Project | Capability surface | Test projects |
|---|---|---|---|
| Modbus TCP | Driver.Modbus + Driver.Modbus.Cli |
IDriver + ITagDiscovery + IReadable + IWritable + ISubscribable + IHostConnectivityProbe |
Tests, IntegrationTests, Cli.Tests |
| AB CIP | Driver.AbCip + Driver.AbCip.Cli |
all of the above + IPerCallHostResolver + IAlarmSource |
Tests, IntegrationTests, Cli.Tests |
| AB Legacy (PCCC / DF1) | Driver.AbLegacy + Driver.AbLegacy.Cli |
IDriver + IReadable + IWritable + ITagDiscovery + ISubscribable + IHostConnectivityProbe + IPerCallHostResolver |
Tests, IntegrationTests, Cli.Tests |
| Siemens S7 | Driver.S7 + Driver.S7.Cli |
IDriver + ITagDiscovery + IReadable + IWritable + ISubscribable + IHostConnectivityProbe |
Tests, IntegrationTests, Cli.Tests |
| Beckhoff TwinCAT (ADS) | Driver.TwinCAT + Driver.TwinCAT.Cli |
IDriver + IReadable + IWritable + ITagDiscovery + ISubscribable + IHostConnectivityProbe + IPerCallHostResolver |
Tests, IntegrationTests, Cli.Tests |
| FANUC FOCAS | Driver.FOCAS + Driver.FOCAS.Host + Driver.FOCAS.Shared + Driver.FOCAS.Cli |
IDriver + IReadable + IWritable + ITagDiscovery + ISubscribable + IHostConnectivityProbe + IPerCallHostResolver; Tier-C out-of-process backend mirrors the Galaxy Proxy/Host split. Fwlib64FocasBackend shipped 2026-04-23 as the production backend (P/Invoke against Fwlib64.dll); Host retargeted from net48 x86 to net10.0-windows x64 at the same time. |
Tests, Host.Tests, Shared.Tests, Cli.Tests |
| OPC UA Client (gateway) | Driver.OpcUaClient |
IDriver + ITagDiscovery + IReadable + IWritable + ISubscribable + IHostConnectivityProbe + IAlarmSource + IHistoryProvider (richest surface in the fleet — it's bridging another UA server) |
Tests, IntegrationTests |
Supporting infrastructure
| PR / Task | Summary |
|---|---|
| #248 | DriverFactoryRegistry + DriverInstanceBootstrapper — central DB DriverInstance rows materialise into live IDriver instances at server startup. |
| #210 | Modbus server-side factory + seed SQL (closed first child of umbrella #209). |
| #211 #212 #213 | AB CIP / S7 / AB Legacy server-side factories + seed SQL. |
| #220 (FOCAS) | FOCAS factory wired into the bootstrap pipeline; Tier-C split (Driver.FOCAS.Host process launcher, named-pipe IPC, NSSM install scripts, post-mortem MMF) shipped across the five-PR series. |
| (this session) | TwinCAT factory wired in + Server project reference added; all seven driver factories now register uniformly in Server/Program.cs. |
| #249 #250 #251 | Per-driver test-client CLI suite (otopcua-<driver>-cli) — shared lib + one CLI per driver for direct-to-PLC smoke testing independent of the server. |
| #253 + follow-ups | E2E CLI test scripts (scripts/e2e/test-<driver>.ps1) — five-stage bidirectional bridge + subscribe-sees-change assertions per driver, plus test-all.ps1 matrix runner. |
| (this session) | OPC UA Client e2e script shipped (test-opcuaclient.ps1, 8 stages) — the only driver that was missing an e2e script. |
Docs
Per-driver test-fixture documentation:
docs/drivers/Modbus-Test-Fixture.mddocs/drivers/AbServer-Test-Fixture.md(covers AB CIP fixture)docs/drivers/AbLegacy-Test-Fixture.mddocs/drivers/S7-Test-Fixture.mddocs/drivers/TwinCAT-Test-Fixture.mddocs/drivers/FOCAS-Test-Fixture.mddocs/drivers/OpcUaClient-Test-Fixture.md
Driver-level ops docs:
docs/Driver.Modbus.Cli.md,docs/Driver.AbCip.Cli.md,docs/Driver.AbLegacy.Cli.md,docs/Driver.S7.Cli.md,docs/Driver.TwinCAT.Cli.md,docs/Driver.FOCAS.Cli.mddocs/v2/driver-specs.md— unified capability-matrix spec for all eight drivers (Galaxy + seven).
Compliance evidence
No dedicated phase-3-compliance.ps1 exists — scope was too broad to fit the
single-script pattern that worked for Phases 6.x and 7. Verification instead
takes the form of the per-driver test suites + e2e scripts:
- Unit tests — every driver has a
Testsproject with capability-interface contract tests;dotnet test tests/ZB.MOM.WW.OtOpcUa.Driver.*.Testsis green. - Integration tests —
Driver.*.IntegrationTestsstands up Docker-hosted simulators (pymodbus, ab_server, python-snap7, opc-plc) at collection init and exercises real wire-level read/write/subscribe/probe per driver. - CLI tests —
Driver.*.Cli.Testscovers the per-driver test-client CLIs (#249–#251). - E2E scripts —
scripts/e2e/test-<driver>.ps1covers the driver-CLI → PLC → OtOpcUa server → OPC UA client round-trip for all seven drivers + Galaxy;test-all.ps1aggregates; README status section (rewritten this session) summarises live-boot evidence. - Factory registration — all seven factories plus Galaxy register in
src/ZB.MOM.WW.OtOpcUa.Server/Program.csinside theDriverFactoryRegistrycomposition; theDriverInstanceBootstrappercan materialise any configured row. - Seed SQL — #210–#213 provide per-driver Config DB seed scripts so a fresh Config DB is populatable without Admin UI interaction.
Live-boot verification
Recorded across the session-level tracking tasks:
| Driver | Fixture | Stages | Tracking |
|---|---|---|---|
| Modbus | pymodbus (dl205 profile) | 5/5 | #209 exit gate; bidirectional + subscribe-sees-change added in #253 follow-ups |
| AB CIP | ab_server ControlLogix |
5/5 | #220 |
| S7 | python-snap7 | 5/5 | #220 |
| AB Legacy | ab_server SLC500 / MicroLogix / PLC-5 (requires /1,0 cip-path for Docker fixture) |
5/5 | #222 partial |
| OPC UA Client | opc-plc Docker fixture | 5/8 (probe, remote read, forward bridge, subscribe, browse) | (this session) |
| TwinCAT | TCBSD VM @ 10.100.0.128 (AmsNetId 41.169.163.43.1.1) — real TwinCAT runtime under FreeBSD on ESXi; bypasses the Hyper-V/RTIME conflict that blocks XAR on this dev box |
features validated | fixture is the TCBSD VM; TWINCAT_TRUST_WIRE=1 still gates the e2e script by default so unintentional runs against cold fixtures don't false-pass |
| FOCAS | Lab-rig CNC + Fwlib64.dll |
— | deferred — Fwlib64FocasBackend shipped 2026-04-23; wire-level live-boot gated FOCAS_TRUST_WIRE=1, lab rig tracked under #222 follow-up |
| Galaxy | Live Galaxy + OtOpcUaGalaxyHost (this dev box) |
7/7 (read / write / subscribe / alarms / history) | closed under Phase 2 |
Deferred to post-gate follow-ups
Items intentionally not blocking closure of this umbrella — each is hardware- dependent and tracked separately:
- FOCAS wire-level live-boot —
test-focas.ps1against a real CNC onceFwlib64.dllis on PATH andFOCAS_TRUST_WIRE=1(#222 follow-up). TheFwlib64FocasBackendshipped 2026-04-23 — code exists, unit-tests green; only the live-CNC smoke test remains. - FOCAS
Fwlib64FocasBackend— CLOSED 2026-04-23. The production backend insrc/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Host/Backend/Fwlib64FocasBackend.cswrapsFwlibFocasClientto fulfilIFocasBackendagainst the licensedFwlib64.dll. Host project retargeted tonet10.0-windowsx64. Default whenOTOPCUA_FOCAS_BACKENDis unset. 6 new backend tests green. Only wire-level live-boot against real hardware remains — see item above. - OPC UA Client stages 5/7/8 — reverse-bridge, alarm, history stages are opt-in via sidecar NodeId params because opc-plc's default image has no writable nodes and doesn't historize. Against a richer upstream (Prosys, UA Expert sample server) all eight stages can run.
Completion checklist
- Modbus driver shipped + unit + integration + CLI tests green
- AB CIP driver shipped + tests green + live-boot 5/5
- AB Legacy driver shipped + tests green + live-boot 5/5
- S7 driver shipped + tests green + live-boot 5/5
- TwinCAT driver shipped + tests green + features validated against the TCBSD VM virtual-PLC fixture
- FOCAS driver shipped (Tier-C split) + tests green (wire-live deferred)
- OPC UA Client driver shipped + tests green + live-boot 5/8
DriverFactoryRegistry+DriverInstanceBootstrappershipped- All seven factories registered in
Server/Program.cs - Per-driver test-client CLI suite shipped
- E2E test scripts shipped +
test-all.ps1aggregator green - Per-driver test-fixture docs present
docs/v2/driver-specs.mdunified capability spec presentscripts/e2e/README.mdstatus section reflects current live-boot matrix- Exit gate doc checked in (this file)
- TwinCAT validated against the TCBSD VM virtual-PLC fixture —
TWINCAT_TRUST_WIRE=1+ e2e script still gated by default to prevent false-pass against cold fixtures - FOCAS lab-rig follow-up filed + tracked (#222)
Why no compliance script
The Phases 6.1/6.2/6.3/6.4/7 pattern of a single phase-N-compliance.ps1
worked because each of those phases touched a narrow slice of server-side
runtime. A "phase-3-compliance.ps1" would have had to boot seven simulators,
configure seven DriverInstance rows, and run seven e2e scripts — which is
exactly what scripts/e2e/test-all.ps1 already does. The aggregate runner
- its README is the compliance artefact for this umbrella.