worker: aaAlarmManagedClient discovery + reference (alarm-helper foundation) #115

Merged
dohertj2 merged 1 commits from track-alarm-helper-discovery into main 2026-04-30 22:20:09 -04:00
Owner

Summary

Discovers the surface of aaAlarmManagedClient.dll and stages the worker csproj reference so subsequent PRs can wire native MxAccess alarm subscription. Replaces the speculative "two paths forward" framing in MxAccessAlarmEventSink with the validated architecture.

Key findings

  1. aaAlarmManagedClient.dll is x86 + .NET Framework (mixed-mode C++/CLI; PE Machine = i386, NativeEntryPoint flag set). The "x64-only" framing in the prior follow-up was wrong — confused by the file path under Wonderware\Historian\x64\. The assembly is bitness- and runtime-compatible with the worker (net48 x86), so it loads in the existing worker process. No sub-process needed.

  2. AlarmClient is the public class. Its model mirrors MxAccess: RegisterConsumer takes a Windows hWnd and the AVEVA alarm service WM_APP-pokes that hwnd when alarms change. The worker's existing STA + WM_APP pump can drive both the data-change COM subscriber and the alarm-client consumer.

  3. AlarmAckByGUID(alarmGuid, ackComment, oprName, oprNode, oprDomain, oprFullName) — the native ack carries the operator's full identity atomically with the comment. Closes the v1 operator-comment fidelity gap completely.

What this PR does

  • Adds the aaAlarmManagedClient.dll reference to MxGateway.Worker.csproj. Worker still builds clean.
  • Adds AlarmClientDiscoveryTests as a Skip-gated reflection probe; flip the Skip parameter to dump the public type surface for reference. The output was captured into the MxAccessAlarmEventSink doc so it doesn't have to be re-run.
  • Replaces MxAccessAlarmEventSink's "two paths forward" doc with the actual wiring plan against AlarmClient.RegisterConsumer + Subscribe + AlarmAckByGUID.

Test plan

  • Worker builds clean (net48 x86) with the new reference
  • Worker.Tests builds clean with the discovery probe
  • Discovery probe produces the expected dump (verified once locally; Skip-gated to keep CI deterministic)

Follow-up PRs

Gated on STA + WM_APP integration testing on the dev rig:

  1. Wire RegisterConsumer + Subscribe at session-startup; route WM_APP messages through GetStatistics + GetAlarmExtendedRec into EnqueueTransition.
  2. Translate gateway-side AcknowledgeAlarm RPC to a worker command that calls AlarmAckByGUID with the OPC UA operator's identity; replaces the worker-pending diagnostic from PR A.3.
  3. Translate gateway-side QueryActiveAlarms to a worker command that walks GetStatistics's reported handles via GetAlarmExtendedRec.
## Summary Discovers the surface of `aaAlarmManagedClient.dll` and stages the worker csproj reference so subsequent PRs can wire native MxAccess alarm subscription. Replaces the speculative "two paths forward" framing in `MxAccessAlarmEventSink` with the validated architecture. ## Key findings 1. **`aaAlarmManagedClient.dll` is x86 + .NET Framework** (mixed-mode C++/CLI; PE Machine = i386, NativeEntryPoint flag set). The "x64-only" framing in the prior follow-up was wrong — confused by the file path under `Wonderware\Historian\x64\`. The assembly is bitness- and runtime-compatible with the worker (net48 x86), so it loads in the existing worker process. **No sub-process needed.** 2. **`AlarmClient` is the public class.** Its model mirrors MxAccess: `RegisterConsumer` takes a Windows `hWnd` and the AVEVA alarm service WM_APP-pokes that hwnd when alarms change. The worker's existing STA + WM_APP pump can drive both the data-change COM subscriber and the alarm-client consumer. 3. **`AlarmAckByGUID(alarmGuid, ackComment, oprName, oprNode, oprDomain, oprFullName)`** — the native ack carries the operator's full identity atomically with the comment. **Closes the v1 operator-comment fidelity gap completely.** ## What this PR does - Adds the `aaAlarmManagedClient.dll` reference to `MxGateway.Worker.csproj`. Worker still builds clean. - Adds `AlarmClientDiscoveryTests` as a Skip-gated reflection probe; flip the Skip parameter to dump the public type surface for reference. The output was captured into the `MxAccessAlarmEventSink` doc so it doesn't have to be re-run. - Replaces `MxAccessAlarmEventSink`'s "two paths forward" doc with the actual wiring plan against `AlarmClient.RegisterConsumer` + `Subscribe` + `AlarmAckByGUID`. ## Test plan - [x] Worker builds clean (net48 x86) with the new reference - [x] Worker.Tests builds clean with the discovery probe - [x] Discovery probe produces the expected dump (verified once locally; Skip-gated to keep CI deterministic) ## Follow-up PRs Gated on STA + WM_APP integration testing on the dev rig: 1. Wire `RegisterConsumer` + `Subscribe` at session-startup; route WM_APP messages through `GetStatistics` + `GetAlarmExtendedRec` into `EnqueueTransition`. 2. Translate gateway-side `AcknowledgeAlarm` RPC to a worker command that calls `AlarmAckByGUID` with the OPC UA operator's identity; replaces the worker-pending diagnostic from PR A.3. 3. Translate gateway-side `QueryActiveAlarms` to a worker command that walks `GetStatistics`'s reported handles via `GetAlarmExtendedRec`.
dohertj2 added 1 commit 2026-04-30 22:20:06 -04:00
Discovers the surface of aaAlarmManagedClient.dll and stages the worker
csproj reference so subsequent PRs can wire native MxAccess alarm
subscription. Replaces the speculative "operator decision needed
between path 1 and path 2" framing in MxAccessAlarmEventSink with the
validated architecture.

Key findings from the discovery probe:

1. aaAlarmManagedClient.dll is x86 + .NET Framework (mixed-mode
   C++/CLI; PE Machine = i386, NativeEntryPoint flag set). The
   "x64-only" framing in the prior follow-up was wrong — confused
   by the file path under Wonderware\Historian\x64\.
   The assembly is bitness- and runtime-compatible with the
   worker (net48 x86), so it loads in the existing process. No
   sub-process needed.

2. AlarmClient is the public class. Its model mirrors MxAccess:
   RegisterConsumer takes a Windows hWnd and the AVEVA alarm
   service WM_APP-pokes that hwnd when alarms change. The worker's
   existing STA + WM_APP pump can drive both the data-change COM
   subscriber and the alarm-client consumer.

3. AlarmAckByGUID(alarmGuid, ackComment, oprName, oprNode,
   oprDomain, oprFullName) — the native ack carries the operator's
   full identity atomically with the comment. Closes the v1
   operator-comment fidelity gap completely.

This PR:

- Adds the aaAlarmManagedClient.dll reference to MxGateway.Worker.
  csproj. Worker still builds clean.
- Adds AlarmClientDiscoveryTests as a Skip-gated reflection probe;
  flip the Skip parameter to dump the public type surface for
  reference. Captured the dump into MxAccessAlarmEventSink
  documentation so it doesn't have to be re-run.
- Replaces MxAccessAlarmEventSink's "two paths forward" doc with
  the actual wiring plan against AlarmClient's RegisterConsumer +
  Subscribe + AlarmAckByGUID surface.

Subsequent PRs (gated on STA + WM_APP integration testing on the
dev rig):

- Wire RegisterConsumer + Subscribe at session-startup; route
  WM_APP messages through GetStatistics + GetAlarmExtendedRec into
  EnqueueTransition.
- Translate gateway-side AcknowledgeAlarm RPC to a worker command
  that calls AlarmAckByGUID with the OPC UA operator's identity;
  replaces the worker-pending diagnostic from PR A.3.
- Translate gateway-side QueryActiveAlarms to a worker command
  that walks GetStatistics's reported handles via GetAlarmExtendedRec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit e7c2c546b5 into main 2026-04-30 22:20:09 -04:00
dohertj2 deleted branch track-alarm-helper-discovery 2026-04-30 22:20:09 -04:00
Sign in to join this conversation.