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
@@ -165,6 +165,36 @@ public class SchemaConfigurationTests : IDisposable
Assert.True((await _context.TemplateAlarms.SingleAsync(a => a.Id == alarm.Id)).IsMesReportable);
Assert.False((await _context.InstanceAlarmOverrides.SingleAsync(o => o.Id == ovr.Id)).IsMesReportableOverride);
}
// Gitea #59: per-binding flag on native alarm sources. Backed on SQL Server by the
// AddNativeAlarmSourceMesReportable migration; pinned here on the model/persist path.
/// <summary>Verifies that native alarm sources and their overrides persist the MES-reportable flags.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task NativeAlarmSource_And_Override_PersistMesReportableFlags()
{
var site = new Site("Site59", "S-059");
var template = new Template("MesNativeT1");
_context.Sites.Add(site);
_context.Templates.Add(template);
await _context.SaveChangesAsync();
var instance = new Instance("MesNativeInst1") { SiteId = site.Id, TemplateId = template.Id };
_context.Instances.Add(instance);
await _context.SaveChangesAsync();
var src = new TemplateNativeAlarmSource("Pressure")
{ TemplateId = template.Id, ConnectionName = "Opc", SourceReference = "ns=2;s=P", IsMesReportable = true };
var ovr = new InstanceNativeAlarmSourceOverride("Pressure")
{ InstanceId = instance.Id, IsMesReportableOverride = false };
_context.Add(src);
_context.Add(ovr);
await _context.SaveChangesAsync();
_context.ChangeTracker.Clear();
Assert.True((await _context.Set<TemplateNativeAlarmSource>().SingleAsync(a => a.Id == src.Id)).IsMesReportable);
Assert.False((await _context.Set<InstanceNativeAlarmSourceOverride>().SingleAsync(o => o.Id == ovr.Id)).IsMesReportableOverride);
}
}
public class SplitQueryBehaviourTests : IDisposable