alarms: compose subtag reference from object's real Galaxy area for exact alarmmgr parity

This commit is contained in:
Joseph Doherty
2026-06-14 02:12:11 -04:00
parent 64db828d71
commit 5b31e99ab6
8 changed files with 138 additions and 39 deletions
@@ -13,7 +13,11 @@ namespace ZB.MOM.WW.MxGateway.Server.Alarms;
// NOTE: The exact subtag names and the canonical AlarmFullReference shape
// ("Galaxy!{area}.{reference}") are validated against a live Galaxy in the
// Task 17 live smoke test. The config Subtags block exists precisely so these
// names are not hard-coded here.
// names are not hard-coded here. The {area} is the alarm object's REAL Galaxy
// area discovered via gobject.area_gobject_id (the alarm group the native
// alarmmgr emits), giving exact reference parity with wnwrap. The configured
// Discovery.Area/DefaultArea is only the fallback for explicit IncludeAttributes
// entries, which carry no discovered area.
public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
{
private const string ProviderLiteral = "Galaxy";
@@ -43,9 +47,16 @@ public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
AlarmDiscoveryOptions discovery = options.Fallback.Discovery;
// Config fallback area used only for explicit IncludeAttributes entries (which
// carry no discovered area): discovery area, else the default area (may be empty).
string configFallbackArea = string.IsNullOrEmpty(discovery.Area) ? options.DefaultArea : discovery.Area;
// 1. Build the ordered, de-duplicated attribute reference set.
// Each entry carries the reference plus the source-object reference.
List<(string Reference, string SourceObject)> ordered = [];
// Each entry carries the reference, the source-object reference, and the
// per-entry area used to compose the canonical reference. GR rows contribute
// the object's real Galaxy area; config includes contribute the config
// fallback area (Discovery.Area else DefaultArea).
List<(string Reference, string SourceObject, string Area)> ordered = [];
HashSet<string> seen = new(StringComparer.OrdinalIgnoreCase);
if (discovery.UseGalaxyRepository)
@@ -73,7 +84,7 @@ public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
continue;
}
ordered.Add((row.FullTagReference, row.SourceObjectReference));
ordered.Add((row.FullTagReference, row.SourceObjectReference, row.Area));
}
}
@@ -84,7 +95,7 @@ public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
continue;
}
ordered.Add((include, DeriveSourceObject(include)));
ordered.Add((include, DeriveSourceObject(include), configFallbackArea));
}
// Remove excluded references (case-insensitive), but only when GR discovery
@@ -112,12 +123,11 @@ public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
string priority = options.Fallback.Subtags.Priority;
string ackComment = options.Fallback.Subtags.AckComment;
// 3. Resolve the area: discovery area, else the default area (may be empty).
string area = string.IsNullOrEmpty(discovery.Area) ? options.DefaultArea : discovery.Area;
// 4. Compose one target per reference.
// 3. Compose one target per reference, using the PER-ENTRY area: the GR row's
// real Galaxy area (matching the alarmmgr group), or the config fallback for
// explicit includes.
List<AlarmSubtagTarget> targets = new(ordered.Count);
foreach ((string reference, string sourceObject) in ordered)
foreach ((string reference, string sourceObject, string area) in ordered)
{
targets.Add(new AlarmSubtagTarget
{
@@ -130,7 +140,7 @@ public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
});
}
// 5. Report the resolved count; warn when subtag mode was expected to cover
// 4. Report the resolved count; warn when subtag mode was expected to cover
// something (GR enabled, or explicit includes were configured) but resolved
// to nothing. Only emit the Debug line when there is at least one target,
// to avoid a confusing "0 target(s)" noise line.