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
+16 -16
View File
@@ -57,7 +57,7 @@ using ZB.MOM.WW.Secrets.DependencyInjection;
using ZB.MOM.WW.Secrets.Replicator.AkkaDotNet;
using ZB.MOM.WW.Secrets.Sqlite;
// #618 — the composition root runs inside one try/catch (not re-indented, to keep the diff reviewable)
// the composition root runs inside one try/catch (not re-indented, to keep the diff reviewable)
// so ANY failure to start — an unknown role, a ValidateOnStart rejection, a hosted service that
// throws from StartAsync — is logged Fatal, flushed, and ends the process with a NON-ZERO exit code.
// Left as an unhandled exception the host could stay up as a zombie under a supervisor/container
@@ -68,7 +68,7 @@ try
var builder = WebApplication.CreateBuilder(args);
// The SINGLE role authority: Cluster:Roles first, OTOPCUA_ROLES as the fallback (archreview
// 01/S-12 = 03/C5, R3-04). Resolved off builder.Configuration BEFORE the per-role overlay is
// 01/S-12 = 03/C5). Resolved off builder.Configuration BEFORE the per-role overlay is
// added, because the overlay's FILENAME depends on the answer — which is why a role overlay may
// not itself set Cluster:Roles (AkkaClusterOptionsValidator fails start if one ever does).
// EffectiveRoles drives the entire conditional wiring below — see ZB.MOM.WW.OtOpcUa.Cluster.
@@ -91,7 +91,7 @@ builder.Host.UseWindowsService(options => options.ServiceName = "OtOpcUaHost");
// Per-role appsettings overlay: appsettings.{role}.json (single role) or appsettings.admin-driver.json
// (both). Optional — base appsettings.json carries enough to boot if these don't exist. Built from the
// PLAIN roles only (#678.6): a cluster-{ClusterId} role in the name pointed at a file that never exists.
// PLAIN roles only: a cluster-{ClusterId} role in the name pointed at a file that never exists.
var roleSuffix = RoleOverlay.Suffix(roles);
if (roleSuffix is not null)
{
@@ -142,7 +142,7 @@ await using (var secretsProvider = new ServiceCollection()
// untouched. UseWindowsService already roots the content root at the base dir, so this only affects sinks.
Directory.SetCurrentDirectory(AppContext.BaseDirectory);
// #561 — Serilog SelfLog to logs/serilog-selflog.txt + stderr, enabled before the first logger
// Serilog SelfLog to logs/serilog-selflog.txt + stderr, enabled before the first logger
// builds. Serilog isolates per-sink failures, so a file sink whose writes fail leaves a 0-byte
// log and a healthy process with no signal anywhere; SelfLog is the only channel that sees the
// swallowed exception. Placed after the CWD anchor above so the relative path lands in the
@@ -159,14 +159,14 @@ builder.AddZbSerilog(o => o.ServiceName = "otopcua");
// ConfigDb is admin-only now (per-cluster mesh Phase 4). Only the admin role owns a ConfigDb
// connection string; a driver-only node holds none at all and gets its deployed configuration from
// central over the Phase-3 fetch-and-cache path (ConfigSource:Mode=FetchAndCache). Registering it
// central over the fetch-and-cache path (ConfigSource:Mode=FetchAndCache). Registering it
// unconditionally would throw on a driver-only node, since AddOtOpcUaConfigDb requires the string.
// A fused admin+driver node keeps ConfigDb via its admin role — byte-for-byte unaffected.
// #520 — bound unconditionally: a driver node needs the pepper to VERIFY keys, an admin node needs it
// bound unconditionally: a driver node needs the pepper to VERIFY keys, an admin node needs it
// to MINT them, and getting this wrong on either side is a silent authentication failure rather than a
// startup error.
builder.Services.Configure<ApiKeyOptions>(builder.Configuration.GetSection(ApiKeyOptions.SectionName));
// #520 stage 5 — Security:Acl:Enabled. Default false; see AclOptions for why the flip must be a config
// Security:Acl:Enabled. Default false; see AclOptions for why the flip must be a config
// change rather than a redeploy, and what it swaps rather than adds.
builder.Services.Configure<AclOptions>(builder.Configuration.GetSection(AclOptions.SectionName));
@@ -327,7 +327,7 @@ if (hasDriver)
builder.Services.AddSingleton<IHistorianValueWriter>(sp => sp.GetRequiredService<IHistorianBackendProvider>().CreateValueWriter(sp));
}
// Historian retention (#667). Only a backend that manages retention in-process returns a purger
// Historian retention. Only a backend that manages retention in-process returns a purger
// (SqlServer with RetentionDays set); otherwise the service is inert. Primary-gated via IHistorizationRoleView.
if (serverHistorianOptions.Enabled)
builder.Services.AddHostedService(sp => new HistorianRetentionService(
@@ -402,11 +402,11 @@ if (hasDriver)
builder.Services.TryAddScoped<ILdapGroupRoleMappingService, NullLdapGroupRoleMappingService>();
builder.Services.TryAddScoped<IGroupRoleMapper<string>, OtOpcUaGroupRoleMapper>();
// #520 stage 2 — the OPC UA DATA PLANE is machine-to-machine, so its identity is an API key
// the OPC UA DATA PLANE is machine-to-machine, so its identity is an API key
// (static username "apikey", the otua_ credential as the password), not an LDAP user. The LDAP
// registrations above are deliberately retained: they back ADMINUI LOGIN, which keeps LDAP.
// Only IOpcUaUserAuthenticator moves.
// #520 stage 4 — the node's data-plane authorization inputs (keys + ACL grants + cluster + auth
// the node's data-plane authorization inputs (keys + ACL grants + cluster + auth
// generation), refreshed by OpcUaPublishActor from every applied artifact. Registered on any
// driver-role node because that is what serves an OPC UA data plane; the two interfaces resolve to
// the SAME instance, since the writer and the readers must see one snapshot.
@@ -416,7 +416,7 @@ if (hasDriver)
builder.Services.AddSingleton<IDataPlaneAuthoritySource>(sp => sp.GetRequiredService<DataPlaneAuthorityState>());
builder.Services.AddSingleton<IDataPlaneAuthoritySink>(sp => sp.GetRequiredService<DataPlaneAuthorityState>());
// #520 stage 5 — the tries the ACL gate evaluates against are taken FROM the authority state, not
// the tries the ACL gate evaluates against are taken FROM the authority state, not
// registered independently. The state builds the trie inside the same Apply() call that installs
// the snapshot, so resolving any other cache here would hand the evaluator a permanently empty
// one — and an empty trie denies everything, which looks exactly like "the ACLs are working" until
@@ -437,7 +437,7 @@ if (hasDriver)
builder.Services.AddSingleton<PermissionTrieCache>();
}
// #520 + arch-review 03/S18 — the node-scoped ACL gate, the shared clock and the role-appropriate
// The node-scoped ACL gate, the shared clock and the role-appropriate
// API-key store + user authenticator, all in one extension so the role-conditional branches are
// reachable from a test (Program.cs's top-level statements are not). See DataPlaneAuthRegistration.
builder.Services.AddOtOpcUaDataPlaneAuth(hasAdmin, hasDriver);
@@ -501,7 +501,7 @@ builder.Services.AddHostedService(sp => new ClusterBootstrapCoordinator(
sp.GetRequiredService<IOptions<AkkaClusterOptions>>(),
sp.GetRequiredService<ILogger<ClusterBootstrapCoordinator>>()));
// Down-if-alone recovery watchdog (#459). Registered AFTER AddAkka so it starts after Akka's own
// Down-if-alone recovery watchdog. Registered AFTER AddAkka so it starts after Akka's own
// hosted service has built the ActorSystem; it resolves the system lazily (never at construction) so
// it can't race startup. On an unexpected SBR self-down it stops the host so the service supervisor
// (sc.exe failure / docker restart: unless-stopped) restarts this node — the 2-node keep-oldest
@@ -748,14 +748,14 @@ Log.Information(
"OtOpcUa.Host starting with roles=[{Roles}] (admin={HasAdmin}, driver={HasDriver}) source={Source}",
string.Join(",", roles), hasAdmin, hasDriver, effectiveRoles.Source);
// R3-04 choice 5: Cluster:Roles and OTOPCUA_ROLES set to different normalized role sets is almost
// Cluster:Roles and OTOPCUA_ROLES set to different normalized role sets is almost
// certainly not what the operator intended (Cluster:Roles still wins outright — this is
// observability, not a behaviour change). Logged here rather than inside the static factory because
// Serilog is not configured yet when EffectiveRoles.Resolve runs at the top of this file.
if (effectiveRoles.DisagreementWarning is not null)
Log.Warning("{Warning}", effectiveRoles.DisagreementWarning);
// #561 — startup growth self-check: the banner above went through the live pipeline; verify each
// startup growth self-check: the banner above went through the live pipeline; verify each
// configured file sink physically grew. A sink whose writes silently fail (the wonder-app-vd03
// 0-byte-log incident) is reported at boot — through SelfLog + stderr, which don't depend on the
// broken sink, and through the normal logger for the console sink's benefit.
@@ -770,7 +770,7 @@ await app.RunAsync();
}
// HostAbortedException is how design-time tooling (EF `dotnet ef … --startup-project`, OpenAPI generators —
// HostFactoryResolver) stops Program once it has the built host. It is not a failure: letting it reach the
// Fatal + Environment.Exit(1) below would kill the tool's own process (#618, review R1 m5).
// Fatal + Environment.Exit(1) below would kill the tool's own process.
catch (Exception ex) when (ex is not HostAbortedException)
{
// Log.Logger is still the silent bootstrap logger when the failure happened before AddZbSerilog