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
@@ -62,6 +62,10 @@ public class CentralControlEndToEndTests : IAsyncLifetime
NullLogger<CentralControlGrpcService>.Instance,
Options.Create(new CommunicationOptions()));
_service.SetReady(stub);
// The two ingest RPCs Ask the audit-ingest singleton DIRECTLY (no CentralCommunicationActor
// relay any more), so the service needs its own proxy handed over. Reusing the same stub
// keeps one actor answering both shapes.
_service.SetAuditIngestActor(stub);
var pskProvider = new MapPskProvider(new Dictionary<string, string>
{
@@ -174,7 +178,7 @@ public class CentralControlEndToEndTests : IAsyncLifetime
// ---- One RPC per shape: unary (above) + the ingest bridge ----
[Fact]
public async Task IngestAuditEvents_DecodesTheBatch_AsksTheActor_EncodesTheAck()
public async Task IngestAuditEvents_DecodesTheBatch_AsksTheIngestProxy_EncodesTheAck()
{
var client = Client(SiteAKey, SiteA);
@@ -185,12 +189,13 @@ public class CentralControlEndToEndTests : IAsyncLifetime
var ack = await client.IngestAuditEventsAsync(batch);
// The stub actor accepts one deterministic id per non-empty batch; its presence proves
// the full DTO→command→Ask→reply→ack bridge ran, gated call and all.
// the full DTO→command→Ask→reply→ack bridge ran straight to the ingest proxy, gated
// call and all.
Assert.Contains(AcceptedId.ToString(), ack.AcceptedEventIds);
}
[Fact]
public async Task IngestAuditEvents_EmptyBatch_ShortCircuits_WithoutAskingTheActor()
public async Task IngestAuditEvents_EmptyBatch_ShortCircuits_WithoutAskingTheIngestProxy()
{
// Even the empty-batch fast path is behind the gate — it still needs a valid key.
var client = Client(SiteAKey, SiteA);
@@ -238,9 +243,9 @@ public class CentralControlEndToEndTests : IAsyncLifetime
}
/// <summary>
/// Minimal stand-in for <c>CentralCommunicationActor</c>: answers the two RPC shapes this
/// test exercises. Replies straight to the Ask's temp sender, exactly as the real actor's
/// Forward/PipeTo paths do.
/// Minimal stand-in for both actors the service Asks — <c>CentralCommunicationActor</c> for
/// the unary control RPCs and the <c>audit-log-ingest</c> singleton for the ingest ones.
/// Replies straight to the Ask's temp sender, exactly as the real actors do.
/// </summary>
private sealed class StubCentralActor : ReceiveActor
{