diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ScriptLogHubE2eTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ScriptLogHubE2eTests.cs
new file mode 100644
index 00000000..188975da
--- /dev/null
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ScriptLogHubE2eTests.cs
@@ -0,0 +1,117 @@
+using System.Collections.Concurrent;
+using Akka.Actor;
+using Akka.Cluster.Tools.PublishSubscribe;
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.Extensions.DependencyInjection;
+using Moq;
+using Shouldly;
+using Xunit;
+using ZB.MOM.WW.OtOpcUa.AdminUI.Hubs;
+using ZB.MOM.WW.OtOpcUa.Commons.Messages.Logging;
+
+namespace ZB.MOM.WW.OtOpcUa.Host.IntegrationTests;
+
+///
+/// E2E integration coverage for the ScriptLogSignalRBridge actor → in-process
+/// broadcaster → Blazor /script-log page pipeline (Layer 0 of the script-log /
+/// scripted-alarm runtime work).
+///
+/// Scope note: mirrors . The Blazor circuit
+/// itself can't be exercised from an integration test (it needs an HTTP listener, JWT auth, and
+/// a real WebSocket upgrade — covered by the manual runbook). This suite instead exercises the
+/// exact server-side delivery the page depends on: it spawns a
+/// in the harness actor system, publishes a
+/// to the script-logs DPS topic, and asserts that the entry
+/// reaches the singleton resolved from the SAME DI
+/// container the /script-log page injects from (plus the SignalR hub push). This is the
+/// link the existing (publisher → topic) and
+/// (broadcaster → subscriber) tests do not cover
+/// together: bridge subscription → broadcaster fan-out off the live topic.
+///
+[Trait("Category", "Integration")]
+public sealed class ScriptLogHubE2eTests
+{
+ private static CancellationToken Ct => TestContext.Current.CancellationToken;
+
+ ///
+ /// Verifies that a published to the script-logs DPS
+ /// topic is forwarded by to (a) the
+ /// singleton the Blazor page reads and (b) the mock
+ /// via a SendAsync on the expected method.
+ ///
+ [Fact]
+ public async Task ScriptLogBridge_ForwardsEntry_ToInProcessBroadcaster_FromDpsTopic()
+ {
+ await using var harness = await TwoNodeClusterHarness.StartAsync();
+
+ // The SAME singleton the Blazor /script-log page injects: AddAdminUI() →
+ // AddOtOpcUaDriverStatusServices() registers IInProcessBroadcaster<> as an open-generic
+ // singleton, so resolving the closed type here yields the page's instance.
+ var broadcaster = harness.NodeA.Services.GetRequiredService>();
+ var received = new ConcurrentQueue();
+ void Handler(ScriptLogEntry e) => received.Enqueue(e);
+ broadcaster.Received += Handler;
+
+ // Mock IHubContext: the bridge pushes to Clients.All in addition to the
+ // broadcaster (for any out-of-process SignalR client).
+ var hubCalls = new List<(string Method, object? Arg)>();
+ var mockClients = new Mock();
+ var mockClientProxy = new Mock();
+ mockClients.Setup(c => c.All).Returns(mockClientProxy.Object);
+ mockClientProxy
+ .Setup(p => p.SendCoreAsync(It.IsAny(), It.IsAny