From 429ccb8d9078d52b9ae03cf2c777fdc6528f42db Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 22 Oct 2026 08:30:38 -0400 Subject: [PATCH] fix(communication): failback probe sentinel uses an illegal actor name so it can never match a real instance (review 2026-10-21 03/P-2 follow-up) --- .../Grpc/SitePairChannelProvider.cs | 10 ++++++++-- .../Grpc/SitePairChannelProviderFailbackTests.cs | 8 ++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) 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.