diff --git a/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/DiffService.cs b/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/DiffService.cs
index e32d1bbc..532e63ef 100644
--- a/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/DiffService.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/DiffService.cs
@@ -142,6 +142,7 @@ public class DiffService
a.Description == b.Description &&
a.PriorityLevel == b.PriorityLevel &&
a.IsLocked == b.IsLocked &&
+ a.IsMesReportable == b.IsMesReportable &&
a.TriggerType == b.TriggerType &&
a.TriggerConfiguration == b.TriggerConfiguration &&
a.OnTriggerScriptCanonicalName == b.OnTriggerScriptCanonicalName;
diff --git a/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/RevisionHashService.cs b/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/RevisionHashService.cs
index 9c8ad5f1..f240e3be 100644
--- a/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/RevisionHashService.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/RevisionHashService.cs
@@ -78,6 +78,8 @@ public class RevisionHashService
Description = a.Description,
PriorityLevel = a.PriorityLevel,
IsLocked = a.IsLocked,
+ // true-only (null when false) so existing revision hashes are unchanged.
+ IsMesReportable = a.IsMesReportable ? true : null,
TriggerType = a.TriggerType,
TriggerConfiguration = a.TriggerConfiguration,
OnTriggerScriptCanonicalName = a.OnTriggerScriptCanonicalName
@@ -242,6 +244,11 @@ public class RevisionHashService
///
public bool IsLocked { get; init; }
///
+ /// MES-reportable flag; null when false (the serializer drops nulls), so
+ /// pre-existing configurations hash identically.
+ ///
+ public bool? IsMesReportable { get; init; }
+ ///
/// The canonical name of the script triggered by this alarm.
///
public string? OnTriggerScriptCanonicalName { get; init; }
diff --git a/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/DiffServiceTests.cs b/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/DiffServiceTests.cs
index 9c9b516f..83cdf7b4 100644
--- a/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/DiffServiceTests.cs
+++ b/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/DiffServiceTests.cs
@@ -230,6 +230,28 @@ public class DiffServiceTests
Assert.Equal(DiffChangeType.Changed, diff.AlarmChanges[0].ChangeType);
}
+ /// Gitea #102: flipping a computed alarm's MES-reportable flag is a diff.
+ [Fact]
+ public void ComputeDiff_AlarmIsMesReportableChange_DetectedAsChanged()
+ {
+ var oldConfig = new FlattenedConfiguration
+ {
+ InstanceUniqueName = "Instance1",
+ Alarms = [new ResolvedAlarm { CanonicalName = "HighTemp", TriggerType = "RangeViolation" }]
+ };
+ var newConfig = new FlattenedConfiguration
+ {
+ InstanceUniqueName = "Instance1",
+ Alarms = [new ResolvedAlarm { CanonicalName = "HighTemp", TriggerType = "RangeViolation", IsMesReportable = true }]
+ };
+
+ var diff = _sut.ComputeDiff(oldConfig, newConfig);
+
+ Assert.True(diff.HasChanges);
+ Assert.Single(diff.AlarmChanges);
+ Assert.Equal(DiffChangeType.Changed, diff.AlarmChanges[0].ChangeType);
+ }
+
/// Verifies that a native alarm source reference change is detected as changed.
[Fact]
public void ComputeDiff_NativeAlarmSourceReferenceChange_DetectedAsChanged()
diff --git a/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/RevisionHashServiceTests.cs b/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/RevisionHashServiceTests.cs
index 5d535be5..e2d13948 100644
--- a/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/RevisionHashServiceTests.cs
+++ b/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/RevisionHashServiceTests.cs
@@ -191,6 +191,24 @@ public class RevisionHashServiceTests
Assert.NotEqual(_sut.ComputeHash(configBefore), _sut.ComputeHash(configAfter));
}
+ /// Gitea #102: the computed alarm's MES-reportable flag participates in the hash; false hashes as before the field existed.
+ [Fact]
+ public void ComputeHash_AlarmIsMesReportableChange_ChangesHash()
+ {
+ var baseAlarm = new ResolvedAlarm { CanonicalName = "HighTemp", TriggerType = "RangeViolation" };
+ var configFalse = new FlattenedConfiguration
+ {
+ InstanceUniqueName = "Instance1", TemplateId = 1, SiteId = 1,
+ Alarms = [baseAlarm]
+ };
+ var configTrue = configFalse with { Alarms = [baseAlarm with { IsMesReportable = true }] };
+
+ Assert.NotEqual(_sut.ComputeHash(configFalse), _sut.ComputeHash(configTrue));
+ // false is omitted from the canonical JSON, so adding the field cannot invalidate stored hashes.
+ Assert.Equal(_sut.ComputeHash(configFalse),
+ _sut.ComputeHash(configFalse with { Alarms = [baseAlarm with { IsMesReportable = false }] }));
+ }
+
/// Verifies that editing a connection endpoint changes the hash.
[Fact]
public void ComputeHash_ConnectionEndpointEdit_ChangesHash()