feat(audit)!: ScadaBridge C3 — swap to canonical ZB.MOM.WW.Audit.AuditEvent across seams/emitters/DTO/redactor wiring; transitional 24-col storage shim (Task 2.5)

This commit is contained in:
Joseph Doherty
2026-06-02 12:37:50 -04:00
parent 5aaf9e2923
commit db707bb0de
127 changed files with 2240 additions and 3886 deletions
@@ -2,22 +2,24 @@ using System.Diagnostics;
using System.Text;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.Audit;
using ZB.MOM.WW.ScadaBridge.AuditLog.Configuration;
using ZB.MOM.WW.ScadaBridge.AuditLog.Payload;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
using ZB.MOM.WW.ScadaBridge.AuditLog.Redaction;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.PerformanceTests.AuditLog;
/// <summary>
/// Bundle D (M5-T9) hot-path latency budget for <see cref="IAuditPayloadFilter"/>.
/// The filter sits between event construction and persistence on every audit
/// Bundle D (M5-T9) hot-path latency budget for <see cref="ScadaBridgeAuditRedactor"/>.
/// The redactor sits between event construction and persistence on every audit
/// row — site SQLite hot-path and central direct-write both — so it MUST stay
/// out of the way of script-thread latency.
/// out of the way of script-thread latency. (C3, Task 2.5: this replaces the
/// former <c>IAuditPayloadFilter</c> hot-path component.)
/// </summary>
/// <remarks>
/// <para>
/// Methodology: warm-up + N iterations, time each <see cref="IAuditPayloadFilter.Apply"/>
/// Methodology: warm-up + N iterations, time each <see cref="ScadaBridgeAuditRedactor.Apply"/>
/// with <see cref="Stopwatch"/>, sort, take p95, assert under threshold. Matches
/// the simple-loop style of the existing <c>StaggeredStartupTests</c> /
/// <c>HealthAggregationTests</c> in this project (no BenchmarkDotNet).
@@ -37,23 +39,20 @@ public class HotPathLatencyTests
private const int WarmupIterations = 200;
private const int MeasureIterations = 2_000;
private static DefaultAuditPayloadFilter Filter(AuditLogOptions opts) => new(
// C3 (Task 2.5): the hot-path redactor is now the canonical
// ScadaBridgeAuditRedactor (IAuditRedactor) operating on the canonical record;
// it ports the old DefaultAuditPayloadFilter redaction + truncation behaviour.
private static ScadaBridgeAuditRedactor Filter(AuditLogOptions opts) => new(
new StaticMonitor(opts),
NullLogger<DefaultAuditPayloadFilter>.Instance);
NullLogger<ScadaBridgeAuditRedactor>.Instance);
private static AuditEvent NewEvent(string request)
{
return new AuditEvent
{
EventId = Guid.NewGuid(),
OccurredAtUtc = DateTime.UtcNow,
Channel = AuditChannel.ApiOutbound,
Kind = AuditKind.ApiCall,
Status = AuditStatus.Delivered,
Target = "esg.target",
RequestSummary = request,
};
}
private static AuditEvent NewEvent(string request) =>
ScadaBridgeAuditEventFactory.Create(
channel: AuditChannel.ApiOutbound,
kind: AuditKind.ApiCall,
status: AuditStatus.Delivered,
target: "esg.target",
requestSummary: request);
/// <summary>
/// Run <paramref name="fn"/> N times, returning the p95 in microseconds.