docs(src): fix CommentChecker findings across src/ — 1,032 → 5 (all false positives)

Comment/XML-doc changes only, no code logic:
- strip project-tracking references (WP*, P*-*, row-NN, #NN, Task N) from
  comments, keeping the explanatory rationale
- add missing summaries, <param>, <returns>, <typeparam> and <inheritdoc/>
- replace misused <inheritdoc/> with real docs; where <inheritdoc/> was
  combined with useful remarks, move the rationale into // comments
- drop stale replicationActor <param> on DeploymentManagerActor ctor

Remaining 5 are false positives (CWE-1236 x2, failures-1, year-0001, M365).
Build 0 errors / 0 warnings.
This commit is contained in:
Joseph Doherty
2026-10-07 14:12:25 -04:00
parent 3a217b9484
commit 0ffd4bdbea
217 changed files with 1224 additions and 695 deletions
@@ -242,7 +242,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
private Action? _disconnectedHandler;
/// <summary>
/// Arch-review 2026-08-19 <b>P2-6</b>. Set when an <see cref="AdapterDisconnected"/> for the
/// Set when an <see cref="AdapterDisconnected"/> for the
/// CURRENT adapter generation is received while the actor is still Connecting/Reconnecting —
/// i.e. the adapter connected and dropped again before the piped
/// <see cref="ConnectResult"/> for that attempt reached the mailbox.
@@ -404,7 +404,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
HandleConnectResult(result);
break;
case AdapterDisconnected disconnected:
// P2-6 — the adapter connected and dropped again before this attempt's
// The adapter connected and dropped again before this attempt's
// ConnectResult was applied. Remember it (see _disconnectDuringConnectAttempt)
// rather than acting now: acting would put the actor into Reconnecting and the
// in-flight ConnectResult(true) would then be applied THERE, re-subscribing and
@@ -557,7 +557,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
FlushQualityCountersIfDirty();
break;
case AdapterDisconnected disconnected:
// P2-6 — fence the disconnect on its adapter generation. The outgoing adapter's
// Fence the disconnect on its adapter generation. The outgoing adapter's
// event can fire concurrently with SwapAdapter's unhook, so a Disconnected from
// the endpoint we have just failed over (or reconfigured) AWAY from could arrive
// here and knock the healthy replacement back into a reconnect cycle.
@@ -803,7 +803,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
HandleReconnectResult(result);
break;
case AdapterDisconnected disconnected:
// P2-6 — same gap as Connecting: a reconnect that succeeds and drops again before
// Same gap as Connecting: a reconnect that succeeds and drops again before
// its ConnectResult is applied would otherwise be declared Connected on a dead
// adapter that will never raise Disconnected a second time.
NotePendingDisconnect(disconnected);
@@ -892,7 +892,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
private void HandleAttemptConnect()
{
_log.Debug("[{0}] Attempting connection...", _connectionName);
// P2-6 — scope the pending-disconnect flag to THIS attempt. Anything noted before now
// Scope the pending-disconnect flag to THIS attempt. Anything noted before now
// belongs to a session that is already over and must not be replayed against the one
// about to start.
_disconnectDuringConnectAttempt = false;
@@ -912,7 +912,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
/// <summary>
/// True when this connect result was produced by an adapter that has since been swapped
/// out, in which case it is dropped WHOLE (arch-review 2026-08-19 P2-3).
/// out, in which case it is dropped WHOLE (arch-review 2026-08-19).
///
/// <para>
/// A success from the dead adapter used to drive <see cref="ReSubscribeAll"/> and
@@ -949,7 +949,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
/// <summary>
/// True when this <see cref="AdapterDisconnected"/> was raised by an adapter that has since
/// been swapped out (failover or in-place reconfigure), in which case it is dropped — the
/// disconnect twin of <see cref="IsStaleConnectResult"/> (arch-review 2026-08-19 P2-6).
/// disconnect twin of <see cref="IsStaleConnectResult"/> (arch-review 2026-08-19).
/// <see cref="SwapAdapter"/> unhooks the outgoing adapter, but the event can already be
/// executing on a background thread when it does, so the message can still be delivered
/// after the swap.
@@ -1022,7 +1022,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
if (result.Success)
{
// P2-6 — a disconnect that raced ahead of this result means the session this
// A disconnect that raced ahead of this result means the session this
// "success" describes is already gone; going Connected here would strand the
// connection on a dead adapter that never raises Disconnected again. Stay in
// Connecting and retry, exactly as a failed connect would.
@@ -1056,7 +1056,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
if (result.Success)
{
// P2-6 — same demotion as the initial connect: the reconnect landed but the adapter
// Same demotion as the initial connect: the reconnect landed but the adapter
// has already reported the new session lost, so re-subscribing and going Connected
// would wedge on a dead adapter. Stay in Reconnecting and retry.
if (ConsumeDisconnectDuringConnectAttempt())
@@ -1709,8 +1709,8 @@ public class DataConnectionActor : UntypedActor, IWithTimers
// fresh-subscribe vs. unresolved→resolved-promotion split existed only to
// decide which of the two scalar counters to bump (a promotion had to move
// _resolvedTags WITHOUT re-bumping _totalSubscribed, or a tag that a second
// instance resolved after a first instance failed it counted twice —
// DataConnectionLayer-020). Derived counts get both cases right for free;
// instance resolved after a first instance failed it counted twice.
// Derived counts get both cases right for free;
// all that is left of the promotion is dropping the retry bookkeeping.
_subscriptionIds[result.TagPath] = result.SubscriptionId!;
if (_unresolvedTags.Remove(result.TagPath))
@@ -1731,7 +1731,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
// (an instance subscribes to it, so it is in the per-tag counted set); it
// simply does not count as resolved. Two instances failing the SAME tag is
// still one logical tag in both counts, because both counts are set sizes
// rather than accumulated increments (DataConnectionLayer-020).
// rather than accumulated increments.
_unresolvedTags.Add(result.TagPath);
_log.Debug("[{0}] Tag resolution failed for {1}: {2}",
_connectionName, result.TagPath, result.Error);
@@ -1821,7 +1821,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
/// <summary>
/// OPC UA status codes that mean the SESSION or the SECURE CHANNEL is gone, not that one
/// node is unusable (arch-review 2026-08-19 P2-4). The SDK reports a dead session by
/// node is unusable (arch-review 2026-08-19). The SDK reports a dead session by
/// throwing <see cref="Opc.Ua.ServiceResultException"/> out of the batch subscribe, which
/// classified as a per-tag fault: every tag in the chunk was marked unresolved and each
/// backoff probe re-issued the whole batch against the same dead session, growing the
@@ -2383,7 +2383,7 @@ public class DataConnectionActor : UntypedActor, IWithTimers
/// through the normal generation-guarded <see cref="TagValueReceived"/> path — the same seed
/// the initial subscribe (<see cref="HandleSubscribe"/>) and the reconnect re-subscribe
/// (<see cref="ReSubscribeAll"/>) already perform, which the resolution probe was missing
/// (arch-review 2026-08-19 <b>P2-5</b>).
/// (arch-review 2026-08-19).
///
/// <para>
/// A newly advised subscription only starts producing values on the source's next CHANGE.
@@ -2447,8 +2447,8 @@ public class DataConnectionActor : UntypedActor, IWithTimers
/// Arms the single-shot tag-resolution retry timer at the current backoff interval
/// when unresolved tags remain, and cancels it when none do. Single-shot (rescheduled
/// on probe completion) rather than periodic — a periodic timer cannot back off, and
/// re-arming a periodic timer on every failure is what starved the retry before
/// (DataConnectionLayer-022). Gating on <c>IsTimerActive</c> keeps a burst of failed
/// re-arming a periodic timer on every failure is what starved the retry before.
/// Gating on <c>IsTimerActive</c> keeps a burst of failed
/// subscribes from pushing the already-running deadline out.
/// </summary>
private void ScheduleTagResolutionRetry()
@@ -2901,11 +2901,22 @@ public class DataConnectionActor : UntypedActor, IWithTimers
private sealed class AlarmReplayState
{
/// <summary>The current alarm transitions keyed by alarm, as last published.</summary>
public Dictionary<string, NativeAlarmTransition> Current { get; set; } = new();
/// <summary>Transitions accumulated while a replay snapshot is being received.</summary>
public Dictionary<string, NativeAlarmTransition> Snapshot { get; } = new();
/// <summary>Live transitions that arrived while the snapshot was still in progress.</summary>
public Dictionary<string, NativeAlarmTransition> LiveDuringSnapshot { get; } = new();
/// <summary>True while a replay snapshot is being received.</summary>
public bool InSnapshot { get; set; }
/// <summary>True once the initial snapshot has completed and live updates may be published.</summary>
public bool Ready { get; set; }
/// <summary>The replay epoch the current state belongs to, if known.</summary>
public Guid? Epoch { get; set; }
}
private readonly Dictionary<string, AlarmReplayState> _alarmReplay = new();
@@ -101,7 +101,7 @@ public class MxGatewayDataConnection
// (no `secret:` prefix) passes through unchanged for back-compat.
// The reference is parsed by the SAME parser central's SecretReferenceScanner uses to
// decide which secret to ship (trimmed, case-insensitive prefix), so a padded or
// case-variant reference resolves exactly the name that was deployed (final review M3).
// case-variant reference resolves exactly the name that was deployed.
var apiKey = cfg.ApiKey;
if (SecretReferenceScanner.TryParseSecretReference(apiKey, out var secretName))
{
@@ -19,7 +19,7 @@ public static class OpcUaAlarmMapper
/// </summary>
/// <remarks>
/// <para>
/// <b>Why the routing identity is the binding string, not the event's name (Gitea #17).</b>
/// <b>Why the routing identity is the binding string, not the event's name.</b>
/// Routing does <c>transition.SourceObjectReference.StartsWith(bindingRef)</c>, where the
/// binding is a NodeId reference (the picker, CSV and config all store NodeIds). Deriving
/// the routing identity from the event's <c>SourceName</c> — a plain name like the RawPath
@@ -39,7 +39,7 @@ public static class OpcUaAlarmMapper
/// </para>
/// </remarks>
/// <param name="subscriptionSourceReference">The binding string this alarm feed was subscribed under (empty for the Server-object aggregate feed).</param>
/// <param name="sourceName">The event's <c>SourceName</c> field (the RawPath for OtOpcUa post-#473), or null/empty when unset.</param>
/// <param name="sourceName">The event's <c>SourceName</c> field (the RawPath for OtOpcUa), or null/empty when unset.</param>
/// <param name="conditionName">The event's <c>ConditionName</c> field, or null/empty when unset.</param>
/// <returns>The per-condition <c>SourceReference</c> key and the <c>SourceObjectReference</c> routing identity.</returns>
public static (string SourceReference, string SourceObjectReference) BuildIdentity(
@@ -29,7 +29,10 @@ public class RealOpcUaClient : IOpcUaClient
/// </summary>
private sealed class DataShard(Subscription subscription)
{
/// <summary>The OPC UA subscription backing this shard.</summary>
public Subscription Subscription { get; } = subscription;
/// <summary>The number of monitored items currently placed on this shard.</summary>
public int ItemCount { get; set; }
}
@@ -97,6 +100,10 @@ public class RealOpcUaClient : IOpcUaClient
public event Action? ConnectionLost;
/// <summary>Selects exactly the requested protection mode; protected discovery failures fail closed.</summary>
/// <param name="url">The discovery URL to query.</param>
/// <param name="requested">The security mode that must be matched exactly.</param>
/// <param name="discover">Delegate that returns the server's advertised endpoints.</param>
/// <returns>The endpoint matching the requested security mode.</returns>
internal static EndpointDescription DiscoverEndpoint(string url, MessageSecurityMode requested,
Func<EndpointDescriptionCollection> discover)
{
@@ -266,6 +273,8 @@ public class RealOpcUaClient : IOpcUaClient
/// A no-op when the advertised host/port is already reachable (so an opc-plc server that
/// advertises its real container name is left untouched).
/// </remarks>
/// <param name="endpoint">The discovered endpoint to rewrite in place; may be null.</param>
/// <param name="discoveryUrl">The reachable URL the operator configured.</param>
internal static void RewriteEndpointHostForReachability(EndpointDescription? endpoint, string discoveryUrl)
{
if (endpoint is null || string.IsNullOrWhiteSpace(endpoint.EndpointUrl))
@@ -633,8 +642,7 @@ public class RealOpcUaClient : IOpcUaClient
// one) leaves every item created so far registered in _callbacks / _itemShard and
// counted against its shard's budget, with nothing to ever release them: the
// actor sees the throw as a whole-chunk fault and re-issues the SAME batch on its
// backoff timer, so each probe grew the bookkeeping again (arch-review 2026-08-19
// P2-4). Unwind before propagating.
// backoff timer, so each probe grew the bookkeeping again. Unwind before propagating.
UnwindCreatedItems(created);
throw;
}
@@ -889,7 +897,7 @@ public class RealOpcUaClient : IOpcUaClient
{
if (e.NotificationValue is EventFieldList efl)
// sourceNodeId is the binding this feed was subscribed under; every
// transition on the feed is routed under it verbatim (see #17).
// transition on the feed is routed under it verbatim.
HandleAlarmEvent(handle, sourceNodeId, efl, onTransition);
};
@@ -1171,8 +1179,8 @@ public class RealOpcUaClient : IOpcUaClient
// Field layout (AlarmStateFields): [1]=SourceNode (NodeId), [2]=SourceName (string).
// The routing identity is the binding this feed was subscribed under (not the
// event's name), so DataConnectionActor's NodeId-keyed routing matches — see #17
// and OpcUaAlarmMapper.BuildIdentity. SourceName seeds the readable per-condition
// event's name), so DataConnectionActor's NodeId-keyed routing matches — see
// OpcUaAlarmMapper.BuildIdentity. SourceName seeds the readable per-condition
// key; fall back to the SourceNode NodeId string only when it is absent.
var sourceName = fields[2].Value as string;
if (string.IsNullOrEmpty(sourceName))
@@ -34,6 +34,7 @@ public class DataConnectionFactory : IDataConnectionFactory
/// the Site container (where <see cref="ISecretResolver"/> is registered); direct
/// construction without it keeps literal-key behaviour.
/// </param>
/// <param name="dataConnectionOptions">Optional data connection options, such as the MxGateway supervisory-advise parallelism; defaults apply when null.</param>
public DataConnectionFactory(
ILoggerFactory loggerFactory,
IOptions<OpcUaGlobalOptions> opcUaGlobalOptions,
@@ -5,7 +5,10 @@ namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer;
/// <summary>Validates the MxGateway client identity before connections start.</summary>
public sealed class MxGatewayGlobalOptionsValidator : IValidateOptions<MxGatewayGlobalOptions>
{
/// <inheritdoc />
/// <summary>Validates the MxGateway global options.</summary>
/// <param name="name">The named-options instance being validated, or <see langword="null"/>.</param>
/// <param name="options">The options to validate.</param>
/// <returns>A success result, or a failure naming the first invalid setting.</returns>
public ValidateOptionsResult Validate(string? name, MxGatewayGlobalOptions options)
{
if (string.IsNullOrWhiteSpace(options.ClientNamePrefix))
@@ -5,7 +5,10 @@ namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer;
/// <summary>Validates the OPC UA application identity before connections start.</summary>
public sealed class OpcUaGlobalOptionsValidator : IValidateOptions<OpcUaGlobalOptions>
{
/// <inheritdoc />
/// <summary>Fails validation when the OPC UA application name is blank.</summary>
/// <param name="name">The named options instance being validated.</param>
/// <param name="options">The options to validate.</param>
/// <returns>The validation result.</returns>
public ValidateOptionsResult Validate(string? name, OpcUaGlobalOptions options)
{
if (string.IsNullOrWhiteSpace(options.ApplicationName))