diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Protocol/AlarmCapableProtocols.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Protocol/AlarmCapableProtocols.cs
index e7bfc151..f837f6d3 100644
--- a/src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Protocol/AlarmCapableProtocols.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Protocol/AlarmCapableProtocols.cs
@@ -6,8 +6,9 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Protocol;
/// mirror native alarms).
///
/// The set MUST stay in sync with the protocols registered against an
-/// alarm-subscribable adapter in the DCL DataConnectionFactory: today the
-/// "OpcUa" adapter (OpcUaDataConnection) and the "MxGateway" adapter
+/// alarm-subscribable adapter in
+/// DataConnectionLayer/DataConnectionFactory.cs: today the "OpcUa" adapter
+/// (OpcUaDataConnection) and the "MxGateway" adapter
/// (MxGatewayDataConnection) both implement
/// . The runtime decision is made in
/// DataConnectionActor via _adapter is IAlarmSubscribableConnection;
@@ -21,7 +22,9 @@ public static class AlarmCapableProtocols
///
/// Determines whether a data connection's protocol string resolves to an
/// alarm-capable adapter (one implementing ).
- /// Case-insensitive; null/blank is not alarm-capable.
+ /// Case-insensitive to match DataConnectionFactory's own
+ /// OrdinalIgnoreCase protocol-key lookup; null/blank is not
+ /// alarm-capable.
///
/// The data connection protocol string (e.g. "OpcUa").
/// true when the protocol's adapter can subscribe native alarms; otherwise false.
diff --git a/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/FlatteningPipeline.cs b/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/FlatteningPipeline.cs
index 39ccbf68..df78fe6c 100644
--- a/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/FlatteningPipeline.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/FlatteningPipeline.cs
@@ -114,8 +114,14 @@ public class FlatteningPipeline : IFlatteningPipeline
// Compute the alarm-capable connection-name set so the semantic validator
// can gate native-alarm-source bindings. "Alarm-capable" matches the DCL
- // runtime decision (DataConnectionActor: _adapter is IAlarmSubscribableConnection),
- // mapped from the protocol string via the shared AlarmCapableProtocols helper.
+ // runtime decision (DataConnectionActor: _adapter is IAlarmSubscribableConnection);
+ // here we filter connections by alarm-capable protocol, then collect their names.
+ //
+ // StringComparer.Ordinal is intentional: connection names are stored and
+ // matched as authored throughout the pipeline (all other name-keyed
+ // dictionaries in FlatteningService and SemanticValidator use the same
+ // case-sensitive semantics). OrdinalIgnoreCase would be inconsistent with
+ // the rest of the binding-resolution path.
var alarmCapableConnectionNames = dataConnections.Values
.Where(c => AlarmCapableProtocols.IsAlarmCapable(c.Protocol))
.Select(c => c.Name)
diff --git a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineNativeAlarmCapabilityTests.cs b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineNativeAlarmCapabilityTests.cs
index b0d6a4de..a49f35c3 100644
--- a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineNativeAlarmCapabilityTests.cs
+++ b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineNativeAlarmCapabilityTests.cs
@@ -83,6 +83,12 @@ public class FlatteningPipelineNativeAlarmCapabilityTests
[Theory]
[InlineData("OpcUa")]
[InlineData("MxGateway")]
+ // Case variants: IsAlarmCapable uses OrdinalIgnoreCase, matching DataConnectionFactory's
+ // own OrdinalIgnoreCase protocol-key lookup; lock the contract with non-canonical casing.
+ [InlineData("OPCUA")]
+ [InlineData("opcua")]
+ [InlineData("mxgateway")]
+ [InlineData("MXGATEWAY")]
public async Task FlattenAndValidate_NativeAlarmSourceOnAlarmCapableConnection_NoCapabilityError(string protocol)
{
Arrange(connectionName: "Boiler", connectionProtocol: protocol, boundConnectionName: "Boiler");