docs(comments): strip internal task/milestone/bundle bookkeeping from code comments

Remove project bookkeeping citations from shipped code comments across the
solution: hyphenated task IDs (WP-14, StoreAndForward-025), milestone/task/
issue refs (M3, Task 4, Audit Log #23, #21), Bundle X task-bundle labels,
and C/D/K/S/T phase labels.

Comment text only — no code logic, string/log literals, or XML-doc structure
changed. Genuine descriptions are preserved (only the citation is stripped),
and technical lookalikes are retained (UTF-8, SHA-256, T00:00:00, M365,
UTC-5, pre-C4/pre-C5 schema versions). Flagged by the new CommentChecker
TaskReferenceInComment / TrackingReferenceInComment checks plus targeted
grep passes; full solution builds clean, append-only guard tests pass.
This commit is contained in:
Joseph Doherty
2026-07-07 11:03:26 -04:00
parent 67005ca4c0
commit 9cff87fe85
435 changed files with 2338 additions and 2547 deletions
@@ -24,7 +24,7 @@ namespace ZB.MOM.WW.ScadaBridge.Host.Actors;
/// Creates the actor system on start, registers actors, and triggers
/// CoordinatedShutdown on stop.
///
/// WP-3: Transport heartbeat is explicitly configured in HOCON from CommunicationOptions.
/// Transport heartbeat is explicitly configured in HOCON from CommunicationOptions.
/// </summary>
public class AkkaHostedService : IHostedService
{
@@ -39,7 +39,7 @@ public class AkkaHostedService : IHostedService
/// Guards the one-time creation of <see cref="_actorSystem"/> in
/// <see cref="GetOrCreateActorSystem"/> so <see cref="StartAsync"/> and a concurrent
/// health-probe resolution of the DI <see cref="ActorSystem"/> singleton race to create
/// it exactly once (HOST-021).
/// it exactly once.
/// </summary>
private readonly object _actorSystemLock = new();
/// <summary>
@@ -51,14 +51,14 @@ public class AkkaHostedService : IHostedService
private readonly List<IDisposable> _trackedDisposables = new();
/// <summary>
/// NotificationService-020 guard: sentinel that flips to <c>true</c> the
/// Sentinel that flips to <c>true</c> the
/// first time a Notification-category S&amp;F delivery handler is registered
/// on this hosted service instance. <see cref="StoreAndForwardService.RegisterDeliveryHandler"/>
/// is last-write-wins on category, so a future code change that introduces
/// a second registration path (e.g. a role-branch + helper that both call
/// the registration) would silently overwrite the canonical
/// <c>NotificationForwarder</c> handler with whatever the loser registers —
/// the prior NS-001 fix did exactly this, and was silently superseded
/// a prior fix did exactly this, and was silently superseded
/// when the central-only redesign moved delivery to <c>NotificationOutbox</c>.
/// This sentinel makes the duplicate noisy at startup so a maintainer
/// re-introducing the second path sees it immediately.
@@ -99,7 +99,7 @@ public class AkkaHostedService : IHostedService
/// <returns>A task representing the asynchronous operation.</returns>
public async Task StartAsync(CancellationToken cancellationToken)
{
// HOST-021: create (or reuse) the externally-owned, process-singleton ActorSystem. A
// Create (or reuse) the externally-owned, process-singleton ActorSystem. A
// health probe may already have created it via the DI singleton bridge
// (GetOrCreateActorSystem) before this hosted service's StartAsync ran; either way the
// call yields the one instance and sets _actorSystem. Actor registration below then
@@ -132,7 +132,7 @@ public class AkkaHostedService : IHostedService
/// whichever runs first creates the system exactly once.
/// </summary>
/// <remarks>
/// HOST-021: the <see cref="ActorSystem"/> is an externally-owned process singleton — its
/// The <see cref="ActorSystem"/> is an externally-owned process singleton — its
/// lifecycle is this hosted service's (created here, torn down via
/// <c>CoordinatedShutdown</c> in <see cref="StopAsync"/>). It MUST be registered in DI as a
/// <b>singleton resolved through this method</b>, never as a transient/scoped factory:
@@ -165,7 +165,7 @@ public class AkkaHostedService : IHostedService
// For site nodes, include a site-specific role (e.g., "site-SiteA") alongside the base role
var roles = BuildRoles();
// Host-006: HOCON is assembled in a dedicated builder that quotes/escapes every
// HOCON is assembled in a dedicated builder that quotes/escapes every
// interpolated value, so a hostname, seed node or strategy containing a quote,
// backslash or whitespace cannot corrupt the configuration document.
var hocon = BuildHocon(_nodeOptions, _clusterOptions, roles,
@@ -195,13 +195,13 @@ public class AkkaHostedService : IHostedService
/// Builds the Akka HOCON configuration document. Every interpolated value is
/// routed through <see cref="QuoteHocon"/> (string values) so a hostname,
/// seed-node URI, role or split-brain strategy containing a quote, backslash or
/// whitespace cannot corrupt the document or be silently misparsed (Host-006).
/// whitespace cannot corrupt the document or be silently misparsed.
///
/// Host-012: the <c>keep-oldest down-if-alone</c> flag is emitted from
/// The <c>keep-oldest down-if-alone</c> flag is emitted from
/// <see cref="ClusterOptions.DownIfAlone"/> rather than hard-coded, so the bound
/// configuration value is actually consumed.
///
/// Host-013: every duration is rendered via <see cref="DurationHocon"/> in
/// Every duration is rendered via <see cref="DurationHocon"/> in
/// milliseconds, so sub-second cluster timing values (e.g. a 750ms heartbeat) are
/// preserved exactly instead of being rounded to whole seconds.
/// </summary>
@@ -275,7 +275,7 @@ akka {{
/// HOCON parser accepts a <c>ms</c> suffix, so emitting whole milliseconds
/// preserves sub-second configuration exactly — a 750ms heartbeat stays 750ms
/// rather than being rounded to <c>1s</c> (or, for sub-half-second values,
/// silently collapsing to a degenerate <c>0s</c>) — Host-013.
/// silently collapsing to a degenerate <c>0s</c>).
/// </summary>
private static string DurationHocon(TimeSpan duration)
{
@@ -354,7 +354,7 @@ akka {{
/// <summary>
/// Registers central-side actors including the CentralCommunicationActor.
/// WP-4: Central communication actor routes all 8 message patterns to sites.
/// Central communication actor routes all 8 message patterns to sites.
/// </summary>
private void RegisterCentralActors()
{
@@ -400,7 +400,7 @@ akka {{
.GetRequiredService<IOptions<ZB.MOM.WW.ScadaBridge.NotificationOutbox.NotificationOutboxOptions>>().Value;
var outboxLogger = _serviceProvider.GetRequiredService<ILoggerFactory>()
.CreateLogger<ZB.MOM.WW.ScadaBridge.NotificationOutbox.NotificationOutboxActor>();
// M4 Bundle B: central direct-write audit writer for dispatcher attempt
// Central direct-write audit writer for dispatcher attempt
// + terminal events. Resolved once from the root provider — the writer
// is a singleton and stateless, opening per-call DI scopes internally
// to resolve the scoped IAuditLogRepository.
@@ -433,12 +433,12 @@ akka {{
commService?.SetNotificationOutbox(outboxProxy);
_logger.LogInformation("NotificationOutbox singleton created and registered with CentralCommunicationActor");
// Audit Log (#23) — central singleton mirrors the Notification Outbox
// Audit Log — central singleton mirrors the Notification Outbox
// pattern. The IngestAuditEvents gRPC handler lives on SiteStreamGrpcServer
// (Communication.Grpc); a central node hosting that server (M6 reconciliation
// (Communication.Grpc); a central node hosting that server (reconciliation
// path) hands the proxy in via SetAuditIngestActor below. When the gRPC
// server is not registered (current central topology), the host still
// brings the singleton up so a Bundle H in-process test (or a future
// brings the singleton up so an in-process test (or a future
// direct caller) can Ask the proxy without further wiring.
// IAuditLogRepository is a SCOPED EF Core service, so the singleton
// actor takes the root IServiceProvider and creates a fresh scope per
@@ -471,15 +471,15 @@ akka {{
// Hand the proxy to the SiteStreamGrpcServer (if registered on this node)
// so the IngestAuditEvents RPC routes incoming site batches to the singleton.
// The gRPC server is currently only registered on Site nodes; on a central
// node this resolves to null and the wiring is a no-op until M6 (which
// brings central-hosted gRPC + a real site→central client).
// node this resolves to null and the wiring is a no-op unless a future
// central-hosted gRPC server (or a real site→central client) is added.
var grpcServer = _serviceProvider.GetService<ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamGrpcServer>();
grpcServer?.SetAuditIngestActor(auditIngestProxy);
_logger.LogInformation(
"AuditLogIngestActor singleton created (gRPC server bound: {GrpcBound})",
grpcServer is not null);
// Audit Log (#23) M6 Bundle E (T7): subscribe the per-site stalled
// Subscribe the per-site stalled
// telemetry tracker to the actor system EventStream NOW that the
// system exists. The tracker mirrors every
// SiteAuditTelemetryStalledChanged publication (from
@@ -504,11 +504,11 @@ akka {{
_logger.LogInformation("SiteAuditTelemetryStalledTracker subscribed to EventStream");
}
// Site Call Audit (#22) — central singleton mirrors the AuditLogIngest
// and NotificationOutbox patterns. M3's dual-write transaction routes
// Site Call Audit — central singleton mirrors the AuditLogIngest
// and NotificationOutbox patterns. The dual-write transaction routes
// SiteCalls upserts through AuditLogIngestActor's own scope-per-message
// ISiteCallAuditRepository resolution, so this singleton is not on the
// M3 happy-path hot path; it exists so direct-write callers Ask through
// happy-path hot path; it exists so direct-write callers Ask through
// a stable cluster proxy without further wiring. The central→site
// Retry/Discard relay now lives in this actor (see the
// RegisterCentralCommunication wiring below); the reconciliation puller
@@ -532,12 +532,12 @@ akka {{
var siteCallAuditSingletonManager =
_actorSystem!.ActorOf(siteCallAuditSingletonProps, "site-call-audit-singleton");
// SiteCallAudit-002 graceful-handover hook. The default singleton handover
// Graceful-handover hook. The default singleton handover
// path waits for the actor's `ReceiveAsync` task to complete before
// signalling `HandOverDone` to the new oldest node — so an in-flight
// EF `UpsertAsync` IS waited for during a *clean* coordinated shutdown
// (the cluster-leave phase below fires before the singleton terminates).
// The risk the finding tracks is the seam between in-flight async work
// The risk here is the seam between in-flight async work
// and the cluster-leave + singleton-stop sequence: we bound it by
// issuing an explicit `GracefulStop` to the singleton manager early
// in `cluster-leave`, with a timeout that lets the running upsert + SQL
@@ -546,7 +546,7 @@ akka {{
// coordinated shutdown indefinitely — exceeding it falls through to
// the existing PoisonPill termination path. Same pattern is suitable
// for the NotificationOutbox singleton; not added here to keep this
// change minimal (out of NS-020's scope).
// change minimal.
var siteCallAuditShutdown = Akka.Actor.CoordinatedShutdown.Get(_actorSystem);
siteCallAuditShutdown.AddTask(
Akka.Actor.CoordinatedShutdown.PhaseClusterLeave,
@@ -577,7 +577,7 @@ akka {{
// SetNotificationOutbox wiring above.
commService?.SetSiteCallAudit(siteCallAuditProxy);
// Task 5 (#22): hand the CentralCommunicationActor to the SiteCallAudit
// Hand the CentralCommunicationActor to the SiteCallAudit
// actor so it can relay operator Retry/Discard on parked cached calls to
// the owning site (over the per-site ClusterClient via SiteEnvelope).
// Mirrors the RegisterAuditIngest / RegisterNotificationOutbox wiring;
@@ -588,7 +588,7 @@ akka {{
_logger.LogInformation(
"SiteCallAuditActor singleton created and registered with CentralCommunicationActor");
// Audit Log (#23) M6 Bundle B/C — start the two central-only maintenance
// Start the two central-only maintenance
// singletons that were fully implemented but never instantiated: the
// daily AuditLog partition-switch purge (AuditLogPurgeActor) and the
// periodic per-site audit-event reconciliation pull
@@ -699,7 +699,7 @@ akka {{
_actorSystem.ActorOf(auditReconProxyProps, "site-audit-reconciliation-proxy");
_logger.LogInformation("SiteAuditReconciliationActor singleton created");
// KPI History (#26, M6) — central singleton that periodically samples the
// KPI History — central singleton that periodically samples the
// Notification Outbox / Site Call Audit point-in-time KPIs into the
// KpiHistorySamples table and runs the daily retention purge. Mirrors the
// audit-log-purge singleton pattern above: a ClusterSingletonManager pins
@@ -832,7 +832,7 @@ akka {{
var dmLogger = _serviceProvider.GetRequiredService<ILoggerFactory>()
.CreateLogger<DeploymentManagerActor>();
// WP-34: Create DCL Manager Actor for tag subscriptions
// Create DCL Manager Actor for tag subscriptions
var dclFactory = _serviceProvider.GetService<ZB.MOM.WW.ScadaBridge.DataConnectionLayer.IDataConnectionFactory>();
var dclOptions = _serviceProvider.GetService<IOptions<ZB.MOM.WW.ScadaBridge.DataConnectionLayer.DataConnectionOptions>>()?.Value
?? new ZB.MOM.WW.ScadaBridge.DataConnectionLayer.DataConnectionOptions();
@@ -841,7 +841,7 @@ akka {{
{
var healthCollector = _serviceProvider.GetRequiredService<ZB.MOM.WW.ScadaBridge.HealthMonitoring.ISiteHealthCollector>();
var siteEventLogger = _serviceProvider.GetService<ZB.MOM.WW.ScadaBridge.SiteEventLogging.ISiteEventLogger>();
// T17: the verify-endpoint probe builds an OPC UA ApplicationConfiguration directly,
// The verify-endpoint probe builds an OPC UA ApplicationConfiguration directly,
// so the manager needs the same deployment-wide OpcUaGlobalOptions the
// DataConnectionFactory feeds to RealOpcUaClient when creating connections.
var opcUaGlobalOptions = _serviceProvider
@@ -854,7 +854,7 @@ akka {{
_logger.LogInformation("Data Connection Layer manager actor created");
}
// T17 / D6 — per-node OPC UA certificate-store actor. Created on EVERY
// Per-node OPC UA certificate-store actor. Created on EVERY
// site node (NOT a singleton) at a well-known name so the Deployment
// Manager singleton can fan a trust/remove out to BOTH nodes' PKI stores
// (node-a + node-b) and keep them in lock-step across failover. It needs
@@ -875,7 +875,7 @@ akka {{
// Notify-and-fetch: the deployment config fetcher pulls a deployment's flattened
// config from central over HTTP. Used by BOTH the active singleton
// (RefreshDeploymentCommand, Task 10) AND the standby replication path — the active
// (RefreshDeploymentCommand) AND the standby replication path — the active
// node now replicates only the deployment id and the standby fetches the config
// itself, so a large config never crosses the intra-site Akka hop. Resolve once.
var deploymentConfigFetcher =
@@ -933,7 +933,7 @@ akka {{
var dmProxy = _actorSystem.ActorOf(proxyProps, "deployment-manager-proxy");
// WP-4: Create SiteCommunicationActor for receiving messages from central
// Create SiteCommunicationActor for receiving messages from central
var siteCommActor = _actorSystem.ActorOf(
Props.Create(() => new SiteCommunicationActor(
_nodeOptions.SiteId!,
@@ -974,7 +974,7 @@ akka {{
if (storeAndForwardService != null)
{
// Initialize SQLite schema and start the retry timer. Must complete before
// any actor or HTTP handler touches the service. Host-005: awaited rather
// any actor or HTTP handler touches the service. Awaited rather
// than blocked via GetAwaiter().GetResult() — no thread-pool starvation /
// sync-context deadlock risk, and exceptions surface as their original type.
cancellationToken.ThrowIfCancellationRequested();
@@ -1010,9 +1010,9 @@ akka {{
// NotificationSubmitAck as the outcome (accepted → delivered; not accepted
// or timeout → throw → transient → keep buffering). Central owns SMTP.
//
// NotificationService-020: register exactly once. The sentinel guard
// Register exactly once. The sentinel guard
// catches a second registration path that re-introduces the dead
// NS-001 site-SMTP handler — see the sentinel's XML doc above for the
// site-SMTP handler — see the sentinel's XML doc above for the
// historical context. Throwing here is intentional: a silent overwrite
// by a future maintainer would invert the design back to site-side
// delivery (NotificationForwarder vs. NotificationDeliveryService).
@@ -1070,7 +1070,7 @@ akka {{
contacts.Count, _nodeOptions.SiteId);
}
// Task 18c — per-node startup reconciliation. Created on EVERY site node (NOT a
// Per-node startup reconciliation. Created on EVERY site node (NOT a
// singleton) so a standby that was DOWN during a deploy self-heals on its next
// restart: it reports its local deployed inventory to central via the
// SiteCommunicationActor Ask, fetches the gap (missing/stale) over HTTP, and
@@ -1103,7 +1103,7 @@ akka {{
+ "startup self-heal disabled (replication remains the primary path)");
}
// Audit Log (#23) — site-side telemetry actor that drains the SQLite
// Audit Log — site-side telemetry actor that drains the SQLite
// Pending queue and pushes to central via IngestAuditEvents. Not a
// cluster singleton: each site is its own cluster, and the actor reads
// node-local SQLite (no replication). The Props are bound to the
@@ -1111,7 +1111,7 @@ akka {{
// batch SQLite read + gRPC push never contend with the default
// dispatcher used by hot-path actors.
//
// Per Bundle E's brief: the SiteAuditTelemetryActor takes its
// The SiteAuditTelemetryActor takes its
// collaborators through its constructor, so we resolve them from DI
// and pass them in via Props.Create rather than relying on a future
// FactoryProvider. The real site→central client is constructed and
@@ -1122,7 +1122,7 @@ akka {{
.GetRequiredService<IOptions<ZB.MOM.WW.ScadaBridge.AuditLog.Site.Telemetry.SiteAuditTelemetryOptions>>();
var siteAuditQueue = _serviceProvider
.GetRequiredService<ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services.ISiteAuditQueue>();
// Audit Log (#23) Task 2 follow-up: the production site→central audit
// Audit Log follow-up: the production site→central audit
// push uses the ClusterClient transport via the SiteCommunicationActor,
// not the DI-resolved NoOpSiteStreamAuditClient. The NoOp default stays
// correct for central/test composition roots (no SiteCommunicationActor);
@@ -1137,7 +1137,7 @@ akka {{
var siteAuditLogger = _serviceProvider.GetRequiredService<ILoggerFactory>()
.CreateLogger<ZB.MOM.WW.ScadaBridge.AuditLog.Site.Telemetry.SiteAuditTelemetryActor>();
// AuditLog-001: resolve the site-local operation tracking store so the
// Resolve the site-local operation tracking store so the
// actor can run the combined-telemetry cached-drain in parallel with
// the audit-only drain. The store is registered by AddSiteRuntime on
// site composition roots; on central it is intentionally absent and
@@ -1162,9 +1162,9 @@ akka {{
siteTrackingStore is not null);
// Gate gRPC subscriptions until the actor system and SiteStreamManager are
// initialized (REQ-HOST-7).
// initialized.
//
// Host-009: SetReady asserts a deliberately narrow contract. By this point the
// SetReady asserts a deliberately narrow contract. By this point the
// actor system exists, SiteStreamManager.Initialize has run, and every
// role actor (SiteCommunicationActor, deployment-manager singleton,
// SiteReplicationActor, the ClusterClient) has been created with ActorOf —
@@ -1178,14 +1178,14 @@ akka {{
// handshake has completed". Streams opened before SetReady are already
// rejected by SiteStreamGrpcServer with StatusCode.Unavailable.
var grpcServer = _serviceProvider.GetService<ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamGrpcServer>();
// Audit Log (#23 M6): hand the site-local SqliteAuditWriter (which
// Audit Log: hand the site-local SqliteAuditWriter (which
// implements ISiteAuditQueue) to the gRPC server so the PullAuditEvents
// reconciliation RPC can serve central's pulls. Both the writer and the
// gRPC server are singletons — wiring this here keeps the dependency
// direction one-way (Host knows both; Communication doesn't reach back
// into AuditLog).
grpcServer?.SetSiteAuditQueue(siteAuditQueue);
// Site Call Audit (#22): hand the site-local OperationTrackingStore to
// Site Call Audit: hand the site-local OperationTrackingStore to
// the gRPC server so the PullSiteCalls reconciliation RPC can serve
// central's self-heal pulls. siteTrackingStore is resolved above with
// GetService — present on site composition roots, null on central — so