feat(native-alarms): per-binding IsMesReportable on native alarm source bindings (ScadaBridge#59)

TemplateNativeAlarmSource.IsMesReportable + tri-state InstanceNativeAlarmSourceOverride
.IsMesReportableOverride flatten onto ResolvedNativeAlarmSource; NativeAlarmActor stamps every
mirrored condition and InstanceActor the quiet-binding placeholder, so ScriptAlarm,
Alarms.MesReportableAsync() and the #60 wire fields carry it. Additive to the 900-999 severity band.
Migration AddNativeAlarmSourceMesReportable. Management commands, CLI --mes-reportable, Central UI
(template dialog checkbox, instance override select), Transport DTOs/importer/diff and the revision
hash (true-only, so existing hashes are unchanged) carry it.

Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
Joseph Doherty
2026-11-09 15:09:54 -05:00
parent 69a2017000
commit f98369a786
38 changed files with 2579 additions and 43 deletions
@@ -192,7 +192,9 @@ public sealed record TemplateNativeAlarmSourceDto(
string? ConditionFilter,
bool IsLocked,
bool IsInherited,
bool LockedInDerived);
bool LockedInDerived,
// Additive trailing field: false on bundles written before it existed.
bool IsMesReportable = false);
public sealed record TemplateAttributeDto(
string Name,
@@ -407,7 +409,9 @@ public sealed record InstanceNativeAlarmSourceOverrideDto(
string SourceCanonicalName,
string? ConnectionNameOverride,
string? SourceReferenceOverride,
string? ConditionFilterOverride);
string? ConditionFilterOverride,
// Additive trailing field: null ("keep inherited") on bundles written before it existed.
bool? IsMesReportableOverride = null);
public sealed record InstanceConnectionBindingDto(
string AttributeName,
@@ -104,7 +104,8 @@ public sealed class EntitySerializer
ConditionFilter: n.ConditionFilter,
IsLocked: n.IsLocked,
IsInherited: n.IsInherited,
LockedInDerived: n.LockedInDerived)).ToList(),
LockedInDerived: n.LockedInDerived,
IsMesReportable: n.IsMesReportable)).ToList(),
};
}).ToList(),
SharedScripts: aggregate.SharedScripts.Select(s => new SharedScriptDto(
@@ -292,7 +293,8 @@ public sealed class EntitySerializer
SourceCanonicalName: o.SourceCanonicalName,
ConnectionNameOverride: o.ConnectionNameOverride,
SourceReferenceOverride: o.SourceReferenceOverride,
ConditionFilterOverride: o.ConditionFilterOverride)).ToList(),
ConditionFilterOverride: o.ConditionFilterOverride,
IsMesReportableOverride: o.IsMesReportableOverride)).ToList(),
// Connection bindings reference their DataConnection by NAME — the
// numeric DataConnectionId FK can't survive a cross-environment
// bundle, so the importer resolves ConnectionName→target FK at
@@ -386,6 +388,7 @@ public sealed class EntitySerializer
IsLocked = n.IsLocked,
IsInherited = n.IsInherited,
LockedInDerived = n.LockedInDerived,
IsMesReportable = n.IsMesReportable,
});
}
return t;
@@ -621,6 +624,7 @@ public sealed class EntitySerializer
ConnectionNameOverride = o.ConnectionNameOverride,
SourceReferenceOverride = o.SourceReferenceOverride,
ConditionFilterOverride = o.ConditionFilterOverride,
IsMesReportableOverride = o.IsMesReportableOverride,
});
}
foreach (var b in dto.ConnectionBindings)