docs: fill missing XML docs and strip tracking IDs from src comments

Clears CommentChecker findings in src/ (3,280 -> 209, the remainder being false
positives like PLC-5/IEEE-754/M0.0) by adding missing summaries/params/returns,
normalising inheritdoc usage, and removing Gitea/review tracking IDs while keeping
the rationale they annotated. Comment-only: comment-stripped sources are identical
to the parent commit.
This commit is contained in:
Joseph Doherty
2026-10-15 06:14:58 -04:00
parent ebcbd81fca
commit 826312befe
430 changed files with 4434 additions and 3923 deletions
@@ -28,7 +28,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Calculation;
/// at least once, and equal results are deduped) and/or on a timer (one timer per interval group).
/// </para>
/// <para>
/// <b>Where scripts run (Driver.Calculation-005).</b> <see cref="OnDependencyValue"/> is called
/// <b>Where scripts run.</b> <see cref="OnDependencyValue"/> is called
/// directly and synchronously by <c>DependencyConsumerMuxAdapter</c> — on an Akka actor's own
/// dispatcher thread — so it does no evaluation itself: it records the value, <i>prepares</i> the
/// affected tags (definition + dependency snapshot, taken at trigger time) and hands them to a
@@ -47,7 +47,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Calculation;
/// </summary>
public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscribable, IReadable, ISkippedTagReporter, IDisposable
{
/// <summary>Authored tags this driver could not build into its calc table (Gitea #541). A raw tag with
/// <summary>Authored tags this driver could not build into its calc table. A raw tag with
/// no <c>scriptId</c> is not a calc tag and computes nothing.</summary>
private readonly SkippedTagLedger _skippedTags = new();
@@ -79,10 +79,9 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
// Live evaluation state. Guarded by _lock: OnDependencyValue (the mux actor's thread), timer ticks
// and the evaluation pump (pool threads) all touch it, so state mutation is serialized. _lock is a
// SHORT-HELD state lock — it is taken for dictionary work only and is NEVER held across a script run
// (Driver.Calculation-005).
// SHORT-HELD state lock — it is taken for dictionary work only and is NEVER held across a script run.
private readonly object _lock = new();
// Dependency SNAPSHOTS, not bare values (archreview 05/STAB-19): the status code is what tells a
// Dependency SNAPSHOTS, not bare values: the status code is what tells a
// comms-lost input apart from a genuine Good null, and storing values only is what let this driver
// compute a Good output from a dead source.
private readonly Dictionary<string, DataValueSnapshot> _depValues = new(StringComparer.Ordinal);
@@ -273,7 +272,9 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
/// <c>CalculationDriverConfigDto</c>.</summary>
private sealed class ReinitConfigDto
{
/// <summary>The raw tag entries carried by the re-initialisation config.</summary>
public List<RawTagEntry>? RawTags { get; init; }
/// <summary>The optional evaluation timeout in milliseconds; ignored on re-initialisation.</summary>
public int? RunTimeoutMs { get; init; }
}
@@ -285,14 +286,12 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
/// <inheritdoc />
public string DriverType => DriverTypeNames.Calculation;
// InitializeAsync takes a config document and the IDriver contract is that the driver serves it
// (the runtime's mid-connect adoption path was deleted) - so it adopts a config carrying a real
// body (the convention every other driver follows), and disposes any running timer scheduler before
// arming a fresh one (re-initialise without teardown must not leak). A "{}" / empty document keeps
// the constructor-supplied tags, as unit tests rely on.
/// <inheritdoc />
/// <remarks>
/// #664: <c>InitializeAsync</c> takes a config document and the <see cref="IDriver"/> contract is that the
/// driver serves it (the runtime's mid-connect adoption path was deleted in #665) — so it adopts a config carrying a
/// real body (the #516 convention every other driver follows), and disposes any running timer scheduler
/// before arming a fresh one (#630: re-initialise without teardown must not leak). A <c>"{}"</c> / empty
/// document keeps the constructor-supplied tags, as unit tests rely on.
/// </remarks>
public Task InitializeAsync(string driverConfigJson, CancellationToken cancellationToken)
{
StopTimers();
@@ -310,7 +309,7 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
{
// An in-place config change: re-bind the new config and REBUILD the tag table + dependency-ref set, so
// added tags compute, removed tags stop publishing and edited scripts serve the new result. The runtime
// itself applies a DriverConfig change by respawning (#516/#665), where a fresh driver registers its
// itself applies a DriverConfig change by respawning, where a fresh driver registers its
// new dependency refs on construction; this path keeps the IDriver contract honest for any caller.
StopTimers();
AdoptConfig(driverConfigJson);
@@ -330,19 +329,15 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
return Task.CompletedTask;
}
/// <summary>
/// Current health, derived from the driver's own lifecycle state.
/// <para><b>Gitea #517.</b> This used to return a hard-coded <see cref="DriverState.Healthy"/> that
/// consulted nothing. That made it the fleet's one driver whose <c>GetHealth()</c> reported Healthy
/// <em>with its timers stopped</em> — not as a race window, but permanently and deterministically:
/// before <see cref="InitializeAsync"/>, after <see cref="ShutdownAsync"/>, and after
/// <see cref="Dispose"/>. Every other driver reads a <c>_health</c> field that shutdown lands on
/// <see cref="DriverState.Unknown"/>.</para>
/// <para>There is no transport to be Degraded about — this driver computes from the dependency mux,
/// so its only meaningful states are "running" and "not running". <c>_running</c> is the flag the
/// compute paths themselves gate on, which is what makes it the honest input here.</para>
/// </summary>
/// <returns>Healthy while running; otherwise Unknown, retaining the last compute time.</returns>
// Current health, derived from the driver's own lifecycle state: Healthy while running; otherwise
// Unknown, retaining the last compute time. Health is never a hard-coded Healthy - a driver whose
// timers are stopped (before InitializeAsync, after ShutdownAsync, after Dispose) must not report
// Healthy, matching every other driver, whose _health field lands on Unknown at shutdown.
//
// There is no transport to be Degraded about - this driver computes from the dependency mux, so its
// only meaningful states are "running" and "not running". _running is the flag the compute paths
// themselves gate on, which is what makes it the honest input here.
/// <inheritdoc />
public DriverHealth GetHealth() => _running
? new DriverHealth(DriverState.Healthy, _lastComputeUtc, null)
: new DriverHealth(DriverState.Unknown, _lastComputeUtc, null);
@@ -363,7 +358,7 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
_arrivedDeps.Add(rawPath);
if (!_changeDependents.TryGetValue(rawPath, out var dependents) || dependents.Count == 0) return;
// QUEUE each change-triggered dependent — never evaluate here (Driver.Calculation-005). This
// QUEUE each change-triggered dependent — never evaluate here. This
// runs on the caller's thread, which for the live path is the Akka dispatcher thread of
// Runtime's DependencyConsumerMuxAdapter, and a script run is bounded only by RunTimeout.
// Everything under this lock is dictionary work; the script runs on the pump.
@@ -426,7 +421,7 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
return new DataValueSnapshot(null, StatusBadWaitingForInitialData, null, now);
// Exactly what the subscriber was last told — including a propagated input sub-code. Deriving
// it from a two-state flag here would make a read disagree with the subscription over the
// same node (05/STAB-19).
// same node.
var status = st.LastPublishedStatus;
return new DataValueSnapshot(st.LastValue, status, st.LastTimestampUtc, st.LastTimestampUtc);
}
@@ -484,7 +479,7 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
if (_depValues.TryGetValue(dep, out var v)) deps[dep] = v;
// Worst-of-input, computed from the SAME snapshot the evaluation will use, so the status
// published can never disagree with the values it was derived from (05/STAB-19).
// published can never disagree with the values it was derived from.
var worst = InputQuality.WorstOf(def.DependencyRefs.Select(r => deps.GetValueOrDefault(r)));
return new PendingEvaluation(def, deps, timestampUtc, worst);
}
@@ -556,7 +551,7 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
{
var def = pending.Definition;
// HOLD ON BAD (05/STAB-19, matching ScriptedAlarmEngine's AreInputsReady): a Bad input is not
// HOLD ON BAD (matching ScriptedAlarmEngine's AreInputsReady): a Bad input is not
// usable, so the script does NOT run — which removes the "(double)ctx.GetTag(x).Value threw"
// storm at its source rather than catching it downstream — and the tag reports the input's own
// sub-code. Uncertain IS usable: the script runs and the output inherits the Uncertain code.
@@ -576,7 +571,7 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
}
// Snapshots, not bare values: the script's ctx.GetTag(path).StatusCode / .SourceTimestampUtc are
// then the input's real ones rather than a fabricated Good stamped at evaluation time (05/STAB-19).
// then the input's real ones rather than a fabricated Good stamped at evaluation time.
var result = _evaluator.Evaluate(def.RawPath, def.ScriptSource, pending.Dependencies);
string? failureReason = null;
@@ -604,7 +599,7 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
/// <summary>Record a successful evaluation. MUST be called under <see cref="_lock"/>; returns what to
/// publish, or null when the result is deduped.
/// <para><b>The dedup key is (value, status), not value alone</b> — 05/STAB-19 generalising the
/// <para><b>The dedup key is (value, status), not value alone</b> — generalising the
/// Bad-recovery bypass 02/S13 introduced. Recovery is a publish, never an assumption: the node is
/// currently carrying the previous status, so a result whose VALUE is unchanged but whose STATUS
/// differs — the shape of every recovery, since a device that comes back usually comes back holding
@@ -629,7 +624,7 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
return (value, statusCode);
}
/// <summary>Record that this tag's INPUTS are Bad, so no evaluation ran (05/STAB-19). Publishes the
/// <summary>Record that this tag's INPUTS are Bad, so no evaluation ran. Publishes the
/// worst input's status — carrying the last known value — <b>once per change of that status</b>: a
/// repeat of the same Bad is silent, while <c>BadNoCommunication</c> arriving over an earlier
/// <c>BadInternalError</c> (or the reverse) is not masked, because the sub-code is what names which
@@ -720,7 +715,7 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
// always carries a non-null handle.
private static readonly CalculationSubscriptionHandle SharedHandle = new("calc-shared");
/// <inheritdoc />
/// <summary>Stops the timers and disposes the script evaluator.</summary>
public void Dispose()
{
if (_disposed) return;
@@ -742,7 +737,7 @@ public sealed class CalculationDriver : IDriver, IDependencyConsumer, ISubscriba
public bool HasPublished;
/// <summary>The status code last published for this tag. Replaces the old two-state
/// <c>LastPublishedBad</c> flag (05/STAB-19): the dedup key is (value, status), and a Bad status
/// <c>LastPublishedBad</c> flag: the dedup key is (value, status), and a Bad status
/// now carries the failing INPUT's sub-code rather than a fixed <c>BadInternalError</c>.</summary>
public uint LastPublishedStatus;
public DateTime LastTimestampUtc;