# 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 ``` 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.