Files
mxaccessgw/docs/AlarmProbeFindings.md
T
Joseph Doherty ce5d8ae7c2 docs(alarms): wnwrap live-probe findings — GUID identity, ALARM_RECORDS COUNT
Both questions stay open, and the reason is the finding: the dev rig's alarm
UDAs reject a plain MXAccess Write with SecurityError/detail=1008 from the
responding automation object, so no alarm instance can be created to follow
through an acknowledge and no population can be built to overflow a capped
fetch. The rig is otherwise live — objects deployed and on scan, wnwrap
subscribed, GetXmlCurrentAlarms2 returning well-formed XML — which is what
makes the blocker specific and the unblock (engine-side script, or
AuthenticateUser + WriteSecured, or reclassifying the UDAs) actionable.

Comment-only changes in WnWrapAlarmConsumer: scope the GUID-identity claim to
the leg live capture actually covers, and record that ALARM_RECORDS/@COUNT
exists as a candidate exact truncation signal but is deliberately not trusted
because its semantics under a capped reply are unverified. No behavior change.
2026-08-17 04:03:39 -04:00

6.4 KiB

Alarm Probe Findings

WnWrapAlarmConsumer rests on two assumptions that no unit test can settle, because both are properties of AVEVA's alarm provider rather than of our code:

  1. GUID identity. The snapshot diff in ComputeTransitions keys on the alarm record's GUID. If wnwrap mints a fresh GUID when an alarm changes state, a single UNACK_ALM → ACK_ALM transition reads as one alarm disappearing and a different one appearing — a spurious clear plus a spurious raise on every acknowledge.
  2. ALARM_RECORDS/@COUNT semantics. IsTruncatedFetch treats a reply holding exactly maxAlmCnt records as truncated, because GetXmlCurrentAlarms2 exposes no explicit "more available" flag. If the reply's COUNT attribute carries the total active count rather than the records-in-reply count, truncation detection can become exact instead of conservative, and the bounded staleness ApplySnapshotUpdate accepts goes away.

This document records what a live probe run against the dev rig (DESKTOP-6JL3KKO, 2026-08-17) could and could not establish, so the next attempt starts from the blocker rather than rediscovering it.

Outcome

Question Status
GUID stable across polls and ALM → RTN Answered — yes, by the 2026-05-01 capture in AlarmClientDiscovery.md
GUID stable across UNACK → ACK, and across clear-then-re-raise Open
COUNT = total active vs records-in-reply under a capped fetch Open

Both open questions are blocked by the same thing: the rig has no active alarm and cannot be driven into one over MXAccess, so there is no alarm instance whose GUID can be followed through an acknowledge and no population large enough to overflow a capped fetch.

Why The Rig Cannot Raise An Alarm

The rig is otherwise healthy, which is what makes the blocker specific rather than a general "nothing works":

  • aaEngine, alarmmgr, NmxSvc, and wnwrapServerEx are all running.
  • TestArea (area of TestMachine_001_003) and the objects themselves are deployed (deployed_version non-null in the ZB Galaxy Repository) and on scan — the probe's advised ScanState subtags report true, and every advised alarm attribute delivers an initial value, so the MXAccess read path is live.
  • The wnwrap consumer subscribes cleanly: InitializeConsumer, RegisterConsumer, Subscribe(\\DESKTOP-6JL3KKO\Galaxy!TestArea), and SetXmlAlarmQuery all return 0, and GetXmlCurrentAlarms2 returns well-formed XML on every poll.

What fails is the write that would set the alarm condition. Every Write to the alarm UDAs completes with a security failure:

WRITE-COMPLETE hLMX=1 hItem=1 statuses=[success=0 category=SecurityError detectedBy=RespondingAutomationObject detail=1008 text=]

The status comes back from the responding automation object, not from the proxy, so the request reaches the engine and the engine refuses it. The advised value confirms the refusal is total rather than transient: neither the alarm UDA nor its .InAlarm /.Acked subtags report any change after a write attempt, across six write attempts in one session (raise, clear, re-raise, cleanup). The attributes carry a security classification that a plain Write cannot satisfy.

The 2026-05-01 capture that answered the ALM → RTN leg did not hit this, because the alarm condition was driven from inside the engine by a System Platform script rather than from an external MXAccess client. That script is not running now, and the values sat idle for the whole probe session.

Unblocking

Any one of these makes both questions answerable, in rough order of cost:

  • Re-enable the System Platform script that flips TestMachine_001.TestAlarm001 (referenced throughout AlarmClientDiscovery.md). It writes from inside the engine, so the attribute's security classification does not apply.
  • Drive the write through AuthenticateUser + WriteSecured with a Galaxy account permitted on that classification. The worker already implements both verbs; the probe used plain Write, which is the wrong verb for a secured attribute.
  • Reclassify the test UDAs to free access in the IDE and redeploy TestMachine_001_003.

Three separate objects are wired to the same alarm UDA name, so once writes land, a maxAlmCnt of 1 or 2 forces truncation against three active alarms and answers the COUNT question in the same run.

Evidence

Snapshot payload, identical at every cap (1, 2, and 1024) and at every poll across the ~100-second session:

<?xml version="1.0"?><ALARM_RECORDS COUNT="0"></ALARM_RECORDS>

Two things follow from the empty case alone. COUNT is present on the root element in every reply, so the attribute exists as a candidate signal rather than something wnwrap omits. And COUNT agrees with the element count here — but trivially, since both are zero, which is exactly the case that cannot discriminate the two hypotheses.

The probe used for the run was a throwaway file in the windev CI clone (C:\build\mxaccessgw-ci), deleted afterwards; the clone is back to a clean tree at origin/main. Nothing in this repository changed to run it. The reusable, Skip-gated harness it was modelled on is src/ZB.MOM.WW.MxGateway.Worker.Tests/Probes/WnWrapConsumerProbeTests.cs.

Implications

Transition identity

ComputeTransitions keying on GUID is safe for the raise and clear legs, which is the evidence AlarmClientDiscovery.md already carries. The acknowledge leg — the one where a re-minted GUID would corrupt the feed, because an ack is the state change most likely to create a new record in a provider that models acknowledgement as a separate event — is still assumed rather than observed. Nothing here justifies changing the diff, but the assumption should not be described in code as established.

Truncation detection

IsTruncatedFetch stays as written. Tightening it to an exact test requires knowing that COUNT reports the total, and this run cannot show that. The conservative rule keeps its justification: at the cap, treating a complete fetch as truncated costs one poll of staleness, while treating a truncated fetch as complete broadcasts clears for every alarm past the cap.

The one substantive correction is to the phrasing rather than the logic. The reply is not featureless — it carries a COUNT attribute the parser currently ignores. Whether that attribute is a usable "more available" signal is unverified, not absent, and the comments in WnWrapAlarmConsumer now say so.