Merge hw3-alarms (#656 atomic ActiveAcknowledged + re-statement flag for native alarms)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-09 00:14:47 -04:00
20 changed files with 1006 additions and 84 deletions
@@ -102,6 +102,14 @@ public sealed record AlarmAcknowledgeRequest(
/// <b>quality-only annotation</b> (<see cref="IsQualityOnly"/>): the host updates (via its Quality-only node path) the condition's
/// Quality without touching its Active/Acked state and publishes no <c>alerts</c> row for it.
/// </param>
/// <param name="IsRestatement">
/// Gitea #656 — true when the source is RE-STATING upstream's current state rather than reporting a transition it
/// watched happen: a reconnect snapshot entry (Galaxy) or the first event for a condition after a driver start or
/// deploy respawn (OpcUaClient). It governs <b>history only, never node state</b>: the host still projects the
/// state, but writes no <c>alerts</c> row when the re-statement changes nothing the condition shows (a Retrigger on
/// an Active+unacked condition with the same message and severity; a Clear on an already-inactive condition).
/// <c>false</c> (the default, every source that does not opt in) keeps every transition's row.
/// </param>
public sealed record AlarmEventArgs(
IAlarmSubscriptionHandle SubscriptionHandle,
string SourceNodeId,
@@ -115,7 +123,8 @@ public sealed record AlarmEventArgs(
string? AlarmCategory = null,
AlarmTransitionKind Kind = AlarmTransitionKind.Unspecified,
int? OpcUaSeverity = null,
uint? QualityStatusCode = null)
uint? QualityStatusCode = null,
bool IsRestatement = false)
{
/// <summary>
/// True when this event only re-annotates the condition's source-data quality — a
@@ -132,5 +141,8 @@ public enum AlarmSeverity { Low, Medium, High, Critical }
/// Kind of alarm state change carried by <see cref="AlarmEventArgs.Kind"/>, letting a
/// consumer derive OPC UA Part 9 active/ack state. Mirrors the driver-side
/// transition-kind enums (e.g. Galaxy's <c>GalaxyAlarmTransitionKind</c>).
/// <see cref="ActiveAcknowledged"/> (Gitea #656) means "the condition is active AND acknowledged", applied by the
/// host as ONE projection — never Raise-then-Acknowledge, which would show clients an Active+unacked intermediate.
/// Members are append-only: their numeric values must not move.
/// </summary>
public enum AlarmTransitionKind { Unspecified = 0, Raise, Acknowledge, Clear, Retrigger }
public enum AlarmTransitionKind { Unspecified = 0, Raise, Acknowledge, Clear, Retrigger, ActiveAcknowledged }