perf(comms+audit): close phase-2 residuals — direct ingest path, monotonic timeouts, synthetic probe, not-reporting set, cursor-exact audit pull

This commit is contained in:
Joseph Doherty
2026-08-14 21:38:23 -04:00
parent 4cd1441984
commit a5882753dd
38 changed files with 1254 additions and 443 deletions
@@ -59,12 +59,24 @@ public class SiteAuditPushFlowTests : TestKit
private sealed class BridgeCentralTransport : ICentralTransport
{
private readonly IActorRef _central;
public BridgeCentralTransport(IActorRef central) => _central = central;
private readonly IActorRef _auditIngest;
/// <param name="central">Stands in for the central control plane's non-audit RPCs.</param>
/// <param name="auditIngest">
/// The central audit-ingest singleton. The two ingest RPCs go straight here, mirroring
/// <c>CentralControlGrpcService</c>, which Asks the proxy directly rather than relaying
/// through <c>CentralCommunicationActor</c>.
/// </param>
public BridgeCentralTransport(IActorRef central, IActorRef auditIngest)
{
_central = central;
_auditIngest = auditIngest;
}
public void SubmitNotification(NotificationSubmit message, IActorRef replyTo) => _central.Tell(message, replyTo);
public void QueryNotificationStatus(NotificationStatusQuery message, IActorRef replyTo) => _central.Tell(message, replyTo);
public void IngestAuditEvents(IngestAuditEventsCommand message, IActorRef replyTo) => _central.Tell(message, replyTo);
public void IngestCachedTelemetry(IngestCachedTelemetryCommand message, IActorRef replyTo) => _central.Tell(message, replyTo);
public void IngestAuditEvents(IngestAuditEventsCommand message, IActorRef replyTo) => _auditIngest.Tell(message, replyTo);
public void IngestCachedTelemetry(IngestCachedTelemetryCommand message, IActorRef replyTo) => _auditIngest.Tell(message, replyTo);
public void ReconcileSite(ReconcileSiteRequest message, IActorRef replyTo) => _central.Tell(message, replyTo);
public void ReportSiteHealth(SiteHealthReport message, IActorRef replyTo) => _central.Tell(message, replyTo);
public void SendHeartbeat(HeartbeatMessage message, IActorRef self) => _central.Tell(message, self);
@@ -144,9 +156,11 @@ public class SiteAuditPushFlowTests : TestKit
centralRepo,
NullLogger<ZB.MOM.WW.ScadaBridge.AuditLog.Central.AuditLogIngestActor>.Instance)));
// Real CentralCommunicationActor. Its periodic site-address refresh
// resolves an ISiteRepository from this provider; an empty result keeps
// the refresh a clean no-op and never touches the audit-ingest path.
// Real CentralCommunicationActor. It is NOT on the audit path any more (the
// central-hosted CentralControlGrpcService Asks the ingest singleton directly), but the
// bridge transport still routes notifications/health/reconcile through it, so it is
// constructed exactly as production does. Its periodic site-address refresh resolves an
// ISiteRepository from this provider; an empty result keeps the refresh a clean no-op.
var siteRepo = Substitute.For<ISiteRepository>();
siteRepo.GetAllSitesAsync().Returns(Array.Empty<Site>());
var centralServices = new ServiceCollection();
@@ -155,9 +169,7 @@ public class SiteAuditPushFlowTests : TestKit
var centralCommActor = Sys.ActorOf(Props.Create(() => new CentralCommunicationActor(
centralProvider,
Substitute.For<ISiteCommandTransport>(),
TimeSpan.FromSeconds(5))));
centralCommActor.Tell(new RegisterAuditIngest(ingestActor));
Substitute.For<ISiteCommandTransport>())));
// ── Site side ─────────────────────────────────────────────────────
// Real SqliteAuditWriter on a file-backed SQLite db (the site hot-path
@@ -177,7 +189,7 @@ public class SiteAuditPushFlowTests : TestKit
CreateTestProbe().Ref, // deployment-manager proxy is unused here
null,
null,
new BridgeCentralTransport(centralCommActor))));
new BridgeCentralTransport(centralCommActor, ingestActor))));
// The production site audit push client — the unit under integration.
var auditClient = new SiteCommunicationAuditClient(