docs: complete XML doc coverage (returns, summaries, inheritdoc)

Resolve all 622 issues flagged by the enhanced CommentChecker: add missing
<returns> tags (incl. the standard phrasing on non-generic Task methods),
add missing <summary> tags, and replace misused/redundant <inheritdoc/> on
members that override or implement nothing with real documentation.
Documentation-only — no behavior change; solution builds clean.
This commit is contained in:
Joseph Doherty
2026-06-03 11:39:32 -04:00
parent a050170414
commit eabf270d71
208 changed files with 867 additions and 114 deletions
@@ -76,7 +76,12 @@ public sealed class AuditLogPartitionMaintenanceService : IHostedService, IDispo
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <inheritdoc />
/// <summary>
/// Starts the background maintenance loop, firing an immediate first tick and then
/// repeating every <see cref="AuditLogPartitionMaintenanceOptions.IntervalSeconds"/>.
/// </summary>
/// <param name="ct">Cancellation token provided by the host.</param>
/// <returns>A completed task; the loop runs independently on a background thread.</returns>
public Task StartAsync(CancellationToken ct)
{
// Linked CTS lets StopAsync's cancellation AND the host's shutdown
@@ -136,14 +141,21 @@ public sealed class AuditLogPartitionMaintenanceService : IHostedService, IDispo
}
}
/// <inheritdoc />
/// <summary>
/// Signals the maintenance loop to stop by cancelling its linked token,
/// then returns the loop task so the host can await its completion.
/// </summary>
/// <param name="ct">Cancellation token provided by the host (unused — the internal CTS is cancelled directly).</param>
/// <returns>The background loop task, or a completed task if the loop was never started.</returns>
public Task StopAsync(CancellationToken ct)
{
_cts?.Cancel();
return _loop ?? Task.CompletedTask;
}
/// <inheritdoc />
/// <summary>
/// Disposes the internal <see cref="CancellationTokenSource"/> used to stop the maintenance loop.
/// </summary>
public void Dispose()
{
_cts?.Dispose();
@@ -41,6 +41,7 @@ public interface IPullAuditEventsClient
/// <param name="sinceUtc">Only events with an <c>OccurredAtUtc</c> at or after this cursor time are returned.</param>
/// <param name="batchSize">Maximum number of events to return per call.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>A task that resolves to the next reconciliation batch with a <c>MoreAvailable</c> flag.</returns>
Task<PullAuditEventsResponse> PullAsync(
string siteId,
DateTime sinceUtc,
@@ -23,6 +23,7 @@ public interface ISiteEnumerator
/// — the actor calls this once per tick.
/// </summary>
/// <param name="ct">Cancellation token for the async enumeration.</param>
/// <returns>A task that resolves to the current set of site entries to poll on the next reconciliation tick.</returns>
Task<IReadOnlyList<SiteEntry>> EnumerateAsync(CancellationToken ct = default);
}
@@ -133,6 +133,7 @@ public sealed class SiteAuditTelemetryStalledTracker : IDisposable
/// Returns a defensive copy of the per-site latched stalled state.
/// Absent sites are interpreted as <c>Stalled=false</c> by consumers.
/// </summary>
/// <returns>A snapshot dictionary mapping each known site ID to its current stalled state.</returns>
public IReadOnlyDictionary<string, bool> Snapshot() =>
new Dictionary<string, bool>(_state);
@@ -71,6 +71,11 @@ internal static class AuditRedactionPrimitives
/// field is over-redacted with <see cref="RedactorErrorMarker"/> and
/// <paramref name="onFailure"/> is invoked.
/// </summary>
/// <param name="json">The raw JSON string to redact; null passes through as null.</param>
/// <param name="redactList">Header names (case-insensitive) whose values should be replaced.</param>
/// <param name="logger">Logger for warning diagnostics on redactor faults.</param>
/// <param name="onFailure">Callback invoked when the redactor stage faults; used to increment health counters.</param>
/// <returns>The re-serialized JSON with redacted header values, the original string if nothing was redacted, or <see cref="RedactorErrorMarker"/> on fault.</returns>
public static string? RedactHeaders(
string? json,
IList<string> redactList,
@@ -152,6 +157,11 @@ internal static class AuditRedactionPrimitives
/// with <see cref="RedactorErrorMarker"/> and <paramref name="onFailure"/>
/// is invoked — the user-facing action is never aborted.
/// </summary>
/// <param name="value">The string to redact; null passes through as null.</param>
/// <param name="regexes">Compiled body-redaction regexes applied in order.</param>
/// <param name="logger">Logger for warning diagnostics on redactor faults.</param>
/// <param name="onFailure">Callback invoked when a regex match faults; used to increment health counters.</param>
/// <returns>The value with all regex matches replaced by <see cref="RedactedMarker"/>, or <see cref="RedactorErrorMarker"/> on fault.</returns>
public static string? RedactBody(
string? value,
IReadOnlyList<Regex> regexes,
@@ -192,6 +202,11 @@ internal static class AuditRedactionPrimitives
/// is over-redacted with <see cref="RedactorErrorMarker"/> and
/// <paramref name="onFailure"/> is invoked.
/// </summary>
/// <param name="json">The raw JSON string to redact; null passes through as null.</param>
/// <param name="paramNameRegex">Compiled regex matched against each SQL parameter name.</param>
/// <param name="logger">Logger for warning diagnostics on redactor faults.</param>
/// <param name="onFailure">Callback invoked when the redactor stage faults; used to increment health counters.</param>
/// <returns>The re-serialized JSON with matched parameter values replaced by <see cref="RedactedMarker"/>, the original string if no parameters matched, or <see cref="RedactorErrorMarker"/> on fault.</returns>
public static string? RedactSqlParameters(
string? json,
Regex paramNameRegex,
@@ -277,6 +292,10 @@ internal static class AuditRedactionPrimitives
/// setting <paramref name="truncated"/> to <c>true</c> when the value was
/// shortened. Null passes through as null.
/// </summary>
/// <param name="value">The string to truncate; null passes through as null.</param>
/// <param name="cap">Maximum number of UTF-8 bytes to retain.</param>
/// <param name="truncated">Set to <c>true</c> when the value was shortened; unchanged otherwise.</param>
/// <returns>The truncated string, the original string if within the cap, or <c>null</c> if the input was null.</returns>
public static string? TruncateField(string? value, int cap, ref bool truncated)
{
if (value is null)
@@ -299,6 +318,9 @@ internal static class AuditRedactionPrimitives
/// (<c>byte &amp; 0xC0 == 0x80</c>), and decodes the resulting prefix —
/// guaranteeing the returned string never splits a multi-byte sequence.
/// </summary>
/// <param name="value">The string to truncate.</param>
/// <param name="capBytes">Maximum number of UTF-8 bytes in the returned string.</param>
/// <returns>The truncated string guaranteed not to split a multi-byte UTF-8 sequence, or the original string if within the cap.</returns>
public static string TruncateUtf8(string value, int capBytes)
{
if (string.IsNullOrEmpty(value))
@@ -35,6 +35,8 @@ internal sealed class AuditRegexCache
private readonly ConcurrentDictionary<string, CompiledRegex> _cache = new();
private readonly ILogger _logger;
/// <summary>Initializes the cache with the logger used to report compile failures.</summary>
/// <param name="logger">Logger for recording invalid or slow-compile pattern warnings.</param>
public AuditRegexCache(ILogger logger) => _logger = logger;
/// <summary>
@@ -44,6 +46,9 @@ internal sealed class AuditRegexCache
/// compile time "invalid"); the failure is logged once and the sentinel
/// cache entry prevents repeat compile attempts.
/// </summary>
/// <param name="pattern">The regex pattern string to look up or compile.</param>
/// <param name="regex">The compiled <see cref="Regex"/>, or <c>null</c> if the pattern is invalid.</param>
/// <returns><c>true</c> if the pattern compiled successfully; <c>false</c> if it is invalid or too slow to compile.</returns>
public bool TryGet(string pattern, out Regex? regex)
{
var entry = _cache.GetOrAdd(pattern, Compile);
@@ -88,8 +93,11 @@ internal sealed class AuditRegexCache
{
public static readonly CompiledRegex Invalid = new(null);
/// <summary>The compiled regex, or <c>null</c> when this entry represents an invalid pattern.</summary>
public Regex? Regex { get; }
/// <summary>Initializes the entry with the compiled regex (or <c>null</c> for the invalid sentinel).</summary>
/// <param name="regex">The compiled <see cref="Regex"/>, or <c>null</c> for a failed compile.</param>
public CompiledRegex(Regex? regex) => Regex = regex;
}
}
@@ -37,7 +37,15 @@ public sealed class SafeDefaultAuditRedactor : IAuditRedactor
private SafeDefaultAuditRedactor() { }
/// <inheritdoc />
/// <summary>
/// Applies line-oriented header redaction to the default sensitive headers
/// (<c>Authorization</c>, <c>X-Api-Key</c>, <c>Cookie</c>, <c>Set-Cookie</c>)
/// found in <c>RequestSummary</c> and <c>ResponseSummary</c> inside
/// <paramref name="rawEvent"/>.<c>DetailsJson</c>. Never throws; over-redacts on
/// any internal failure.
/// </summary>
/// <param name="rawEvent">The audit event whose details JSON is to be redacted.</param>
/// <returns>A new <see cref="AuditEvent"/> with sensitive headers replaced by the redacted marker, or an over-redacted sentinel on failure.</returns>
public AuditEvent Apply(AuditEvent rawEvent)
{
ArgumentNullException.ThrowIfNull(rawEvent);
@@ -73,7 +73,12 @@ public sealed class ScadaBridgeAuditRedactor : IAuditRedactor
_regexCache = new AuditRegexCache(_logger);
}
/// <inheritdoc />
/// <summary>
/// Applies the full redaction pipeline to <paramref name="rawEvent"/> and returns a
/// filtered copy; returns the same instance unchanged on the fast path. Never throws.
/// </summary>
/// <param name="rawEvent">The raw audit event to redact.</param>
/// <returns>A redacted copy of <paramref name="rawEvent"/>, or the original instance when no changes are needed.</returns>
public AuditEvent Apply(AuditEvent rawEvent)
{
try
@@ -96,6 +96,7 @@ public sealed class RingBufferFallback
/// must call <see cref="Complete"/> first.
/// </summary>
/// <param name="cancellationToken">Cancellation token to abort the async enumeration.</param>
/// <returns>An async sequence of buffered <see cref="AuditEvent"/> values in FIFO order.</returns>
public async IAsyncEnumerable<AuditEvent> DrainAsync(
[EnumeratorCancellation] CancellationToken cancellationToken)
{
@@ -69,7 +69,9 @@ public sealed class SiteAuditBacklogReporter : IHostedService, IDisposable
_refreshInterval = refreshInterval ?? DefaultRefreshInterval;
}
/// <inheritdoc />
/// <summary>Starts the background polling loop, running an immediate first probe before entering the timed cycle.</summary>
/// <param name="ct">Cancellation token signalling host shutdown.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public Task StartAsync(CancellationToken ct)
{
// Linked CTS lets StopAsync's cancellation AND the host's shutdown
@@ -123,14 +125,16 @@ public sealed class SiteAuditBacklogReporter : IHostedService, IDisposable
}
}
/// <inheritdoc />
/// <summary>Signals the polling loop to stop and waits for it to complete.</summary>
/// <param name="ct">Cancellation token (not used; the internal CTS governs shutdown).</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public Task StopAsync(CancellationToken ct)
{
_cts?.Cancel();
return _loop ?? Task.CompletedTask;
}
/// <inheritdoc />
/// <summary>Releases the internal <see cref="CancellationTokenSource"/> used to stop the polling loop.</summary>
public void Dispose()
{
_cts?.Dispose();
@@ -244,7 +244,13 @@ public class SqliteAuditWriter : IAuditWriter, ISiteAuditQueue, IAsyncDisposable
cmd.ExecuteNonQuery();
}
/// <inheritdoc />
/// <summary>
/// Enqueues an audit event for asynchronous batched persistence to SQLite.
/// Back-pressure is applied when the write channel is full.
/// </summary>
/// <param name="evt">The audit event to persist.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>A task that completes when the event has been persisted.</returns>
public Task WriteAsync(AuditEvent evt, CancellationToken ct = default)
{
ArgumentNullException.ThrowIfNull(evt);
@@ -469,7 +475,13 @@ public class SqliteAuditWriter : IAuditWriter, ISiteAuditQueue, IAsyncDisposable
return CachedTelemetryKinds.Contains(kind);
}
/// <inheritdoc />
/// <summary>
/// Returns up to <paramref name="limit"/> non-cached pending audit events, oldest first.
/// Cached-lifecycle kinds are excluded; use <see cref="ReadPendingCachedTelemetryAsync"/> for those.
/// </summary>
/// <param name="limit">Maximum number of rows to return.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>A task that resolves to a read-only list of pending audit events.</returns>
public Task<IReadOnlyList<AuditEvent>> ReadPendingAsync(int limit, CancellationToken ct = default)
{
if (limit <= 0)
@@ -512,7 +524,13 @@ public class SqliteAuditWriter : IAuditWriter, ISiteAuditQueue, IAsyncDisposable
}
}
/// <inheritdoc />
/// <summary>
/// Returns up to <paramref name="limit"/> pending cached-lifecycle audit events, oldest first.
/// Only rows with cached-call kinds (CachedSubmit, ApiCallCached, DbWriteCached, CachedResolve) are included.
/// </summary>
/// <param name="limit">Maximum number of rows to return.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>A task that resolves to a read-only list of pending cached-telemetry audit events.</returns>
public Task<IReadOnlyList<AuditEvent>> ReadPendingCachedTelemetryAsync(
int limit, CancellationToken ct = default)
{
@@ -560,6 +578,7 @@ public class SqliteAuditWriter : IAuditWriter, ISiteAuditQueue, IAsyncDisposable
/// </summary>
/// <param name="limit">Maximum number of rows to return.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>A task that resolves to a read-only list of forwarded audit events.</returns>
public Task<IReadOnlyList<AuditEvent>> ReadForwardedAsync(int limit, CancellationToken ct = default)
{
if (limit <= 0)
@@ -645,7 +664,15 @@ public class SqliteAuditWriter : IAuditWriter, ISiteAuditQueue, IAsyncDisposable
}
}
/// <inheritdoc />
/// <summary>
/// Returns up to <paramref name="batchSize"/> pending or forwarded audit events
/// with <see cref="AuditEvent.OccurredAtUtc"/> &gt;= <paramref name="sinceUtc"/>, oldest first.
/// Used by the M6 reconciliation-pull handler.
/// </summary>
/// <param name="sinceUtc">Lower bound timestamp (UTC) for event occurrence.</param>
/// <param name="batchSize">Maximum number of rows to return.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>A task that resolves to a read-only list of audit events since the given timestamp.</returns>
public Task<IReadOnlyList<AuditEvent>> ReadPendingSinceAsync(
DateTime sinceUtc, int batchSize, CancellationToken ct = default)
{
@@ -867,6 +894,7 @@ public class SqliteAuditWriter : IAuditWriter, ISiteAuditQueue, IAsyncDisposable
}
/// <summary>Asynchronously disposes the audit writer and releases resources.</summary>
/// <returns>A <see cref="ValueTask"/> that completes when all resources have been released.</returns>
public async ValueTask DisposeAsync()
{
Task? writerLoop;
@@ -44,6 +44,9 @@ public sealed class ClusterClientSiteAuditClient : ISiteStreamAuditClient
private readonly IActorRef _siteCommunicationActor;
private readonly TimeSpan _askTimeout;
/// <summary>
/// Initializes a new instance that forwards audit telemetry to central via the site's <c>SiteCommunicationActor</c>.
/// </summary>
/// <param name="siteCommunicationActor">
/// The site's <c>SiteCommunicationActor</c> — it forwards the ingest command
/// over the registered central ClusterClient and routes the reply back to
@@ -22,6 +22,7 @@ public interface ISiteStreamAuditClient
/// </summary>
/// <param name="batch">The batch of audit events to forward.</param>
/// <param name="ct">Cancellation token for the operation.</param>
/// <returns>A task that resolves to the ingest acknowledgement containing accepted event IDs.</returns>
Task<IngestAck> IngestAuditEventsAsync(AuditEventBatch batch, CancellationToken ct);
/// <summary>
@@ -42,5 +43,6 @@ public interface ISiteStreamAuditClient
/// </remarks>
/// <param name="batch">The batch of cached-call telemetry packets to forward.</param>
/// <param name="ct">Cancellation token for the operation.</param>
/// <returns>A task that resolves to the ingest acknowledgement containing accepted event IDs.</returns>
Task<IngestAck> IngestCachedTelemetryAsync(CachedTelemetryBatch batch, CancellationToken ct);
}