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:
@@ -21,8 +21,8 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||
/// is hit the service appends a <c># Capped at … rows. Use the CLI for larger
|
||||
/// exports.</c> footer line so an operator can tell a truncated download from
|
||||
/// a complete one. The header row contains the same 24 columns, in the same
|
||||
/// order, as the ManagementService CLI's CSV export (arch-review 2026-08-19
|
||||
/// P6-7 — the two CSV writers were found to have drifted and are kept aligned).
|
||||
/// order, as the ManagementService CLI's CSV export (the two CSV writers
|
||||
/// had drifted and are kept aligned).
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public interface IAuditLogExportService
|
||||
@@ -162,7 +162,7 @@ public sealed class AuditLogExportService : IAuditLogExportService
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// CSV helpers — 24 columns, kept aligned with the ManagementService CLI's
|
||||
// CSV export (arch-review 2026-08-19 P6-7)
|
||||
// CSV export
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>The 24 column names, in <see cref="AuditEventView"/> declaration order.</summary>
|
||||
@@ -179,8 +179,7 @@ public sealed class AuditLogExportService : IAuditLogExportService
|
||||
/// cleanly on another. Free-text columns are run through
|
||||
/// <see cref="NeedsFormulaNeutralization"/> before RFC 4180 quoting so a
|
||||
/// leading <c>=</c>/<c>+</c>/<c>-</c>/<c>@</c>/TAB/CR can't be interpreted as
|
||||
/// a formula or DDE trigger by a spreadsheet application (CWE-1236;
|
||||
/// arch-review 2026-08-19 P6-7). GUID/enum/numeric/date/bool columns this
|
||||
/// a formula or DDE trigger by a spreadsheet application (CWE-1236). GUID/enum/numeric/date/bool columns this
|
||||
/// formatter generates itself are never neutralized.
|
||||
/// </summary>
|
||||
/// <param name="evt">The audit event view to format as a CSV row.</param>
|
||||
|
||||
@@ -70,6 +70,7 @@ public sealed class AuditLogQueryService : IAuditLogQueryService
|
||||
/// </summary>
|
||||
/// <param name="scopeFactory">Factory used to open a fresh DI scope per query.</param>
|
||||
/// <param name="healthAggregator">Central health aggregator for KPI backlog data.</param>
|
||||
/// <param name="auth">Optional authentication state provider used to resolve the current user.</param>
|
||||
public AuditLogQueryService(
|
||||
IServiceScopeFactory scopeFactory,
|
||||
ICentralHealthAggregator healthAggregator, AuthenticationStateProvider? auth = null)
|
||||
|
||||
@@ -8,10 +8,13 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||
public sealed class AuthorizedManualFailoverService(AuthenticationStateProvider auth, IManualFailoverService backend)
|
||||
{
|
||||
/// <summary>Fails over central only for a currently authorized administrator.</summary>
|
||||
/// <returns>The failover outcome message, or <c>null</c> when none was reported.</returns>
|
||||
public async Task<string?> FailOverCentralAsync()
|
||||
=> await backend.FailOverCentralAsync(await auth.RequireRoleAsync(Roles.Administrator));
|
||||
|
||||
/// <summary>Fails over a site only for a currently authorized administrator.</summary>
|
||||
/// <param name="siteId">The site identifier to fail over.</param>
|
||||
/// <returns>The outcome of the site failover.</returns>
|
||||
public async Task<SiteFailoverOutcome> FailOverSiteAsync(string siteId)
|
||||
=> await backend.FailOverSiteAsync(siteId, await auth.RequireRoleAsync(Roles.Administrator));
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ public enum BindingConnectionState { None, Single, Mixed }
|
||||
/// <summary>A member of a <see cref="BindingGroup"/>: the row plus its tail relative to the group.</summary>
|
||||
public sealed record BindingGroupMember(BindingRow Row, string MemberTail)
|
||||
{
|
||||
/// <summary>True when the row has no bound (or a non-positive) connection id.</summary>
|
||||
public bool IsUnbound => Row.ConnectionId is null or <= 0;
|
||||
/// <summary>Effective reference: override if set, else the default.</summary>
|
||||
public string? EffectiveReference => string.IsNullOrWhiteSpace(Row.Override) ? Row.DefaultReference : Row.Override;
|
||||
@@ -32,6 +33,7 @@ public sealed record BindingGroup(
|
||||
int? CommonConnectionId,
|
||||
int UnboundCount)
|
||||
{
|
||||
/// <summary>True when this group holds the instance's direct (non-module) attributes.</summary>
|
||||
public bool IsInstanceGroup => Key == BindingGroupBuilder.InstanceGroupKey;
|
||||
}
|
||||
|
||||
@@ -44,12 +46,14 @@ public static class BindingGroupBuilder
|
||||
{
|
||||
public const string InstanceGroupKey = "(instance)";
|
||||
|
||||
/// <summary>Groups the data-sourced rows by module and infers each group's shared connection and object prefix.</summary>
|
||||
/// <param name="rows">The data-sourced flattened attributes with their current binding state.</param>
|
||||
/// <param name="knownConnectionIds">
|
||||
/// The site's data connection ids. When supplied, a row whose connection id is not
|
||||
/// in the set is treated as UNBOUND — a binding to a deleted connection renders as
|
||||
/// "— none —" and the deploy gate rejects it, so the pills must agree.
|
||||
/// </param>
|
||||
/// <returns>One <see cref="BindingGroup"/> per module (or the instance group).</returns>
|
||||
public static IReadOnlyList<BindingGroup> Build(IEnumerable<BindingRow> rows, IReadOnlyCollection<int>? knownConnectionIds = null)
|
||||
{
|
||||
if (knownConnectionIds is not null)
|
||||
@@ -153,6 +157,10 @@ public static class BindingGroupBuilder
|
||||
/// Save path is an upsert and a removal could not persist anyway. Surrounding
|
||||
/// whitespace and a trailing '.' are tolerated.
|
||||
/// </summary>
|
||||
/// <param name="group">The group whose members are rewritten.</param>
|
||||
/// <param name="connectionId">The connection to bind, or null to keep each member's current connection.</param>
|
||||
/// <param name="objectPath">The object path prefix, or blank to clear the overrides.</param>
|
||||
/// <returns>One change per group member.</returns>
|
||||
public static IReadOnlyList<BindingChange> ApplyObject(BindingGroup group, int? connectionId, string? objectPath)
|
||||
{
|
||||
var obj = (objectPath ?? string.Empty).Trim().TrimEnd('.');
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||
public sealed class ConfigurationCommandService(IServiceProvider services, AuthenticationStateProvider auth)
|
||||
{
|
||||
/// <summary>Runs an existing audited instance operation with fresh scope and an atomic audit commit.</summary>
|
||||
/// <typeparam name="T">The result type of the operation.</typeparam>
|
||||
/// <param name="instanceId">The existing instance id, or null when creating.</param>
|
||||
/// <param name="createSiteId">The target site id when creating an instance.</param>
|
||||
/// <param name="operation">The operation to run, given the instance service and the acting username.</param>
|
||||
/// <returns>The operation's result.</returns>
|
||||
public async Task<T> ExecuteInstanceAsync<T>(int? instanceId, int? createSiteId,
|
||||
Func<ZB.MOM.WW.ScadaBridge.TemplateEngine.Services.InstanceService, string, Task<T>> operation)
|
||||
{
|
||||
@@ -36,6 +41,8 @@ public sealed class ConfigurationCommandService(IServiceProvider services, Authe
|
||||
}
|
||||
|
||||
/// <summary>Executes one command through the same guarded boundary as the management actor.</summary>
|
||||
/// <param name="command">The configuration command to execute.</param>
|
||||
/// <returns>The command's result, if any.</returns>
|
||||
public async Task<object?> ExecuteAsync(object command)
|
||||
{
|
||||
var principal = (await auth.GetAuthoritativeStateAsync()).User;
|
||||
@@ -52,6 +59,9 @@ public sealed class ConfigurationCommandService(IServiceProvider services, Authe
|
||||
public static class ConfigurationCommandExtensions
|
||||
{
|
||||
/// <summary>Submits a database-only configuration mutation with current server-side authority.</summary>
|
||||
/// <param name="services">The service provider used to resolve the command service.</param>
|
||||
/// <param name="command">The configuration command to execute.</param>
|
||||
/// <returns>The command's result, if any.</returns>
|
||||
public static Task<object?> ExecuteConfigurationAsync(this IServiceProvider services, object command)
|
||||
=> services.GetRequiredService<ConfigurationCommandService>().ExecuteAsync(command);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||
/// NAME keys back to <c>DataConnection.Id</c> using the same site repository the
|
||||
/// design page loads from. Health reports key connections by <c>Name</c>, the
|
||||
/// page renders nodes by id, so the join is per-site Name → Id; doing it per-site
|
||||
/// avoids cross-site name collisions (two sites can each own a "PLC-1").
|
||||
/// avoids cross-site name collisions (two sites can each own a "MainPlc").
|
||||
/// </remarks>
|
||||
public sealed class ConnectionHealthQueryService : IConnectionHealthQueryService
|
||||
{
|
||||
|
||||
@@ -59,6 +59,8 @@ public sealed class FlowDebugService : IFlowDebugService
|
||||
/// the run itself at <c>timeoutSeconds + RunGrace</c> (see <c>FlowDebugRunner.RunMethodAsync</c>),
|
||||
/// so the client must wait at least that long or it cuts the run off before the server does.
|
||||
/// </summary>
|
||||
/// <param name="timeoutSeconds">The method's own timeout in seconds.</param>
|
||||
/// <returns>The Ask timeout to use for the run.</returns>
|
||||
public static TimeSpan RunAskTimeoutFor(int timeoutSeconds)
|
||||
{
|
||||
var t = TimeSpan.FromSeconds(Math.Max(1, timeoutSeconds)) + FlowDebugRunner.RunGrace + ClientSlack;
|
||||
@@ -69,6 +71,8 @@ public sealed class FlowDebugService : IFlowDebugService
|
||||
/// Client-side Ask wait for a WRITE-kind script run (<see cref="RunScriptAsync"/>): the
|
||||
/// trigger-wait window plus <see cref="ClientSlack"/>.
|
||||
/// </summary>
|
||||
/// <param name="waitSeconds">The trigger-wait window in seconds.</param>
|
||||
/// <returns>The Ask timeout to use for the run.</returns>
|
||||
public static TimeSpan ValueChangeAskTimeoutFor(int waitSeconds)
|
||||
=> TimeSpan.FromSeconds(Math.Max(1, waitSeconds)) + ClientSlack;
|
||||
|
||||
@@ -110,6 +114,14 @@ public sealed class FlowDebugService : IFlowDebugService
|
||||
IReadOnlyList<FlowScriptOption> Options);
|
||||
|
||||
/// <summary>Initializes the service.</summary>
|
||||
/// <param name="holder">Holder for the management actor reference.</param>
|
||||
/// <param name="auth">Provides the caller's authentication state.</param>
|
||||
/// <param name="inboundApi">Repository for inbound API methods.</param>
|
||||
/// <param name="templates">Repository for templates and instances.</param>
|
||||
/// <param name="pipeline">Flattening pipeline used to resolve instance scripts.</param>
|
||||
/// <param name="comms">Communication service for central-to-site requests.</param>
|
||||
/// <param name="logger">Logger for diagnostics.</param>
|
||||
/// <param name="sites">Repository for sites.</param>
|
||||
public FlowDebugService(
|
||||
ManagementActorHolder holder,
|
||||
AuthenticationStateProvider auth,
|
||||
|
||||
@@ -44,7 +44,7 @@ public interface IAlarmSummaryService
|
||||
|
||||
/// <summary>
|
||||
/// Builds an <see cref="AlarmSummaryResult"/> directly from an in-memory live
|
||||
/// snapshot (plan #10, Task 5) — the current alarms served by
|
||||
/// snapshot — the current alarms served by
|
||||
/// <see cref="ZB.MOM.WW.ScadaBridge.Communication.ISiteAlarmLiveCache.GetCurrentAlarms"/>
|
||||
/// — instead of fanning out per-instance snapshot Asks. Each
|
||||
/// <see cref="AlarmStateChanged"/> is flattened to one
|
||||
|
||||
@@ -28,6 +28,9 @@ public sealed record FlowDebugOutcome(
|
||||
public bool Success => Graph != null && Error == null;
|
||||
|
||||
/// <summary>Creates a failed outcome.</summary>
|
||||
/// <param name="error">The error message.</param>
|
||||
/// <param name="errorCode">The machine-readable error code.</param>
|
||||
/// <returns>A failed outcome carrying the error.</returns>
|
||||
public static FlowDebugOutcome Fail(string error, string errorCode) => new(null, null, error, errorCode);
|
||||
}
|
||||
|
||||
@@ -83,18 +86,21 @@ public interface IFlowDebugService
|
||||
/// <summary>The instance's scripts from its flattened configuration, ordered by canonical name; empty when the instance does not exist.</summary>
|
||||
/// <param name="instanceId">The instance id.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The instance's scripts ordered by canonical name.</returns>
|
||||
Task<IReadOnlyList<FlowScriptOption>> GetInstanceScriptsAsync(int instanceId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>Predicts the flow of running <paramref name="scriptName"/>: the write + spawned script for a write kind, a RouteCall root + the script for a call kind.</summary>
|
||||
/// <param name="instanceId">The instance id.</param>
|
||||
/// <param name="scriptName">Canonical script name (case-insensitive).</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The predicted flow for the script.</returns>
|
||||
Task<PredictedFlow> PredictScriptAsync(int instanceId, string scriptName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>Runs an inbound API method with tracing on the active central node and returns the flow.</summary>
|
||||
/// <param name="apiMethodId">The method id.</param>
|
||||
/// <param name="parameters">Flat JSON object of parameters, or null.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The outcome of the run, including the built flow graph.</returns>
|
||||
Task<FlowDebugOutcome> RunMethodAsync(int apiMethodId, JsonElement? parameters, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>Runs a script by name (write kinds take <paramref name="value"/>, call kinds <paramref name="parameters"/>) and returns the flow.</summary>
|
||||
@@ -103,11 +109,13 @@ public interface IFlowDebugService
|
||||
/// <param name="parameters">Call kinds: flat JSON object of parameters, or null.</param>
|
||||
/// <param name="value">Write kinds: the new value for the trigger's attribute, in canonical string form.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The outcome of the run, including the built flow graph.</returns>
|
||||
Task<FlowDebugOutcome> RunScriptAsync(int instanceId, string scriptName, JsonElement? parameters, string? value, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>Rebuilds a past flow from the central audit store.</summary>
|
||||
/// <param name="executionId">Any execution id in the chain.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The outcome of the replay, including the rebuilt flow graph.</returns>
|
||||
Task<FlowDebugOutcome> ReplayAsync(Guid executionId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -120,6 +128,7 @@ public interface IFlowDebugService
|
||||
/// </summary>
|
||||
/// <param name="step">The outbound step to retry.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The result of the retry request.</returns>
|
||||
Task<FlowOutboundActionResult> RetryOutboundAsync(FlowStep step, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -128,5 +137,6 @@ public interface IFlowDebugService
|
||||
/// </summary>
|
||||
/// <param name="step">The outbound step to discard.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The result of the discard request.</returns>
|
||||
Task<FlowOutboundActionResult> DiscardOutboundAsync(FlowStep step, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Process-level memoized point-in-time KPI snapshots shared by every Blazor circuit on
|
||||
/// this node (arch-review WP2.4, finding #8 — the per-circuit polling half).
|
||||
/// this node (the per-circuit polling half).
|
||||
/// <para>
|
||||
/// Every KPI here is a <em>global, point-in-time aggregate</em>: it does not vary by user,
|
||||
/// site scope, or role, so N circuits asking for it inside one refresh window are asking
|
||||
|
||||
@@ -13,6 +13,9 @@ public sealed class PollGate
|
||||
public bool TryEnter() => Interlocked.CompareExchange(ref _inFlight, 1, 0) == 0;
|
||||
|
||||
/// <summary>Runs and observes a posted refresh, releasing the gate even if dispatch is rejected.</summary>
|
||||
/// <param name="dispatch">Delegate that posts the refresh.</param>
|
||||
/// <param name="onError">Callback invoked with any exception thrown by <paramref name="dispatch"/>.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public async Task RunAsync(Func<Task> dispatch, Action<Exception> onError)
|
||||
{
|
||||
if (!TryEnter()) return;
|
||||
|
||||
@@ -6,7 +6,7 @@ using ZB.MOM.WW.ScadaBridge.Communication;
|
||||
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Process-level memoizing façade over <see cref="AlarmSummaryService"/> (arch-review WP2.4).
|
||||
/// Process-level memoizing façade over <see cref="AlarmSummaryService"/>.
|
||||
/// <para>
|
||||
/// The Alarm Summary page polls every 15s <em>per circuit</em>, and each poll fans one debug
|
||||
/// snapshot Ask out to every Enabled instance on the site. Ten operators watching one site
|
||||
|
||||
@@ -17,6 +17,9 @@ public static class TemplatePathFormatter
|
||||
/// Builds the display path for <paramref name="template"/> by walking its
|
||||
/// folder chain upward through <paramref name="foldersById"/>.
|
||||
/// </summary>
|
||||
/// <param name="template">The template whose path is built.</param>
|
||||
/// <param name="foldersById">Folders keyed by id, used to walk the parent chain.</param>
|
||||
/// <returns>The folder-qualified display path.</returns>
|
||||
public static string Format(Template template, IReadOnlyDictionary<int, TemplateFolder> foldersById)
|
||||
{
|
||||
var parts = new List<string> { template.Name };
|
||||
|
||||
Reference in New Issue
Block a user