fix(auditlog): explicit permanent rejections on the ingest ack (IngestAck.rejected_event_ids, field 2) with a dedicated counter; reconciler ignores transient faults for abandonment; persist the served high-water mark; prune only on a non-empty enumeration (review 2026-10-21 06/PERF-1, 06/IMPL-1 adversarial follow-up)

This commit is contained in:
Joseph Doherty
2026-10-22 08:40:42 -04:00
parent 38167bca88
commit b0a08bb63b
23 changed files with 790 additions and 168 deletions
@@ -0,0 +1,35 @@
using System.Reflection;
using Microsoft.Data.SqlClient;
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Tests.TestSupport;
/// <summary>
/// Fabricates a <see cref="SqlException"/> with a given error number via the driver's internal
/// <c>CreateException</c> factory (the type has no public constructor) — same technique as
/// ExternalSystemGateway.Tests' <c>FabricateSqlException</c>.
/// </summary>
internal static class SqlExceptionFactory
{
/// <summary>Creates a <see cref="SqlException"/> carrying one error with <paramref name="number"/>.</summary>
/// <param name="number">The SQL Server error number.</param>
/// <param name="message">The error message.</param>
/// <returns>The fabricated exception.</returns>
public static SqlException Create(int number, string message = "simulated")
{
var errorCtor = typeof(SqlError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
.First(c => c.GetParameters().Length == 8 && c.GetParameters()[7].ParameterType == typeof(Exception));
var sqlError = (SqlError)errorCtor.Invoke(
new object?[] { number, (byte)0, (byte)0, "server", message, "procedure", 0, null });
var collection = (SqlErrorCollection)typeof(SqlErrorCollection)
.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First()
.Invoke(Array.Empty<object?>());
typeof(SqlErrorCollection).GetMethod("Add", BindingFlags.Instance | BindingFlags.NonPublic)!
.Invoke(collection, new object?[] { sqlError });
var create = typeof(SqlException).GetMethod("CreateException",
BindingFlags.Static | BindingFlags.NonPublic,
new[] { typeof(SqlErrorCollection), typeof(string) })!;
return (SqlException)create.Invoke(null, new object?[] { collection, "6.0.0" })!;
}
}