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.
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:
- GUID identity. The snapshot diff in
ComputeTransitionskeys on the alarm record'sGUID. If wnwrap mints a fresh GUID when an alarm changes state, a singleUNACK_ALM → ACK_ALMtransition reads as one alarm disappearing and a different one appearing — a spurious clear plus a spurious raise on every acknowledge. ALARM_RECORDS/@COUNTsemantics.IsTruncatedFetchtreats a reply holding exactlymaxAlmCntrecords as truncated, becauseGetXmlCurrentAlarms2exposes no explicit "more available" flag. If the reply'sCOUNTattribute carries the total active count rather than the records-in-reply count, truncation detection can become exact instead of conservative, and the bounded stalenessApplySnapshotUpdateaccepts 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, andwnwrapServerExare all running.TestArea(area ofTestMachine_001…_003) and the objects themselves are deployed (deployed_versionnon-null in theZBGalaxy Repository) and on scan — the probe's advisedScanStatesubtags 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), andSetXmlAlarmQueryall return 0, andGetXmlCurrentAlarms2returns 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 throughoutAlarmClientDiscovery.md). It writes from inside the engine, so the attribute's security classification does not apply. - Drive the write through
AuthenticateUser+WriteSecuredwith a Galaxy account permitted on that classification. The worker already implements both verbs; the probe used plainWrite, 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.