feat(notif): NotificationOutboxActor + CentralAuditWriter wired (#23 M4)

M4 Bundle B (B1) — add the central-only ICentralAuditWriter implementation
and inject it into NotificationOutboxActor so subsequent tasks (B2/B3) can
route attempt + terminal lifecycle events through the direct-write audit path.

- CentralAuditWriter: thin wrapper around IAuditLogRepository.InsertIfNotExistsAsync;
  scope-per-call (matches AuditLogIngestActor / NotificationOutboxActor pattern);
  stamps IngestedAtUtc; swallows all internal failures (alog.md §13).
- Registered as a singleton in AddAuditLog.
- NotificationOutboxActor ctor takes ICentralAuditWriter (validated non-null).
- Host wiring resolves the writer once from the root provider and passes it
  into the singleton's Props.Create call.
- Existing TestKit fixtures updated with a NoOpCentralAuditWriter helper so
  tests that don't exercise audit emission still compile and pass.
This commit is contained in:
Joseph Doherty
2026-05-20 16:04:01 -04:00
parent e4d902753b
commit b31747a632
13 changed files with 383 additions and 4 deletions

View File

@@ -0,0 +1,15 @@
using ScadaLink.Commons.Entities.Audit;
using ScadaLink.Commons.Interfaces.Services;
namespace ScadaLink.NotificationOutbox.Tests.TestSupport;
/// <summary>
/// Test-only no-op <see cref="ICentralAuditWriter"/>. Used by existing
/// NotificationOutboxActor TestKit fixtures whose tests pre-date the M4 Bundle B
/// audit-writer injection — they don't care about audit emission, they just
/// need a non-null collaborator so the actor's constructor succeeds.
/// </summary>
internal sealed class NoOpCentralAuditWriter : ICentralAuditWriter
{
public Task WriteAsync(AuditEvent evt, CancellationToken ct = default) => Task.CompletedTask;
}