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
@@ -43,7 +43,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
private readonly DeployCompileValidator _deployCompileValidator;
private readonly SharedScriptLibrary _sharedScriptLibrary;
/// <summary>
/// WP2.6a: the shared cache backing <c>SiteExternalSystemRepository</c> reads.
/// The shared cache backing <c>SiteExternalSystemRepository</c> reads.
/// Invalidated wholesale after <see cref="HandleDeployArtifacts"/> applies
/// external-system changes so a script's next call re-reads fresh definitions/method
/// lists instead of serving a stale cached snapshot. Null in tests that do not wire
@@ -51,7 +51,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
/// </summary>
private readonly ExternalSystemDefinitionCache? _externalSystemCache;
/// <summary>
/// Task 10 (site-secrets artifact deploy): per-node mirror reconciled synchronously by
/// Per-node mirror reconciled synchronously by
/// <see cref="HandleDeployArtifacts"/> right after the shipped secrets are written to
/// <c>deployed_secrets</c>, so the reply's <c>SecretsApplied</c> reflects this node's own
/// apply/verify outcome rather than the next periodic pass. Optional/null on nodes/tests
@@ -97,7 +97,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
/// test can hold the read open mid-flight (row 101's ensure-started race tests).
/// </summary>
/// <remarks>
/// Register P1-4: the row-67 ensure-started heal used to read through
/// The ensure-started heal used to read through
/// <see cref="_configLoader"/> — the same full-table-including-ConfigJson load the boot
/// sequence uses — just to <c>FirstOrDefault</c> one instance. A volume-restore reconcile
/// that raises hundreds of <see cref="EnsureInstanceStartedCommand"/>s in a row turned that
@@ -202,7 +202,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
private readonly HashSet<string> _initFailedPendingRowRemoval = new();
/// <summary>
/// WP3.1 warm-then-gate: instances whose deploy compile is being warmed off the actor
/// Warm-then-gate: instances whose deploy compile is being warmed off the actor
/// thread, keyed by instance name. Presence is the per-instance in-flight guard that keeps
/// same-instance command ordering intact while OTHER instances' commands flow freely.
/// Entries are added in <see cref="HandleDeploy"/> and removed in
@@ -212,7 +212,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
private readonly Dictionary<string, DeployWarmState> _deployWarms = new();
/// <summary>
/// WP3.1: script-execution scheduler seam (#18) — the pool this actor grows as instances
/// Script-execution scheduler seam — the pool this actor grows as instances
/// deploy. Null selects the process-wide shared scheduler; tests inject their own so
/// sizing assertions do not perturb (or depend on) the process-wide singleton.
/// </summary>
@@ -236,7 +236,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
/// <summary>
/// The stored revision hash the instance reconcile sweep has already ACTED on for an
/// instance, keyed by instance name — <b>one repair attempt per (instance, revision)
/// pair</b>, for both the row-78 start and the row-72 restart.
/// pair</b>, for both the reconcile-sweep start and the snapshot-driven restart.
/// <para>
/// This is what keeps a periodic self-heal from becoming a restart loop. An instance whose
/// Instance Actor dies during init leaves its config row in place, so without this the
@@ -281,7 +281,6 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
/// <param name="options">Site runtime options (startup batch size, stagger interval, etc.).</param>
/// <param name="logger">Logger instance.</param>
/// <param name="dclManager">Optional Data Connection Layer manager actor.</param>
/// <param name="replicationActor">Optional standby replication actor.</param>
/// <param name="healthCollector">Optional site health collector.</param>
/// <param name="serviceProvider">Optional service provider for resolving per-instance services.</param>
/// <param name="loggerFactory">Optional logger factory for creating Instance Actor loggers.</param>
@@ -295,13 +294,13 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
/// <param name="configLoader">Optional override for loading all deployed configurations
/// at startup; defaults to reading from <paramref name="storage"/>. Primarily for tests.</param>
/// <param name="externalSystemCache">
/// WP2.6a: the shared <see cref="ExternalSystemDefinitionCache"/> backing
/// The shared <see cref="ExternalSystemDefinitionCache"/> backing
/// <c>SiteExternalSystemRepository</c> reads, invalidated after this actor applies
/// external-system changes. Optional/null in tests that do not exercise external-system
/// caching.
/// </param>
/// <param name="scriptScheduler">
/// WP3.1: optional script-execution scheduler override (#18). This actor grows the pool
/// Optional script-execution scheduler override. This actor grows the pool
/// towards <see cref="ScriptExecutionScheduler.ComputeTargetThreads"/> on every instance-
/// count change; null uses the process-wide shared scheduler.
/// </param>
@@ -312,12 +311,12 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
/// drive a read failure.
/// </param>
/// <param name="deployedConfigLoader">
/// Register P1-4: optional override for the single-row deployed-config read the row-67
/// Optional override for the single-row deployed-config read the
/// ensure-started heal uses; defaults to reading from <paramref name="storage"/>. Primarily
/// for tests that need to hold the read open mid-flight to drive the row-101 race.
/// for tests that need to hold the read open mid-flight to drive the freshness race.
/// </param>
/// <param name="secretsMirror">
/// Task 10 (site-secrets artifact deploy): this node's <see cref="DeployedSecretsMirror"/>,
/// This node's <see cref="DeployedSecretsMirror"/>,
/// reconciled synchronously by <see cref="HandleDeployArtifacts"/> right after a shipped
/// <c>command.Secrets</c> set is written to <c>deployed_secrets</c>. Optional/null on
/// nodes/tests that never register secret deployment.
@@ -378,10 +377,10 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
Receive<EnableInstanceCommand>(cmd => HandleEnable(cmd, Sender));
Receive<DeleteInstanceCommand>(cmd => HandleDelete(cmd, Sender));
// WP3.1 warm-then-gate: the off-thread compile warm for a deploy has finished, so
// Warm-then-gate: the off-thread compile warm for a deploy has finished, so
// the (now all-cache-hit) synchronous compile gate can run on the actor thread.
Receive<DeployCompileWarmed>(HandleDeployCompileWarmed);
// WP3.1: a staggered startup batch's compiles have been pre-warmed off-thread;
// A staggered startup batch's compiles have been pre-warmed off-thread;
// create the batch's Instance Actors now that their PreStart compiles are hits.
Receive<BatchCompileWarmed>(msg => CreateInstanceActorBatch(msg.Batch));
@@ -732,7 +731,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
// Rows 89 + 90: seed the DCL arbitration overlay BEFORE any Instance Actor is created,
// so the boot batch's EnsureDclConnections already resolves to the definition-owned
// config. This is the failover half of the row-89 fix: a singleton incarnation starting
// config. This is the failover half of the fix: a singleton incarnation starting
// on the peer node rebuilds the whole DCL from flattened snapshots, and without the
// overlay in place first it would rebuild them STALE and only correct itself a sweep
// tick later — a needless create-then-diverge on every failover.
@@ -764,7 +763,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
if (msg.EnabledConfigs.Count == 0)
{
// Nothing to create, so boot-time creation is trivially complete and the instance
// reconcile sweep may run. This is exactly the row-78 live case: the node booted
// reconcile sweep may run. This is exactly the live case: the node booted
// with an empty deployed_configurations table and CDC replication seeds it moments
// later, with no boot load left to notice.
_startupInstanceCreationComplete = true;
@@ -777,7 +776,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
}
/// <summary>
/// WP3.1: pre-warms one staggered startup batch's script and trigger-expression compiles
/// Pre-warms one staggered startup batch's script and trigger-expression compiles
/// off the actor thread, then pipes <see cref="BatchCompileWarmed"/> so
/// <see cref="CreateInstanceActorBatch"/> can create the batch's Instance Actors with
/// every <c>PreStart</c> compile already a cache hit.
@@ -814,7 +813,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
catch
{
// Best-effort warm — a throw here just means that instance's PreStart
// compiles the hard way, exactly as it did before WP3.1.
// compiles the hard way, exactly as it did before the warm-then-gate change.
}
}
@@ -896,7 +895,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
}
// WP3.1 warm-then-gate. The S3 gate below must stay synchronous on the actor thread
// Warm-then-gate. The S3 gate below must stay synchronous on the actor thread
// (mailbox FIFO is what makes redeploy-supersede and delete-during-redeploy correct),
// but the Roslyn compile it performs used to hold the whole singleton — every OTHER
// instance's commands stalled behind one instance's compile. So the compile is WARMED
@@ -941,7 +940,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
/// <see cref="DeployCompileWarmed"/> back so the authoritative gate can run on the actor
/// thread against a warm cache. The warm is best-effort: its verdict is discarded and any
/// exception swallowed, because <see cref="RunDeployGateAndProceed"/> re-derives the
/// verdict (and reproduces any failure) exactly as it did before WP3.1.
/// verdict (and reproduces any failure) exactly as it did before the warm-then-gate change.
/// </summary>
private void StartDeployCompileWarm(DeployInstanceCommand command)
{
@@ -1044,7 +1043,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
// synchronously on the actor thread as a pure prefix step of the deploy
// application, so the existing redeploy-supersede / delete-during-redeploy
// ordering (which depends on strict mailbox FIFO) is preserved exactly.
// WP3.1 removed the COST rather than the ordering: the same compile has
// The warm-then-gate change removed the COST rather than the ordering: the same compile has
// already been warmed off-thread (StartDeployCompileWarm), so this call is
// pure cache hits and no longer holds the singleton — while the per-instance
// warm guard keeps this instance's own command ordering intact. Redeploys and
@@ -1345,7 +1344,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
// Static overrides and mirrored native alarm state are reset on redeployment per
// design decision — the new config may bind different sources, and the source snapshot
// re-seeds the mirror on (re)subscribe. Dispatched HERE, BEFORE the successor exists,
// and handed to it as a gate (arch-review 2026-08-19 P1-2). It used to run inside the
// and handed to it as a gate. It used to run inside the
// persistence task below, i.e. after the actor was already created AND queued behind a
// full config-JSON write, so the successor's PreStart override load routinely won the
// race and applied the PREDECESSOR's overrides — including keys absent from the new
@@ -1557,7 +1556,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
{
var instanceName = command.InstanceUniqueName;
// WP3.1 warm-then-gate: a deploy for this instance is mid-compile-warm; queue this
// Warm-then-gate: a deploy for this instance is mid-compile-warm; queue this
// command so same-instance ordering is preserved (see TryBufferDuringDeployWarm).
if (TryBufferDuringDeployWarm(instanceName, command, replyTo)) return;
if (DeferLifecycleStop(instanceName, command.CommandId, false, replyTo)) return;
@@ -1567,7 +1566,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
var sender = replyTo;
// Row 101 (initiation half): the actor has just stopped the Instance Actor while the
// durable row still reads enabled, which is exactly the shape the row-78 sweep repairs.
// durable row still reads enabled, which is exactly the shape the reconcile sweep repairs.
// Any store read in flight would therefore "prove" a divergence that does not exist and
// restart the instance the operator just disabled.
BumpStoreWriteGeneration("disable dispatch");
@@ -1617,7 +1616,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
}
// WP3.1 warm-then-gate: see TryBufferDuringDeployWarm.
// Warm-then-gate: see TryBufferDuringDeployWarm.
if (TryBufferDuringDeployWarm(instanceName, command, replyTo)) return;
var sender = replyTo;
@@ -1628,7 +1627,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
Task.Run(async () =>
{
await _storage.SetInstanceEnabledAsync(instanceName, true);
// Row P1-4: a single-row read — this used to materialize every deployed config
// A single-row read — this used to materialize every deployed config
// (including every ConfigJson blob) just to FirstOrDefault this one instance.
var config = await _storage.GetDeployedConfigAsync(instanceName);
return new EnableResult(command, config, null, sender);
@@ -1722,7 +1721,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
var generationAtRead = _storeWriteGeneration;
Task.Run(async () =>
{
// Register P1-4: read a single row through _deployedConfigLoader (defaults to
// Read a single row through _deployedConfigLoader (defaults to
// _storage.GetDeployedConfigAsync — a WHERE instance_unique_name = @name read, not
// the full-table-including-ConfigJson load the boot sequence uses), which still lets
// a test hold the read open and land the result behind a committed disable/delete.
@@ -1821,7 +1820,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
/// <summary>
/// The one place an advisory self-heal turns a stored, enabled config into a running
/// Instance Actor — shared by the row-67 ensure-started handler and the row-78 sweep so
/// Instance Actor — shared by the ensure-started handler and the reconcile sweep so
/// both produce identical bookkeeping and identical operator-facing surfacing. Callers
/// are responsible for the guards; this method assumes they have passed.
/// </summary>
@@ -1915,7 +1914,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
// Row 101, sweep half: this node mutated one of the two tables while the read was in
// flight, so the snapshot predates state the actor has already advanced past. Discard it
// WHOLE — no overlay apply, no row-78 start, no row-72 restart. Every repair this sweep
// WHOLE — no overlay apply, no sweep start, no snapshot restart. Every repair this sweep
// makes is derived from "the store says X, the runtime says Y", and a snapshot older
// than the runtime inverts that comparison: it would restart an instance BACKWARD onto
// the revision a deploy just replaced, or resurrect one a disable/delete just stopped.
@@ -2099,7 +2098,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
{
var instanceName = command.InstanceUniqueName;
// WP3.1 warm-then-gate: see TryBufferDuringDeployWarm.
// Warm-then-gate: see TryBufferDuringDeployWarm.
if (TryBufferDuringDeployWarm(instanceName, command, replyTo)) return;
if (DeferLifecycleStop(instanceName, command.CommandId, true, replyTo)) return;
@@ -2191,7 +2190,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
var sender = Sender;
var instanceName = request.InstanceUniqueName;
// Row P1-4: a single-row, ConfigJson-free projection — this used to materialize every
// A single-row, ConfigJson-free projection — this used to materialize every
// deployed config (including every ConfigJson blob) just to FirstOrDefault this one
// instance's DeploymentId/RevisionHash. Neither is ever read here.
_storage.GetDeployedConfigMetadataAsync(instanceName).ContinueWith(t =>
@@ -2493,13 +2492,13 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
/// <item>DEFINITIONS half: absences "prove" just-applied names disappeared, tombstoning and
/// STOPPING live connections that nothing re-creates until an instance redeploy; rows push
/// superseded configs onto live connections and flip-flop with the next fresh read.</item>
/// <item>CONFIGS half, row-72 leg: a snapshot carrying the revision a deploy has just
/// <item>CONFIGS half, deploy-revision leg: a snapshot carrying the revision a deploy has just
/// replaced makes <see cref="TryRestartStaleInstance"/> "repair" the instance BACKWARD —
/// it redeploys the snapshot's own (old) config JSON through the redeploy path.
/// <see cref="InstanceIsOwnedByADeployPipeline"/> does not cover this: it only holds while
/// the deploy is in flight, and the stale snapshot can land after the pipeline released
/// ownership.</item>
/// <item>CONFIGS half, row-78 leg: a snapshot read before an undeploy/delete or a disable
/// <item>CONFIGS half, stale-snapshot leg: a snapshot read before an undeploy/delete or a disable
/// committed still shows an enabled row while the actor is already stopped, so
/// <see cref="StartStoredInstance"/> RESURRECTS a just-stopped instance.</item>
/// </list>
@@ -2543,7 +2542,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
}
/// <summary>
/// The row-101 freshness test both snapshot consumers run BEFORE touching anything the
/// The freshness test both snapshot consumers run BEFORE touching anything the
/// snapshot carries. <see langword="true"/> means this actor mutated one of the two tables
/// while the read was in flight, so the snapshot predates state the actor has already
/// advanced past and must be discarded whole (see <see cref="_storeWriteGeneration"/> for
@@ -3231,7 +3230,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
Task.Run(async () =>
{
// M2 (final review): the DCL push for this deploy's data connections is captured
// The DCL push for this deploy's data connections is captured
// here and sent only AFTER the shipped secrets are written and mirrored (in the
// finally below), so a connection whose config references a secret this same deploy
// ships resolves it on its FIRST connect instead of failing "not found" and waiting
@@ -3279,7 +3278,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
await _storage.DeleteExternalSystemsExceptAsync(
command.ExternalSystems.Select(es => es.Name).ToList());
// WP2.6a: drop the shared read cache so the next script call sees
// Drop the shared read cache so the next script call sees
// the freshly-applied definitions/method lists instead of a stale
// snapshot loaded before this deploy.
_externalSystemCache?.InvalidateAll();
@@ -3335,7 +3334,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
// artifact bundle. Reconciled removals ride the same
// message so the live DCL connection actor is stopped
// on the actor thread alongside the hash-cache eviction.
// Sent after the secrets step — see pendingDclApply above (M2).
// Sent after the secrets step — see pendingDclApply above.
pendingDclApply = new ApplyArtifactDataConnectionsToDcl(
command.DataConnections, removedConnections);
}
@@ -3343,7 +3342,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
// SMTP configuration is
// central-only and is never stored on a site (see the purge above).
// Site-secrets artifact deploy (Task 10): write the shipped secrets to the
// Site-secrets artifact deploy: write the shipped secrets to the
// replicated deployed_secrets table, then reconcile THIS node's own mirror
// synchronously — the reply's SecretsApplied must reflect this node's own
// apply/verify outcome, not whatever the next periodic pass finds. A null
@@ -3465,7 +3464,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
/// </param>
/// <param name="staticStateResetGate">
/// The deploy path's static-override / native-alarm reset, dispatched BEFORE this call so the
/// new actor's PreStart override load can be ordered after it (arch-review 2026-08-19 P1-2).
/// new actor's PreStart override load can be ordered after it.
/// <see langword="null"/> on every non-deploy start (boot batch, enable, self-heal), where
/// nothing is being reset and the load runs immediately as before.
/// </param>
@@ -3479,13 +3478,13 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
//
// This used to be the caller's job, and only TWO of the four callers did it: the
// boot-time batch and ApplyDeployment. The two self-heal starts did not —
// StartStoredInstance (the shared row-67 ensure-started / row-78 sweep path) and
// StartStoredInstance (the shared ensure-started / reconcile sweep path) and
// HandleEnableResult. Both therefore created an instance whose every tag subscribe was
// answered "Unknown connection: X" by the DCL manager, forever, because nothing else on
// the node would ever create that connection actor:
//
// - Row 85's live symptom (2026-08-16): a replication-seeded deployed_configurations row
// is started by the row-78 sweep, but the connection actor is only ever created as a
// is started by the reconcile sweep, but the connection actor is only ever created as a
// side effect of a deploy or the boot load, so tag subscribes failed for 6+ minutes
// until a second pair restart let the boot load create it.
// - The same defect is reachable with no replication at all: the boot load reads only
@@ -3587,7 +3586,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
internal int InstanceActorCount => _instanceActors.Count;
/// <summary>
/// Updates the health collector with current instance counts, and (WP3.1) grows the
/// Updates the health collector with current instance counts, and grows the
/// script-execution pool to match.
/// Total deployed = _deployedInstanceNames.Count, enabled = running actors, disabled = difference.
/// </summary>
@@ -3598,7 +3597,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
enabled: _instanceActors.Count,
disabled: _deployedInstanceNames.Count - _instanceActors.Count);
// WP3.1: the blocking script pool scales with the number of running instances rather
// The blocking script pool scales with the number of running instances rather
// than sitting at a fixed 8 forever. This is the single call site because it already
// runs on every deploy / undeploy / enable / disable and once per staggered startup
// batch. Growth is idempotent and one-way — see ScriptExecutionScheduler.EnsureCapacity.
@@ -3672,7 +3671,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
List<DeployedInstance> EnabledConfigs, int CompiledCount, int TotalCount);
/// <summary>
/// WP3.1 warm-then-gate: piped back to self once a deployment's scripts have been
/// Warm-then-gate: piped back to self once a deployment's scripts have been
/// compiled off the actor thread into the process-wide compile cache. Carries the exact
/// command instance it warmed so a result superseded mid-warm is recognised by reference
/// and dropped.
@@ -3680,7 +3679,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
internal sealed record DeployCompileWarmed(DeployInstanceCommand Command);
/// <summary>
/// WP3.1: piped back to self once a staggered startup batch's compiles have been
/// Piped back to self once a staggered startup batch's compiles have been
/// pre-warmed, carrying the original batch message so actor creation resumes unchanged.
/// </summary>
internal sealed record BatchCompileWarmed(StartNextBatch Batch);