feat(auditlog): extend ISiteStreamAuditClient with IngestCachedTelemetryAsync (#23 M3)

Add the second site→central RPC seam alongside the existing M2
IngestAuditEventsAsync. The Bundle D proto already lit up
IngestCachedTelemetry (CachedTelemetryBatch / IngestAck) so this commit
just plumbs the client-side abstraction:

* ISiteStreamAuditClient gains IngestCachedTelemetryAsync(batch, ct).
* NoOpSiteStreamAuditClient implements it returning an empty IngestAck
  (same shape as M2 — production gRPC client lands in M6).
* SyncCallEmissionEndToEndTests' DirectActorSiteStreamAuditClient stub
  throws NotSupportedException from the new method so a regression that
  accidentally routes a cached packet through the sync stub fails loudly.
* New NoOpSiteStreamAuditClientTests cover the null-guard + empty-ack
  contract for both batch shapes.

Bundle E task E1.
This commit is contained in:
Joseph Doherty
2026-05-20 14:39:24 -04:00
parent 0a97fff906
commit 73719ee066
4 changed files with 101 additions and 0 deletions
@@ -38,4 +38,16 @@ public sealed class NoOpSiteStreamAuditClient : ISiteStreamAuditClient
// Pending until M6's real client (or a Bundle H test stub) takes over.
return Task.FromResult(EmptyAck);
}
/// <inheritdoc/>
public Task<IngestAck> IngestCachedTelemetryAsync(CachedTelemetryBatch batch, CancellationToken ct)
{
ArgumentNullException.ThrowIfNull(batch);
// Empty ack — same rationale as IngestAuditEventsAsync. The M3
// CachedCallTelemetryForwarder still writes the audit + tracking rows to
// the site SQLite stores authoritatively; central-side state only
// materialises once M6's real gRPC client (or a Bundle G test stub) is
// wired in.
return Task.FromResult(EmptyAck);
}
}