diff --git a/archreview/plans/R2-10-resilience-observability-plan.md.tasks.json b/archreview/plans/R2-10-resilience-observability-plan.md.tasks.json
index 1053d3e8..a63899c7 100644
--- a/archreview/plans/R2-10-resilience-observability-plan.md.tasks.json
+++ b/archreview/plans/R2-10-resilience-observability-plan.md.tasks.json
@@ -9,7 +9,7 @@
{ "id": "T5", "subject": "Host: DriverResilienceStatusPublisherService (BuildMessages mapping + 5s DPS timer shell; TDD mapping in Host.IntegrationTests)", "status": "completed", "blockedBy": ["T1", "T4"] },
{ "id": "T6", "subject": "Host DI: register the publisher in AddOtOpcUaDriverFactories + ResilienceStatusReaderRegistrationTests wiring guard (tracker HAS a production reader)", "status": "completed", "blockedBy": ["T5"] },
{ "id": "T7", "subject": "AdminUI: IDriverResilienceStatusStore + InMemory impl + AddOtOpcUaDriverStatusServices registration (TDD mirroring DriverStatusSnapshotStoreTests)", "status": "completed", "blockedBy": ["T4"] },
- { "id": "T8", "subject": "AdminUI: DriverResilienceStatusBridge DPS actor + spawn in WithOtOpcUaSignalRBridges", "status": "pending", "blockedBy": ["T7"] },
+ { "id": "T8", "subject": "AdminUI: DriverResilienceStatusBridge DPS actor + spawn in WithOtOpcUaSignalRBridges", "status": "completed", "blockedBy": ["T7"] },
{ "id": "T9", "subject": "AdminUI: resilience chip section in DriverStatusPanel.razor (in-process store read; no bUnit — verified by T10)", "status": "pending", "blockedBy": ["T7"] },
{ "id": "T10", "subject": "Live-/run gate on docker-dev: rebuild BOTH centrals, S7 dead-endpoint breaker-open, both-replica chips, recovery clear, staleness dim", "status": "pending", "blockedBy": ["T6", "T8", "T9"] },
{ "id": "T11", "subject": "Docs + review ledger: mark 03/U10 + 04/U-5 remediated; update STATUS.md + FOLLOWUP-10", "status": "pending", "blockedBy": ["T10"] }
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/DriverResilienceStatusBridge.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/DriverResilienceStatusBridge.cs
new file mode 100644
index 00000000..8b488327
--- /dev/null
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/DriverResilienceStatusBridge.cs
@@ -0,0 +1,39 @@
+using Akka.Actor;
+using Akka.Cluster.Tools.PublishSubscribe;
+using ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers;
+
+namespace ZB.MOM.WW.OtOpcUa.AdminUI.Hubs;
+
+///
+/// Akka actor that subscribes to the driver-resilience-status DistributedPubSub topic and
+/// upserts every snapshot into the in-process
+/// . The driver status panel's resilience section reads
+/// that store directly (per the house ban on server-side self-targeted SignalR connections), so —
+/// unlike — there is no SignalR hub here; resilience has no
+/// browser-JS consumer. Spawned per admin-role node by WithOtOpcUaSignalRBridges.
+///
+public sealed class DriverResilienceStatusBridge : ReceiveActor
+{
+ public const string TopicName = DriverResilienceStatusChanged.TopicName;
+
+ private readonly IDriverResilienceStatusStore _store;
+
+ /// Creates actor props for a .
+ /// Resilience status store updated on every forwarded snapshot.
+ /// An Akka.NET instance for spawning the bridge actor.
+ public static Props Props(IDriverResilienceStatusStore store) =>
+ Akka.Actor.Props.Create(() => new DriverResilienceStatusBridge(store));
+
+ /// Initializes a new instance of .
+ /// Resilience status store updated on every forwarded snapshot.
+ public DriverResilienceStatusBridge(IDriverResilienceStatusStore store)
+ {
+ _store = store;
+ Receive(msg => _store.Upsert(msg));
+ Receive(_ => { /* DPS confirmation */ });
+ }
+
+ ///
+ protected override void PreStart() =>
+ DistributedPubSub.Get(Context.System).Mediator.Tell(new Subscribe(TopicName, Self));
+}
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/HubServiceCollectionExtensions.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/HubServiceCollectionExtensions.cs
index b77d7048..f3675564 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/HubServiceCollectionExtensions.cs
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/HubServiceCollectionExtensions.cs
@@ -11,6 +11,7 @@ public static class HubServiceCollectionExtensions
public const string AlertSignalRBridgeName = "alert-signalr-bridge";
public const string ScriptLogSignalRBridgeName = "script-log-signalr-bridge";
public const string DriverStatusSignalRBridgeName = "driver-status-signalr-bridge";
+ public const string DriverResilienceStatusBridgeName = "driver-resilience-status-bridge";
///
/// Registers the in-process live-push services the AdminUI's Blazor Server panels read
@@ -71,6 +72,12 @@ public static class HubServiceCollectionExtensions
var driverStatusStore = resolver.GetService();
var driverStatusBridge = system.ActorOf(DriverStatusSignalRBridge.Props(driverStatusHub, driverStatusStore), DriverStatusSignalRBridgeName);
registry.Register(driverStatusBridge);
+
+ // Resilience-status bridge: DPS topic -> in-process store (no SignalR hub — the panel reads
+ // the store directly, and resilience has no browser-JS consumer).
+ var resilienceStore = resolver.GetService();
+ var resilienceBridge = system.ActorOf(DriverResilienceStatusBridge.Props(resilienceStore), DriverResilienceStatusBridgeName);
+ registry.Register(resilienceBridge);
});
return builder;
}
@@ -81,3 +88,4 @@ public sealed class FleetStatusSignalRBridgeKey { }
public sealed class AlertSignalRBridgeKey { }
public sealed class ScriptLogSignalRBridgeKey { }
public sealed class DriverStatusSignalRBridgeKey { }
+public sealed class DriverResilienceStatusBridgeKey { }