docs: backfill XML documentation across 756 files
v2-ci / build (push) Failing after 1m43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped

Adds <summary>, <param>, <typeparam>, and <inheritdoc/> tags to public
members surfaced by commentchecker — resolves 5,847 of 5,869 issues
(99.6%) across three /fixdocs passes.
This commit is contained in:
Joseph Doherty
2026-05-28 08:10:17 -04:00
parent f9fc7dd2e1
commit 64e3fbe035
756 changed files with 9876 additions and 96 deletions
@@ -31,6 +31,7 @@ public sealed class ScriptedAlarmEngineTests
MessageTemplate: msg,
PredicateScriptSource: predicate);
/// <summary>Verifies that LoadAsync compiles the alarm predicate and subscribes to all referenced upstream tags.</summary>
[Fact]
public async Task Load_compiles_and_subscribes_to_referenced_upstreams()
{
@@ -45,6 +46,7 @@ public sealed class ScriptedAlarmEngineTests
up.ActiveSubscriptionCount.ShouldBe(1);
}
/// <summary>Verifies that compile failures across multiple alarms are aggregated into a single error.</summary>
[Fact]
public async Task Compile_failures_aggregated_into_one_error()
{
@@ -60,6 +62,7 @@ public sealed class ScriptedAlarmEngineTests
ex.Message.ShouldContain("2 alarm(s) did not compile");
}
/// <summary>Verifies that an upstream tag change triggers predicate re-evaluation and emits an Activated event.</summary>
[Fact]
public async Task Upstream_change_re_evaluates_predicate_and_emits_Activated()
{
@@ -80,6 +83,7 @@ public sealed class ScriptedAlarmEngineTests
eng.GetState("HighTemp")!.Active.ShouldBe(AlarmActiveState.Active);
}
/// <summary>Verifies that clearing an upstream tag value emits a Cleared event and transitions the alarm to Inactive.</summary>
[Fact]
public async Task Clearing_upstream_emits_Cleared_event()
{
@@ -100,6 +104,7 @@ public sealed class ScriptedAlarmEngineTests
eng.GetState("HighTemp")!.Active.ShouldBe(AlarmActiveState.Inactive);
}
/// <summary>Verifies that the message template resolves current tag values at the moment of alarm emission.</summary>
[Fact]
public async Task Message_template_resolves_tag_values_at_emission()
{
@@ -124,6 +129,7 @@ public sealed class ScriptedAlarmEngineTests
events[0].Message.ShouldBe("Temp 150C exceeded limit 100C");
}
/// <summary>Verifies that AcknowledgeAsync records the operator user and persists the ack state to the store.</summary>
[Fact]
public async Task Ack_records_user_and_persists_to_store()
{
@@ -143,6 +149,7 @@ public sealed class ScriptedAlarmEngineTests
persisted.Comments.Any(c => c.Kind == "Acknowledge" && c.User == "alice").ShouldBeTrue();
}
/// <summary>Verifies that startup recovery restores the persisted ack state but re-derives the active state from the live predicate.</summary>
[Fact]
public async Task Startup_recovery_preserves_ack_but_rederives_active_from_predicate()
{
@@ -190,6 +197,7 @@ public sealed class ScriptedAlarmEngineTests
s.LastAckUser.ShouldBe("alice");
}
/// <summary>Verifies that a shelved alarm transitions its internal state on activation but suppresses the Activated emission.</summary>
[Fact]
public async Task Shelved_active_transitions_state_but_suppresses_emission()
{
@@ -213,6 +221,7 @@ public sealed class ScriptedAlarmEngineTests
"state still advances so startup recovery is consistent");
}
/// <summary>Verifies that a runtime exception thrown by a predicate script leaves the alarm state unchanged and does not affect other alarms.</summary>
[Fact]
public async Task Predicate_runtime_exception_does_not_transition_state()
{
@@ -229,6 +238,7 @@ public sealed class ScriptedAlarmEngineTests
eng.GetState("GoodScript")!.Active.ShouldBe(AlarmActiveState.Active);
}
/// <summary>Verifies that a disabled alarm does not activate on predicate change and resumes normally after being re-enabled.</summary>
[Fact]
public async Task Disable_prevents_activation_until_re_enabled()
{
@@ -249,6 +259,7 @@ public sealed class ScriptedAlarmEngineTests
await WaitForAsync(() => eng.GetState("HighTemp")!.Active == AlarmActiveState.Active);
}
/// <summary>Verifies that AddCommentAsync appends to the audit trail without changing the alarm's active or ack state.</summary>
[Fact]
public async Task AddComment_appends_to_audit_without_state_change()
{
@@ -266,6 +277,7 @@ public sealed class ScriptedAlarmEngineTests
s.Comments[0].Kind.ShouldBe("AddComment");
}
/// <summary>Verifies that predicate scripts are forbidden from calling SetVirtualTag, and that the exception is isolated without state change.</summary>
[Fact]
public async Task Predicate_scripts_cannot_SetVirtualTag()
{
@@ -289,6 +301,7 @@ public sealed class ScriptedAlarmEngineTests
eng.GetState("Bad")!.Active.ShouldBe(AlarmActiveState.Inactive);
}
/// <summary>Verifies that disposing the engine releases all upstream tag subscriptions.</summary>
[Fact]
public async Task Dispose_releases_upstream_subscriptions()
{
@@ -303,6 +316,7 @@ public sealed class ScriptedAlarmEngineTests
up.ActiveSubscriptionCount.ShouldBe(0);
}
/// <summary>Verifies that concurrent reads of alarm state during dictionary mutations do not throw (regression for Core.ScriptedAlarms-001).</summary>
[Fact]
public async Task Concurrent_reads_during_mutation_do_not_throw(/* Core.ScriptedAlarms-001 */)
{
@@ -371,6 +385,7 @@ public sealed class ScriptedAlarmEngineTests
// (1) Timed-shelve auto-expiry driven by the engine's shelving timer via an
// injectable clock — the clock and scriptTimeout constructor parameters
// exist for exactly this.
/// <summary>Verifies that a timed shelve automatically expires when the engine's shelving check runs past the unshelve time.</summary>
[Fact]
public async Task TimedShelve_auto_expires_when_engine_shelving_check_runs(/* -012 (1) */)
{
@@ -407,6 +422,7 @@ public sealed class ScriptedAlarmEngineTests
}
// (2a) ConfirmAsync end-to-end through the engine.
/// <summary>Verifies that ConfirmAsync records the confirming user and emits a Confirmed event persisted to the store.</summary>
[Fact]
public async Task ConfirmAsync_records_user_and_emits_Confirmed(/* -012 (2) */)
{
@@ -433,6 +449,7 @@ public sealed class ScriptedAlarmEngineTests
}
// (2b) TimedShelveAsync / UnshelveAsync end-to-end through the engine.
/// <summary>Verifies that TimedShelveAsync shelves with a deadline and UnshelveAsync removes the shelve before the timer expires.</summary>
[Fact]
public async Task TimedShelveAsync_and_UnshelveAsync_round_trip(/* -012 (2) */)
{
@@ -460,6 +477,7 @@ public sealed class ScriptedAlarmEngineTests
}
// (2c) EnableAsync end-to-end through the engine.
/// <summary>Verifies that EnableAsync transitions the alarm back to Enabled state and emits an Enabled event.</summary>
[Fact]
public async Task EnableAsync_re_enables_after_disable(/* -012 (2) */)
{
@@ -482,6 +500,7 @@ public sealed class ScriptedAlarmEngineTests
// (3) OnEvent subscriber-throws isolation — a bad subscriber must not crash
// the engine or prevent subsequent alarm state transitions. The engine logs
// the exception and continues operating; any later alarm changes still work.
/// <summary>Verifies that an exception thrown by an OnEvent subscriber is isolated and does not crash the engine or prevent further state transitions.</summary>
[Fact]
public async Task OnEvent_subscriber_exception_does_not_crash_engine(/* -012 (3) */)
{
@@ -514,6 +533,7 @@ public sealed class ScriptedAlarmEngineTests
// (4) IAlarmStateStore.SaveAsync failure — in-memory state must remain at the
// prior value after finding -007 fix (persist-before-update).
/// <summary>Verifies that a store SaveAsync failure leaves the in-memory alarm state at its prior value (persist-before-update invariant, finding -007).</summary>
[Fact]
public async Task Store_save_failure_leaves_in_memory_state_unchanged(/* -012 (4) */)
{
@@ -544,6 +564,7 @@ public sealed class ScriptedAlarmEngineTests
// (5) Re-entrant LoadAsync — the old timer must not keep firing after a second
// call (regression for finding -002: _shelvingTimer?.Dispose() fix).
/// <summary>Verifies that a second LoadAsync call disposes the prior shelving timer so it does not keep firing after reload (regression for finding -002).</summary>
[Fact]
public async Task Second_LoadAsync_does_not_leak_old_timer(/* -012 (5) */)
{
@@ -576,6 +597,7 @@ public sealed class ScriptedAlarmEngineTests
// (6) Cold-start AreInputsReady guard — null value, Bad status, and Uncertain
// status inputs are all handled correctly.
/// <summary>Verifies that AreInputsReady blocks predicate evaluation when inputs have null values or Bad status codes, while Uncertain quality is accepted.</summary>
[Fact]
public async Task AreInputsReady_blocks_evaluation_for_null_and_bad_inputs(/* -012 (6) */)
{
@@ -612,6 +634,7 @@ public sealed class ScriptedAlarmEngineTests
// (2) A subscriber that re-enters the engine (e.g. AcknowledgeAsync) must
// not deadlock against _evalGate. Both regressions are covered here.
// -------------------------------------------------------------------------
/// <summary>Verifies that an OnEvent subscriber can call engine methods (e.g. AcknowledgeAsync) without deadlocking against the evaluation gate (regression for Core.ScriptedAlarms-003).</summary>
[Fact]
public async Task OnEvent_subscriber_can_call_back_into_engine_without_deadlock(/* -003 */)
{
@@ -663,6 +686,7 @@ public sealed class ScriptedAlarmEngineTests
}
}
/// <summary>Verifies that OnEvent emission occurs after the evaluation gate is released, so subscribers can re-enter the engine without deadlocking (regression for Core.ScriptedAlarms-003).</summary>
[Fact]
public void OnEvent_emission_happens_outside_evalGate(/* -003 */)
{
@@ -723,6 +747,7 @@ public sealed class ScriptedAlarmEngineTests
// or shelving check started just before Dispose can keep running and write
// to a (possibly disposed) store after the engine has returned.
// -------------------------------------------------------------------------
/// <summary>Verifies that Dispose blocks until in-flight background re-evaluation tasks complete, preventing the engine from outliving its store (regression for Core.ScriptedAlarms-006).</summary>
[Fact]
public async Task Dispose_drains_in_flight_reevaluation_tasks(/* -006 */)
{
@@ -768,6 +793,7 @@ public sealed class ScriptedAlarmEngineTests
// resolution renders Uncertain as "{?}" so the operator sees the doubt
// explicitly. The two policies are documented in docs/ScriptedAlarms.md.
// -------------------------------------------------------------------------
/// <summary>Verifies that Uncertain-quality inputs are accepted by the predicate but rendered as "{?}" in the operator-facing message template (Core.ScriptedAlarms-010).</summary>
[Fact]
public async Task Uncertain_quality_drives_predicate_but_renders_question_mark_in_message(/* -010 */)
{
@@ -815,6 +841,7 @@ public sealed class ScriptedAlarmEngineTests
// (which still satisfies IReadOnlyList<AlarmComment> for existing
// consumers).
// -------------------------------------------------------------------------
/// <summary>Verifies that the Comments collection is an ImmutableList, enabling O(log n) append and satisfying IReadOnlyList consumers (Core.ScriptedAlarms-008).</summary>
[Fact]
public async Task Comments_collection_uses_ImmutableList_for_efficient_append(/* -008 */)
{
@@ -836,6 +863,7 @@ public sealed class ScriptedAlarmEngineTests
// propagated, not silently discarded. The class-level remarks promise a
// diagnostic log line for no-op disabled-alarm evaluations.
// -------------------------------------------------------------------------
/// <summary>Verifies that TransitionResult.NoOp preserves the supplied diagnostic reason string for caller logging (Core.ScriptedAlarms-011).</summary>
[Fact]
public void TransitionResult_NoOp_propagates_reason(/* -011 */)
{
@@ -845,6 +873,7 @@ public sealed class ScriptedAlarmEngineTests
"NoOp reason must be preserved on the TransitionResult so callers can log it");
}
/// <summary>Verifies that TransitionResult.None carries a null reason, distinguishing it from the NoOp factory (Core.ScriptedAlarms-011).</summary>
[Fact]
public void TransitionResult_None_carries_no_reason(/* -011 */)
{
@@ -875,20 +904,32 @@ public sealed class ScriptedAlarmEngineTests
private sealed class FailOnSaveAlarmStateStore : IAlarmStateStore
{
private readonly InMemoryAlarmStateStore _inner = new();
/// <summary>Gets or sets a value indicating whether the next SaveAsync call should throw a simulated failure.</summary>
public bool FailSave { get; set; }
/// <summary>Loads an alarm condition state by ID from the inner store.</summary>
/// <param name="alarmId">The ID of the alarm condition state to load.</param>
/// <param name="ct">A cancellation token.</param>
public Task<AlarmConditionState?> LoadAsync(string alarmId, CancellationToken ct)
=> _inner.LoadAsync(alarmId, ct);
/// <summary>Loads all alarm condition states from the inner store.</summary>
/// <param name="ct">A cancellation token.</param>
public Task<IReadOnlyList<AlarmConditionState>> LoadAllAsync(CancellationToken ct)
=> _inner.LoadAllAsync(ct);
/// <summary>Saves an alarm condition state, optionally throwing if FailSave is set.</summary>
/// <param name="state">The alarm condition state to save.</param>
/// <param name="ct">A cancellation token.</param>
public Task SaveAsync(AlarmConditionState state, CancellationToken ct)
{
if (FailSave) throw new InvalidOperationException("Simulated store failure");
return _inner.SaveAsync(state, ct);
}
/// <summary>Removes an alarm condition state by ID from the inner store.</summary>
/// <param name="alarmId">The ID of the alarm condition state to remove.</param>
/// <param name="ct">A cancellation token.</param>
public Task RemoveAsync(string alarmId, CancellationToken ct)
=> _inner.RemoveAsync(alarmId, ct);
}
@@ -900,15 +941,25 @@ public sealed class ScriptedAlarmEngineTests
private sealed class BlockingSaveAlarmStateStore : IAlarmStateStore
{
private readonly InMemoryAlarmStateStore _inner = new();
/// <summary>Gets or sets a TaskCompletionSource that, when set, blocks the next SaveAsync until signalled.</summary>
public TaskCompletionSource? BlockNextSave { get; set; }
/// <summary>Gets a value indicating whether a SaveAsync call is currently blocked waiting on BlockNextSave.</summary>
public bool SaveInProgress { get; private set; }
/// <summary>Loads an alarm condition state by ID from the inner store.</summary>
/// <param name="alarmId">The ID of the alarm condition state to load.</param>
/// <param name="ct">A cancellation token.</param>
public Task<AlarmConditionState?> LoadAsync(string alarmId, CancellationToken ct)
=> _inner.LoadAsync(alarmId, ct);
/// <summary>Loads all alarm condition states from the inner store.</summary>
/// <param name="ct">A cancellation token.</param>
public Task<IReadOnlyList<AlarmConditionState>> LoadAllAsync(CancellationToken ct)
=> _inner.LoadAllAsync(ct);
/// <summary>Saves an alarm condition state, optionally blocking on BlockNextSave gate.</summary>
/// <param name="state">The alarm condition state to save.</param>
/// <param name="ct">A cancellation token.</param>
public async Task SaveAsync(AlarmConditionState state, CancellationToken ct)
{
var gate = BlockNextSave;
@@ -922,12 +973,16 @@ public sealed class ScriptedAlarmEngineTests
await _inner.SaveAsync(state, ct).ConfigureAwait(false);
}
/// <summary>Removes an alarm condition state by ID from the inner store.</summary>
/// <param name="alarmId">The ID of the alarm condition state to remove.</param>
/// <param name="ct">A cancellation token.</param>
public Task RemoveAsync(string alarmId, CancellationToken ct)
=> _inner.RemoveAsync(alarmId, ct);
}
// --- Core.ScriptedAlarms-009: per-alarm evaluation-scratch reuse ---
/// <summary>Verifies that re-evaluations reuse the same read cache dictionary instance instead of allocating a new one.</summary>
[Fact]
public async Task Reevaluation_reuses_the_same_read_cache_dictionary()
{
@@ -960,6 +1015,7 @@ public sealed class ScriptedAlarmEngineTests
scratchAfterPush!["Temp"].Value.ShouldBe(150, "refill must update the existing dictionary in place");
}
/// <summary>Verifies that re-evaluations reuse the same predicate context instance across evaluations.</summary>
[Fact]
public async Task Reevaluation_reuses_the_same_predicate_context()
{
@@ -985,6 +1041,7 @@ public sealed class ScriptedAlarmEngineTests
"the AlarmPredicateContext must be reused across evaluations (Core.ScriptedAlarms-009).");
}
/// <summary>Verifies that LoadAsync clears prior evaluation scratch so new alarms use fresh scratch.</summary>
[Fact]
public async Task LoadAsync_drops_the_prior_generations_scratch()
{
@@ -1018,6 +1075,7 @@ public sealed class ScriptedAlarmEngineTests
// --- Core.Scripting-016: engine routes compiles through CompiledScriptCache ---
/// <summary>Verifies that Dispose unloads the compiled predicate assembly via the script cache.</summary>
[Fact]
public void Dispose_unloads_compiled_predicate_assembly()
{