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:
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user