diff --git a/src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SitePairChannelProvider.cs b/src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SitePairChannelProvider.cs index b03dfd81..d22f94f0 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SitePairChannelProvider.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SitePairChannelProvider.cs @@ -589,8 +589,14 @@ public sealed class SitePairChannelProvider : IDisposable return GrpcChannel.ForAddress(endpoint, channelOptions); } - /// Sentinel instance name the readiness probe queries; never a real instance. - internal const string ReadinessProbeInstance = "__scadabridge-failback-probe__"; + /// + /// Sentinel instance name the readiness probe queries. The leading $ makes it an + /// illegal Akka actor name, which ActorNameRules rejects for every real instance, so it + /// can never collide with one. The site-side DeploymentStateQuery path (dispatcher → + /// DeploymentManagerActor → a parameterised SQLite lookup) never validates or materialises + /// the name, so the probe simply reads "not deployed". + /// + internal const string ReadinessProbeInstance = "$scadabridge-failback-probe"; /// /// Production failback probe (review 2026-10-21 03/P-2): a real, read-only diff --git a/tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/Grpc/SitePairChannelProviderFailbackTests.cs b/tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/Grpc/SitePairChannelProviderFailbackTests.cs index 824c0504..7fef788c 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/Grpc/SitePairChannelProviderFailbackTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/Grpc/SitePairChannelProviderFailbackTests.cs @@ -150,6 +150,14 @@ public class SitePairChannelProviderFailbackTests Assert.Contains(SitePairChannelProvider.ReadinessProbeInstance, handler.LastRequestBody); } + /// Verifies that the probe's sentinel instance name can never be a real instance (it is not a legal actor name). + [Fact] + public void ReadinessProbeSentinel_IsNotALegalInstanceName() + { + Assert.False(ZB.MOM.WW.ScadaBridge.Commons.Validation.ActorNameRules.IsValid( + SitePairChannelProvider.ReadinessProbeInstance)); + } + /// /// Minimal in-memory gRPC server stand-in: a trailers-only Unavailable (+ the not-dispatched /// trailer) while not ready, or a framed with OK status when ready.