diff --git a/src/MxGateway.Worker/MxAccess/MxAccessAlarmEventSink.cs b/src/MxGateway.Worker/MxAccess/MxAccessAlarmEventSink.cs index cb5f181..ebf0f27 100644 --- a/src/MxGateway.Worker/MxAccess/MxAccessAlarmEventSink.cs +++ b/src/MxGateway.Worker/MxAccess/MxAccessAlarmEventSink.cs @@ -4,33 +4,80 @@ using MxGateway.Contracts.Proto; namespace MxGateway.Worker.MxAccess; /// -/// PR A.2 — sink that registers against the MXAccess Toolkit's alarm event -/// source and forwards each alarm transition into the worker's event queue -/// as an . Sister to -/// , but for the alarm event family -/// instead of data-change. +/// PR A.2 sink intended to register against an MXAccess alarm event source +/// and forward each alarm transition into the worker's event queue as an +/// . The mapper bridge is fully +/// implemented + unit-tested via +/// ; the +/// path is intentionally a no-op pending the +/// architectural decision documented below. /// /// /// -/// The MXAccess Toolkit's alarm subscription API differs across major -/// AVEVA versions. The exact COM interface (today expected to be one of -/// IAlarmEventSink, IAlarmEventSubscription, or a method -/// on the existing LMXProxyServerClass like -/// OnAlarmEvent) is pinned during dev-rig validation against the -/// worker host's installed Toolkit version. Until that pin lands, the -/// path logs a clear "alarm subscription not yet -/// wired" warning and registers no COM hook — the worker continues to -/// function for data subscriptions, and the gateway's -/// path simply receives no -/// events. +/// 2026-04-30 dev-rig finding: the MXAccess COM +/// Toolkit installed at C:\Program Files (x86)\ArchestrA\Framework\Bin\ArchestrA.MXAccess.dll +/// does not expose any alarm event family. Reflection +/// enumeration of the assembly (which exports a single COM interop +/// module containing ILMXProxyServerEvents and +/// ILMXProxyServerEvents2) confirms the only available events +/// are OnDataChange, OnWriteComplete, +/// OperationComplete, and OnBufferedDataChange. There is +/// no OnAlarmTransition, no IAlarmEventSink, and no +/// Alarms collection on the COM server. /// /// -/// is fully -/// implemented and unit-testable — it builds the proto event from -/// decoded fields, so once the COM subscription resolves to a method -/// that produces those fields, the only edit needed here is to wire -/// the COM event-handler delegate to call -/// . +/// AVEVA's separate alarm-subscription managed assemblies +/// (aaAlarmManagedClient.dll under +/// InTouch\ViewAppFramework\Content\MA\, +/// ArchestrAAlarmsAndEvents.SDK.Common.dll under +/// Wonderware\Historian\x64\) are present on this box but are +/// x64-only; they cannot load into the worker process, +/// which is x86 because of the MXAccess COM bitness constraint that +/// the mxaccessgw architecture exists to isolate. Loading them +/// in a separate x64 helper process would add meaningful operational +/// complexity (a third process tier alongside worker + gateway) and is +/// not in the current architecture. +/// +/// +/// Two paths forward — operator decision needed before the +/// sink can be wired: +/// +/// +/// +/// +/// Stay on the value-driven sub-attribute path +/// (current production behaviour). The lmxopcua server's +/// AlarmConditionService already synthesizes Part 9 +/// transitions from the four MXAccess sub-attributes +/// (InAlarm, Acked, Priority, +/// Description) via the data-change subscription. +/// Operator-comment fidelity is the only regression vs. v1; if +/// acceptable, this row stays the production path and the +/// family stays +/// reserved-but-dormant on the wire. +/// +/// +/// +/// +/// Add an x64 alarm-helper sub-process alongside +/// the worker that loads aaAlarmManagedClient, +/// subscribes to alarms, and forwards transitions to the worker +/// over a small named-pipe IPC. Then this sink's +/// connects to that helper instead of to +/// the COM server, and routes each transition through +/// . Adds operational complexity +/// but recovers full v1 fidelity (operator user, comment, +/// original raise time, category). +/// +/// +/// +/// +/// Until that decision is made, this sink's is a +/// no-op. The worker continues to function for data subscriptions, and +/// the gateway's family +/// is reserved on the wire but never emitted. lmxopcua-side +/// AlarmConditionService keeps the sub-attribute synthesis +/// active and continues to surface alarms to OPC UA Part 9 clients. /// /// public sealed class MxAccessAlarmEventSink : IMxAccessEventSink