Phase 1 + Phase 2 A/B/C feature-complete #1
Closed
dohertj2
wants to merge 0 commits from
phase-1-configuration into v2
pull from: phase-1-configuration
merge into: dohertj2:v2
dohertj2:master
dohertj2:v2
dohertj2:abcip-pr4-iwritable
dohertj2:abcip-pr3-ireadable
dohertj2:abcip-pr2-scaffolding
dohertj2:abcip-pr1-pollgroupengine
dohertj2:phase-6-1-stream-e3-inflight-counter
dohertj2:phase-6-4-stream-b-staging-tables
dohertj2:phase-6-1-resilience-status-publisher
dohertj2:phase-6-1-stream-a-multihost-dispatch
dohertj2:phase-6-1-stream-a-resilience-config
dohertj2:phase-6-4-stream-d-identification
dohertj2:phase-6-1-stream-b4-hosted-service
dohertj2:v2-release-readiness-blocker3-closed
dohertj2:phase-6-3-stream-c-state-publisher
dohertj2:phase-6-3-stream-a-topology-loader
dohertj2:v2-release-readiness-blocker2-closed
dohertj2:phase-6-1-stream-d-wiring-followup
dohertj2:v2-release-readiness-blocker1-closed
dohertj2:phase-6-2-stream-c-dispatch-wiring-followup
dohertj2:v2-release-readiness-capstone
dohertj2:phase-6-4-exit-gate
dohertj2:phase-6-4-stream-ab-data-layer
dohertj2:phase-6-3-exit-gate
dohertj2:phase-6-3-stream-b-service-level
dohertj2:phase-6-2-exit-gate
dohertj2:phase-6-2-stream-d-validated-authoring
dohertj2:phase-6-2-stream-c-dispatch-wiring
dohertj2:phase-6-2-stream-b-permission-trie
dohertj2:phase-6-2-stream-a-ldap-role-mapping
dohertj2:phase-6-1-exit-gate
dohertj2:phase-6-1-stream-e-admin-hosts
dohertj2:phase-6-1-stream-d-litedb-sealed-cache
dohertj2:phase-6-1-stream-c-health-logging
dohertj2:phase-6-1-stream-b-stability
dohertj2:phase-6-1-stream-a-resilience
dohertj2:phase-6-reconcile
dohertj2:phase-6-plans-drafts
dohertj2:phase-3-pr76-opcua-client-history
dohertj2:phase-3-pr75-opcua-client-alarms
dohertj2:phase-3-pr74-opcua-client-session-reconnect
dohertj2:phase-3-pr73-opcua-client-browse-enrichment
dohertj2:phase-3-pr72-opcua-client-failover
dohertj2:phase-3-pr71-opcua-client-cert-auth
dohertj2:phase-3-pr70-opcua-client-security-policy
dohertj2:phase-3-pr69-opcua-client-subscribe-probe
dohertj2:phase-3-pr68-opcua-client-discovery
dohertj2:phase-3-pr67-opcua-client-read-write
dohertj2:phase-3-pr66-opcua-client-scaffold
dohertj2:phase-3-pr65-s7-discovery-subscribe-probe
dohertj2:phase-3-pr64-s7-read-write
dohertj2:phase-3-pr63-s7-address-parser
dohertj2:phase-3-pr62-s7-driver-scaffold
dohertj2:phase-2-pr61-scrub-v1-archive-residue
dohertj2:phase-3-pr60-mitsubishi-quirk-tests
dohertj2:phase-3-pr59-melsec-address-helper
dohertj2:phase-3-pr58-mitsubishi-sim-profile
dohertj2:phase-3-pr57-s7-quirk-tests
dohertj2:phase-3-pr56-s7-sim-profile
dohertj2:phase-3-pr55-mitsubishi-research-doc
dohertj2:phase-3-pr54-s7-research-doc
dohertj2:phase-3-pr53-dl205-reconnect
dohertj2:phase-3-pr52-dl205-exception-codes
dohertj2:phase-3-pr51-dl205-xinput
dohertj2:phase-3-pr50-dl205-coil-mapping
dohertj2:phase-3-pr49-dl205-fc-caps
dohertj2:phase-3-pr48-dl205-cdab-float
dohertj2:phase-3-pr47-dl205-vmemory
dohertj2:phase-3-pr46-dl205-bcd
dohertj2:phase-3-pr45-dl205-string-byte-order
dohertj2:phase-3-pr44-pymodbus-validation-fixes
dohertj2:phase-3-pr43-pymodbus-swap
dohertj2:phase-3-pr42-modbuspal-profiles
dohertj2:phase-3-pr41-dl205-quirks-doc
dohertj2:phase-3-pr40-livestack-write-subscribe
dohertj2:phase-3-pr39-elevated-shell-skip
dohertj2:phase-3-pr38-historyread-servicehandler
dohertj2:phase-3-pr37-live-stack-smoke
dohertj2:phase-3-pr36-aveva-prerequisites
dohertj2:phase-3-pr35-history-readtime-readevents
dohertj2:phase-3-pr34-host-status-publisher-page
dohertj2:phase-3-pr33-driverhoststatus-entity
dohertj2:phase-3-pr32-multi-driver-integration
dohertj2:phase-3-pr31-live-ldap-ad-compat
dohertj2:phase-3-pr30-modbus-integration-scaffold
dohertj2:phase-3-pr29-account-page
dohertj2:phase-3-pr28-cert-trust
dohertj2:phase-3-pr27-fleet-dashboard
dohertj2:phase-3-pr26-server-write-authz
dohertj2:phase-3-pr25-modbus-test-plan
dohertj2:phase-3-pr24-modbus-types
dohertj2:phase-3-pr23-modbus-probe
dohertj2:phase-3-pr22-modbus-subscribe
dohertj2:phase-3-pr21-modbus-driver
dohertj2:phase-3-pr20-lmx-followups
dohertj2:phase-3-pr19-ldap-security
dohertj2:phase-3-pr18-delete-v1
dohertj2:phase-3-pr17-server-startup
dohertj2:phase-3-pr16-opcua-server
dohertj2:phase-3-pr15-alarm-contract
dohertj2:phase-2-pr14-alarm-subsystem
dohertj2:phase-2-pr13-runtime-probe
dohertj2:phase-2-pr12-quality-mapper
dohertj2:phase-2-pr11-history-events
dohertj2:phase-2-pr10-history-attime
dohertj2:phase-2-pr9-alarms
dohertj2:phase-2-pr8-alarms-hoststatus
dohertj2:phase-2-pr7-history-processed
dohertj2:phase-2-pr6-monitor-findings
dohertj2:phase-2-pr5-historian
dohertj2:phase-2-pr4-findings
dohertj2:phase-2-stream-d
dohertj2:phase-0-rename
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "phase-1-configuration"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
PR 1 — Phase 1 + Phase 2 A/B/C → v2
Source:
phase-1-configuration(commits980ea51..7403b92, 11 commits)Target:
v2URL: https://gitea.dohertylan.com/dohertj2/lmxopcua/pulls/new/phase-1-configuration
Summary
(InitialSchema + 8 stored procs + AuthorizationGrants), Core + Server + full Admin UI
(Blazor Server with cluster CRUD, draft → diff → publish → rollback, equipment with
OPC 40010, UNS, namespaces, drivers, ACLs, reservations, audit), LDAP via GLAuth
(
localhost:3893), SignalR real-time fleet status + alerts.(Galaxy.Shared, netstandard2.0, MessagePack), Galaxy.Host with real Win32 STA pump,
ACL + caller-SID + per-process-secret IPC, Galaxy-specific MemoryWatchdog +
RecyclePolicy + PostMortemMmf + MxAccessHandle, three
IGalaxyBackendimplementations (Stub / DbBacked / MxAccess — real ArchestrA.MxAccess.dll
reference, x86, smoke-tested live against
LMXProxyServer), Galaxy.Proxy with all9 capability interfaces (
IDriver/ITagDiscovery/IReadable/IWritable/ISubscribable/IAlarmSource/IHistoryProvider/IRediscoverable/IHostConnectivityProbe) + supervisor (Backoff + CircuitBreaker +HeartbeatMonitor).
migration script, two-service Windows installer scripts, process-spawn cross-FX
parity test, Stream D removal procedure doc with both Option A (rewrite 494 v1
tests) and Option B (archive + new v2 E2E suite) spelled out step-by-step.
What's NOT in this PR
OtOpcUa.Hostdeletion (Stream D.1) — reserved for a follow-up PR afterOption B's E2E suite is green. The 494 v1 tests still pass against the unchanged
legacy Host.
removal-procedure doc describes.
Tests
964 pass / 1 pre-existing Phase 0 baseline failure, across 14 test projects:
Test plan for reviewers
dotnet build ZB.MOM.WW.OtOpcUa.slnxsucceeds with no warnings beyond theknown NuGetAuditSuppress + xUnit1051 warnings
dotnet test ZB.MOM.WW.OtOpcUa.slnxshows the same 964/1 resultGet-Service aaGR, aaBootstrapreports Running on the merger's boxdocker ps --filter name=otopcua-mssqlshows the SQL container Updotnet run --project src/ZB.MOM.WW.OtOpcUa.Admin); home pagerenders at http://localhost:5123/; LDAP sign-in with GLAuth
readonly/readonly123succeedspowershell -File scripts/migration/Migrate-AppSettings-To-DriverConfig.ps1 -DryRunproducesa well-formed DriverConfig JSON
are explicitly documented (
549cd36,a7126ba,7403b92are the mostrecent and most detailed)
Follow-up tracking
PR 2 (next session) will execute Stream D Option B — archive
OtOpcUa.TestsasOtOpcUa.Tests.v1Archive, build the newOtOpcUa.Driver.Galaxy.E2Etest project,delete legacy
OtOpcUa.Host, and run the parity-validation cycle. Seedocs/v2/implementation/stream-d-removal-procedure.md.otopcua-mssql-data:/var/opt/mssqlon the SQL Server container so DB files survive container restart anddocker rm; sqlcmd verification command using the newmssql-tools18path that the 2022 image ships with; EF Core CLI install for use starting in Phase 1 Stream B; bumped step count from 8 → 10. Also adds a Troubleshooting subsection covering the seven most common Windows install snags (WSL distro not auto-installed needs-d Ubuntu; Docker PATH not refreshed needs new shell or sign-in; docker-users group membership needs sign-out/in; WSL 2 kernel update needs manual install on legacy systems; SA password complexity rules; Linux vs Windows containers mode mismatch; Hyper-V coexistence with Docker requires WSL 2 backend not Hyper-V backend per decision #134). Step 1 acceptance criteria gain "docker ps shows otopcua-mssql Up" and explicit note that steps 4a/4b need admin elevation (no silent admin-free path exists on Windows). bf6741ba7fotopcua-mssqlat localhost:1433 with sa/OtOpcUaDev_2026! credentials and Docker named volumeotopcua-mssql-datamounted at /var/opt/mssql, dev Galaxy, GLAuth at C:\publish\glauth\ on ports 3893/3894, plus rows for not-yet-standing services like OPC Foundation reference server / FOCAS stub / Modbus simulator / ab_server / Snap7 / TwinCAT XAR VM with target ports to stand up later); Connection strings for appsettings.Development.json (copy-paste-ready, flagged never-commit); Container management quick reference (start/stop/logs/shell/query/nuclear-reset); Credential rotation note. fc0ce36308requiredmodifier — net48 lacks RequiredMemberAttribute and we'd need a polyfill shim like the existing IsExternalInit one; default-string init is simpler). System.Data.SqlClient 4.9.0 added (the same package the v1 Host uses; net48-compatible). Backend/DbBackedGalaxyBackend wraps the repository: DiscoverAsync builds a real DiscoverHierarchyResponse (groups attributes by gobject, resolves parent-by-tagname, maps category_id → human-readable template-category name mirroring v1 AlarmObjectFilter); ReadValuesAsync/WriteValuesAsync/HistoryReadAsync still surface "MXAccess code lift pending (Phase 2 Task B.1)" because runtime data values genuinely need the COM client; OpenSession/CloseSession/Subscribe/Unsubscribe/AlarmSubscribe/AlarmAck/Recycle return success without backend work (subscription ID is a synthetic counter for now). Live smoke tests (GalaxyRepositoryLiveSmokeTests) skip when localhost ZB is unreachable; when present they verify (1) TestConnection returns true, (2) GetHierarchy returns at least one deployed gobject with a non-empty TagName, (3) GetAttributes returns rows with FullTagReference matching the "tag.attribute" shape, (4) GetLastDeployTime returns a value, (5) DbBackedBackend.DiscoverAsync returns at least one gobject with attributes and a populated TemplateCategory. All 5 pass against the local Galaxy. Full solution 957 pass / 1 pre-existing Phase 0 baseline; the 494 v1 IntegrationTests + 6 v1 IntegrationTests-net48 tests still pass — legacy OtOpcUa.Host untouched. Remaining for the Phase 2 exit gate is the MXAccess COM client port itself (the v1 MxAccessClient partials + IMxProxy abstraction + StaPump-based Connect/Subscribe/Read/Write semantics) — Discover is now solved in DB-backed form, so the lift can focus exclusively on the runtime data-plane. 549cd36662git rm -r src/ZB.MOM.WW.OtOpcUa.Hostis destructive enough to need explicit operator authorization on a real PR review. scripts/migration/Migrate-AppSettings-To-DriverConfig.ps1 takes a v1 appsettings.json and emits the v2 DriverInstance.DriverConfig JSON blob (MxAccess/Database/Historian sections) ready to upsert into the central Configuration DB; null-leaf stripping; -DryRun mode; smoke-tested against the dev appsettings.json and produces the expected three-section ordered-dictionary output. scripts/install/Install-Services.ps1 registers the two v2 services with sc.exe — OtOpcUaGalaxyHost first (net48 x86 EXE with OTOPCUA_GALAXY_PIPE/OTOPCUA_ALLOWED_SID/OTOPCUA_GALAXY_SECRET/OTOPCUA_GALAXY_BACKEND/OTOPCUA_GALAXY_ZB_CONN/OTOPCUA_GALAXY_CLIENT_NAME env vars set via HKLM:\SYSTEM\CurrentControlSet\Services\OtOpcUaGalaxyHost\Environment registry), then OtOpcUa with depend=OtOpcUaGalaxyHost; resolves down-level account names to SID for the IPC ACL; generates a fresh 32-byte base64 shared secret per install if not supplied (kept out of registry — operators record offline for service rebinding scenarios); echoes start commands. scripts/install/Uninstall-Services.ps1 stops + removes both services. tests/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Proxy.Tests/HostSubprocessParityTests.cs is the production-shape parity test — Proxy (.NET 10) spawns the actual OtOpcUa.Driver.Galaxy.Host.exe (net48 x86) as a subprocess via Process.Start with backend=db env vars, connects via real named pipe, calls Discover, asserts at least one Galaxy gobject comes back. Skipped when running as Administrator (PipeAcl denies admins, same guard as other IPC integration tests), when the Host EXE hasn't been built, or when the ZB SQL endpoint is unreachable. This is the cross-FX integration that the parity suite genuinely needs — the previous IPC tests all ran in-process; this one validates the production deployment topology where Proxy and Host are separate processes communicating only over the named pipe. docs/v2/implementation/stream-d-removal-procedure.md is the next-session playbook: Option A (rewrite 494 v1 tests via a ProxyMxAccessClientAdapter that implements v1's IMxAccessClient by forwarding to GalaxyProxyDriver — Vtq↔DataValueSnapshot, Quality↔StatusCode, OnTagValueChanged↔OnDataChange mapping; 3-5 days, full coverage), Option B (rename OtOpcUa.Tests → OtOpcUa.Tests.v1Archive with [Trait("Category", "v1Archive")] for opt-in CI runs; new OtOpcUa.Driver.Galaxy.E2E test project with 10-20 representative tests via the HostSubprocessParityTests pattern; 1-2 days, accreted coverage); deletion checklist with eight pre-conditions, ten ordered steps, and a rollback path (git revert restores the legacy Host alongside the v2 stack — both topologies remain installable until the downstream consumer cutover). Full solution 964 pass / 1 pre-existing Phase 0 baseline; the 494 v1 IntegrationTests + 6 v1 IntegrationTests-net48 still pass because legacy OtOpcUa.Host stays untouched until an interactive session executes the procedure doc. 7403b92b72Closing � commits from this PR are already ancestors of v2 via PR #3 (pr4-findings was a linear superset). The code is merged; this PR is now redundant.
Pull request closed