Phase 2 PR 9 — thread IsAlarm discovery flag end-to-end #8

Merged
dohertj2 merged 1 commits from phase-2-pr9-alarms into v2 2026-04-18 06:59:26 -04:00
Owner

Summary

Thread IsAlarm discovery flag end-to-end: GalaxyRepository → IPC GalaxyAttributeInfoDriverAttributeInfo. The SQL has emitted is_alarm alongside is_historized since the PR 5 repository port (via the primitive_name='AlarmExtension' join), but the flag was silently dropped at the MapAttribute helper because the IPC message had no field to carry it.

Changes

  • GalaxyAttributeInfo.IsAlarm at [Key(6)] — appended after IsHistorized for wire-compat (MessagePack treats missing keys as default).
  • MxAccessGalaxyBackend.MapAttribute + DbBackedGalaxyBackend.MapAttribute — copy row.IsAlarm into the IPC shape.
  • DriverAttributeInfo record gains an IsAlarm positional parameter with default false — positional-record change with default, so non-Galaxy drivers don't need to flow a flag they don't produce.
  • GalaxyProxyDriver.DiscoverAsync passes attr.IsAlarm through.

Scope

Discovery-side foundation only. The full alarm subsystem — subscription to <tag>.InAlarm + .Priority + .DescAttrName + .Acked, state-machine tracking for Active / Unacknowledged / Confirmed / Inactive, OPC UA Part 9 event emission, write-to-AckMsg ack path — is PR 10+. That layer lives in the generic node-manager, so it's orthogonal to the IPC wiring this PR covers.

Tests

  • Round-trip: IsAlarm=true survives MessagePack serialize + deserialize.
  • Round-trip: IsAlarm=false default path.
  • Wire-compat: pre-PR9 payload (keys 0..5 only, no IsAlarm) deserializes cleanly with IsAlarm=false — so a rolling upgrade where the Proxy ships first can talk to an old Host during the window.

Test plan

  • dotnet build ZB.MOM.WW.OtOpcUa.slnx — 0 errors, 38 pre-existing warnings
  • dotnet test tests/.../Host.Tests/ --filter "Category=Unit" — 27/27 pass
  • Reviewer: on a machine with ArchestrA runtime + alarm-bearing gobjects deployed, run Discover and verify at least one returned GalaxyAttributeInfo has IsAlarm=true for a tag known to have an AlarmExtension primitive.

Merge order

Branches off phase-2-pr5-historian. Fast-forwards once PR 5 merges; otherwise rebase.


🤖 Generated with Claude Code

## Summary Thread `IsAlarm` discovery flag end-to-end: `GalaxyRepository` → IPC `GalaxyAttributeInfo` → `DriverAttributeInfo`. The SQL has emitted `is_alarm` alongside `is_historized` since the PR 5 repository port (via the `primitive_name='AlarmExtension'` join), but the flag was silently dropped at the `MapAttribute` helper because the IPC message had no field to carry it. ## Changes - `GalaxyAttributeInfo.IsAlarm` at `[Key(6)]` — appended after `IsHistorized` for wire-compat (MessagePack treats missing keys as default). - `MxAccessGalaxyBackend.MapAttribute` + `DbBackedGalaxyBackend.MapAttribute` — copy `row.IsAlarm` into the IPC shape. - `DriverAttributeInfo` record gains an `IsAlarm` positional parameter with default `false` — positional-record change with default, so non-Galaxy drivers don't need to flow a flag they don't produce. - `GalaxyProxyDriver.DiscoverAsync` passes `attr.IsAlarm` through. ## Scope Discovery-side foundation only. The full alarm subsystem — subscription to `<tag>.InAlarm` + `.Priority` + `.DescAttrName` + `.Acked`, state-machine tracking for Active / Unacknowledged / Confirmed / Inactive, OPC UA Part 9 event emission, write-to-AckMsg ack path — is PR 10+. That layer lives in the generic node-manager, so it's orthogonal to the IPC wiring this PR covers. ## Tests - Round-trip: `IsAlarm=true` survives MessagePack serialize + deserialize. - Round-trip: `IsAlarm=false` default path. - Wire-compat: pre-PR9 payload (keys 0..5 only, no `IsAlarm`) deserializes cleanly with `IsAlarm=false` — so a rolling upgrade where the Proxy ships first can talk to an old Host during the window. ## Test plan - [x] `dotnet build ZB.MOM.WW.OtOpcUa.slnx` — 0 errors, 38 pre-existing warnings - [x] `dotnet test tests/.../Host.Tests/ --filter "Category=Unit"` — 27/27 pass - [ ] Reviewer: on a machine with ArchestrA runtime + alarm-bearing gobjects deployed, run Discover and verify at least one returned `GalaxyAttributeInfo` has `IsAlarm=true` for a tag known to have an `AlarmExtension` primitive. ## Merge order Branches off `phase-2-pr5-historian`. Fast-forwards once PR 5 merges; otherwise rebase. --- 🤖 Generated with [Claude Code](https://claude.com/claude-code)
dohertj2 changed target branch from phase-2-pr5-historian to v2 2026-04-18 06:58:45 -04:00
dohertj2 added 1 commit 2026-04-18 06:58:45 -04:00
Phase 2 PR 9 — thread IsAlarm discovery flag end-to-end. GalaxyRepository.GetAttributesAsync has always emitted is_alarm alongside is_historized (CASE WHEN EXISTS with the primitive_definition join on primitive_name='AlarmExtension' per v1's Extended Attributes SQL lifted byte-for-byte into the PR 5 repository port), and GalaxyAttributeRow.IsAlarm has been populated since the port, but the flag was silently dropped at the MapAttribute helper in both MxAccessGalaxyBackend and DbBackedGalaxyBackend because GalaxyAttributeInfo on the IPC side had no field to carry it — every deployed alarm attribute arrived at the Proxy with no signal that it was alarm-bearing. This PR wires the flag through the three translation boundaries: GalaxyAttributeInfo gains [Key(6)] public bool IsAlarm { get; set; } at the end of the message to preserve wire-compat with pre-PR9 payloads that omit the key (MessagePack treats missing keys as default, so a newer Proxy talking to an older Host simply gets IsAlarm=false for every attribute); both backend MapAttribute helpers copy row.IsAlarm into the IPC shape; DriverAttributeInfo in Core.Abstractions gains a new IsAlarm parameter with default value false so the positional record signature change doesn't force every non-Galaxy driver call site to flow a flag they don't produce (the existing generic node-manager and future Modbus/etc. drivers keep compiling without modification); GalaxyProxyDriver.DiscoverAsync passes attr.IsAlarm through to the DriverAttributeInfo positional constructor. This is the discovery-side foundation — the generic node-manager can now enrich alarm-bearing variables with OPC UA AlarmConditionState during address-space build (the existing v1 LmxNodeManager pattern that subscribes to <tag>.InAlarm + .Priority + .DescAttrName + .Acked and merges them into a ConditionState) but this PR deliberately stops at discovery: the full alarm subsystem (subscription management for the 4 alarm-status attributes, state-machine tracking for Active/Unacknowledged/Confirmed/Inactive transitions, OPC UA Part 9 alarm event emission, and the write-to-AckMsg ack path) is a follow-up PR 10+ because it touches the node-manager's address-space build path — orthogonal to the IPC flow this PR covers. Tests — AlarmDiscoveryTests (new, 3 cases): GalaxyAttributeInfo_IsAlarm_round_trips_true_through_MessagePack serializes an IsAlarm=true instance and asserts the decoded flag is true + IsHistorized is true + AttributeName survives unchanged; GalaxyAttributeInfo_IsAlarm_round_trips_false_through_MessagePack covers the default path; Pre_PR9_payload_without_IsAlarm_key_deserializes_with_default_false is the wire-compat regression guard — serializes a stand-in PrePR9Shape class with only keys 0..5 (identical layout to the pre-PR9 GalaxyAttributeInfo) and asserts the newer GalaxyAttributeInfo deserializer produces IsAlarm=false without throwing, so a rolling upgrade where the Proxy ships first can talk to an old Host during the window before the Host upgrades without a MessagePack "missing key" exception. Full solution build: 0 errors, 38 warnings (existing). Galaxy.Host.Tests Unit suite: 27 pass / 0 fail (3 new alarm-discovery + 9 PR5 historian + 15 pre-existing). This PR branches off phase-2-pr5-historian because GalaxyProxyDriver's constructor signature + GalaxyHierarchyRow's IsAlarm init-only property are both ancestor state that the simpler branch bases (phase-2-pr4-findings, master) don't yet include. 70a5d06b37
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit d2ebb91cb1 into v2 2026-04-18 06:59:26 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#8