Windows services default to System32 as working directory, causing logs to land in the wrong location. Set Environment.CurrentDirectory to AppDomain.CurrentDomain.BaseDirectory before Serilog init. Also fix ZB root folder not appearing under Objects folder — BuildAddressSpace runs after CreateAddressSpace completes so the externalReferences dict is already consumed; use Server.NodeManager.AddReferences instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Preserve and replay subscription ref counts across address space rebuilds to prevent MXAccess subscription leaks
- Mark read timeouts and write failures as unsuccessful in PerformanceMetrics for accurate health reporting
- Add deferred MxAccess reconnect path when initial connection fails at startup
- Update code review document with verified completions and new findings
- Add covering tests for all fixes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
P1: Wire OPC UA monitored items to MXAccess subscriptions
- Override OnCreateMonitoredItemsComplete/OnDeleteMonitoredItemsComplete
in LmxNodeManager to trigger ref-counted SubscribeTag/UnsubscribeTag
- Clients subscribing to tags now start live MXAccess data pushes
P1: Write timeout now returns false instead of true
- Previously a missing OnWriteComplete callback was treated as success
- Now correctly reports failure so OPC UA clients see the error
P1: Auto-reconnect retries from Error state (not just Disconnected)
- Monitor loop now checks both Disconnected and Error states
- Prevents permanent outages after a single failed reconnect attempt
P2: Topological sort on hierarchy before building address space
- Parents guaranteed to appear before children regardless of input order
- Prevents misplaced nodes when SQL returns unsorted results
P3: Skip redundant first-poll rebuild on startup
- ChangeDetectionService accepts initial deploy time from OpcUaService
- First poll only triggers rebuild if deploy time is actually unknown
- Eliminates duplicate DB fetch and address space rebuild at startup
All 212 tests pass (205 unit + 7 integration).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full OPC UA server on .NET Framework 4.8 (x86) exposing AVEVA System
Platform Galaxy tags via MXAccess. Mirrors Galaxy object hierarchy as
OPC UA address space, translating contained-name browse paths to
tag-name runtime references.
Components implemented:
- Configuration: AppConfiguration with 4 sections, validator
- Domain: ConnectionState, Quality, Vtq, MxDataTypeMapper, error codes
- MxAccess: StaComThread, MxAccessClient (partial classes), MxProxyAdapter
using strongly-typed ArchestrA.MxAccess COM interop
- Galaxy Repository: SQL queries (hierarchy, attributes, change detection),
ChangeDetectionService with auto-rebuild on deploy
- OPC UA Server: LmxNodeManager (CustomNodeManager2), LmxOpcUaServer,
OpcUaServerHost with programmatic config, SecurityPolicy None
- Status Dashboard: HTTP server with HTML/JSON/health endpoints
- Integration: Full 14-step startup, graceful shutdown, component wiring
175 tests (174 unit + 1 integration), all passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>