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
@@ -21,7 +21,7 @@ namespace ZB.MOM.WW.ScadaBridge.Transport.Import;
/// "Coarse" means: each persistent field is compared as a value; differing
/// non-code fields appear in <c>changes</c> with old/new values. Code / large-
/// text fields (script bodies, API-method scripts) instead carry a structured
/// per-line Myers diff (T20): the <see cref="FieldChange.OldValue"/> /
/// per-line Myers diff: the <see cref="FieldChange.OldValue"/> /
/// <see cref="FieldChange.NewValue"/> keep a compact <c>&lt;N lines&gt;</c>
/// summary for fallback rendering, and a <see cref="FieldChange.LineDiff"/>
/// payload carries the hunk lines (+/-/context) plus add/remove totals and a
@@ -210,7 +210,7 @@ public sealed class ArtifactDiff
incoming.Recipients,
e => e.Name,
i => i.Name,
// S10: a recipient is unchanged only when BOTH contacts match — a phone
// A recipient is unchanged only when BOTH contacts match — a phone
// number added/changed on an existing recipient is a real diff.
(e, i) => e.EmailAddress == i.EmailAddress && e.PhoneNumber == i.PhoneNumber,
"Recipients",
@@ -254,7 +254,7 @@ public sealed class ArtifactDiff
/// <summary>
/// Compares an incoming SMS provider configuration against the existing one in
/// the database (S10b). Mirrors <see cref="CompareSmtpConfiguration"/>: keyed by
/// the database. Mirrors <see cref="CompareSmtpConfiguration"/>: keyed by
/// the natural key <c>AccountSid</c>, with the auth token diffed presence-only
/// (it lives in <see cref="SecretsBlock"/>, never compared by value).
/// </summary>
@@ -286,7 +286,7 @@ public sealed class ArtifactDiff
return BuildItem("SmsConfiguration", incoming.AccountSid, changes);
}
// CompareApiKey was removed in re-arch C4: inbound API keys are not transported
// CompareApiKey was removed: inbound API keys are not transported
// between environments, so the import preview never diffs keys.
/// <summary>
@@ -301,7 +301,7 @@ public sealed class ArtifactDiff
if (existing is null) return New("ApiMethod", incoming.Name);
var changes = new List<FieldChange>();
// ApprovedApiKeyIds is not transported (re-arch C4) and is excluded from the diff.
// ApprovedApiKeyIds is not transported and is excluded from the diff.
AddIfDifferent(changes, "ParameterDefinitions", existing.ParameterDefinitions, incoming.ParameterDefinitions);
AddIfDifferent(changes, "ReturnDefinition", existing.ReturnDefinition, incoming.ReturnDefinition);
AddIfDifferent(changes, "TimeoutSeconds", existing.TimeoutSeconds, incoming.TimeoutSeconds);
@@ -329,7 +329,7 @@ public sealed class ArtifactDiff
return BuildItem("TemplateFolder", incoming.Name, changes);
}
// ---- Site / Connection / Instance (M8) ----
// ---- Site / Connection / Instance ----
/// <summary>
/// Compares an incoming site against the existing site in the database.
@@ -504,8 +504,8 @@ public sealed class ArtifactDiff
private static void AddCodeChangeIfDifferent(List<FieldChange> changes, string field, string? existing, string? incoming)
{
// Code/large-text fields: when they differ, emit a real per-line Myers diff
// (T20). The OldValue/NewValue keep a compact "<N lines>" summary as a
// Code/large-text fields: when they differ, emit a real per-line Myers diff.
// The OldValue/NewValue keep a compact "<N lines>" summary as a
// fallback for renderers that don't consume the structured payload; the
// LineDiff carries the +/- hunk lines. Identical code emits no change.
var sameNullness = existing is null == incoming is null;
@@ -635,7 +635,7 @@ public sealed class ArtifactDiff
if (!ScriptsEqual(ex, inc))
{
// A script row can diverge in Code and/or its trigger/param metadata.
// The structured line diff covers the Code body (T20); when only the
// The structured line diff covers the Code body; when only the
// metadata changed the hunk list is all-context (no +/-), which still
// tells the operator the row changed.
changes.Add(BuildCodeFieldChange($"Scripts.{name}", ex.Code, inc.Code));
@@ -696,7 +696,7 @@ public sealed class ArtifactDiff
[property: JsonPropertyName("field")] string Field,
[property: JsonPropertyName("oldValue")] string? OldValue,
[property: JsonPropertyName("newValue")] string? NewValue,
// Present only for code / large-text fields (T20). Null (and omitted from
// Present only for code / large-text fields. Null (and omitted from
// the JSON by the WhenWritingNull policy) for ordinary coarse fields.
[property: JsonPropertyName("lineDiff")] LineDiffPayload? LineDiff = null);
@@ -49,7 +49,7 @@ public sealed class BundleImporter : IBundleImporter
{
// All bundle content deserialization goes through BundleJsonOptions.Default.
// IMPORTANT — unknown JSON properties must remain ALLOWED (the default
// JsonUnmappedMemberHandling.Skip). Pre-C4 bundles may carry a top-level
// JsonUnmappedMemberHandling.Skip). Legacy bundles may carry a top-level
// "apiKeys" array and/or "ApprovedApiKeyIds" inside "apiMethods[]" entries.
// Setting JsonUnmappedMemberHandling.Disallow here would cause those bundles
// to fail deserialization, breaking backward-compat. This tolerance is
@@ -74,7 +74,7 @@ public sealed class BundleImporter : IBundleImporter
private readonly IOptions<TransportOptions> _options;
private readonly TimeProvider _timeProvider;
private readonly SemanticValidator _semanticValidator;
// #16 (M8 D2): optional. Implemented in DeploymentManager (where the flattening
// Optional. Implemented in DeploymentManager (where the flattening
// pipeline lives) and surfaced via the Commons IStaleInstanceProbe seam. Null
// in a host that registers Transport without DeploymentManager — staleness is
// then best-effort empty (informational only, never gates the import).
@@ -96,12 +96,12 @@ public sealed class BundleImporter : IBundleImporter
/// <param name="externalRepo">External system repository for diff and apply.</param>
/// <param name="notificationRepo">Notification repository for diff and apply.</param>
/// <param name="inboundApiRepo">Inbound API repository for diff and apply.</param>
/// <param name="siteRepo">Site repository — supplies the target sites and site-scoped data connections that the preview's site/connection auto-match resolves against (M8 C2).</param>
/// <param name="siteRepo">Site repository — supplies the target sites and site-scoped data connections that the preview's site/connection auto-match resolves against.</param>
/// <param name="auditService">Audit service for writing per-entity import audit rows.</param>
/// <param name="correlationContext">Correlation context that carries the active BundleImportId.</param>
/// <param name="dbContext">EF Core context used to commit the import transaction.</param>
/// <param name="semanticValidator">Validates template references before applying.</param>
/// <param name="staleInstanceProbe">Optional (#16): recomputes a deployed instance's current revision hash so the importer can enumerate instances stale-ed by a template overwrite. Null when no flattening pipeline is registered (Transport-without-DeploymentManager hosts) — staleness is then skipped.</param>
/// <param name="staleInstanceProbe">Optional: recomputes a deployed instance's current revision hash so the importer can enumerate instances stale-ed by a template overwrite. Null when no flattening pipeline is registered (Transport-without-DeploymentManager hosts) — staleness is then skipped.</param>
/// <param name="logger">Optional logger.</param>
public BundleImporter(
BundleSerializer bundleSerializer,
@@ -371,7 +371,7 @@ public sealed class BundleImporter : IBundleImporter
}
// ---- Templates ----
// Transport-008: previously this loop iterated GetAllTemplatesAsync()
// Previously this loop iterated GetAllTemplatesAsync()
// and called GetTemplateWithChildrenAsync(stub.Id) once per matching
// name (classic N+1). The bulk variant fetches every matching template
// with children eager-loaded in a single round-trip.
@@ -429,7 +429,7 @@ public sealed class BundleImporter : IBundleImporter
items.Add(_diff.CompareSmtpConfiguration(sm, existing));
}
// ---- SmsConfigurations (S10b; no by-AccountSid lookup — scan GetAll) ----
// ---- SmsConfigurations (no by-AccountSid lookup — scan GetAll) ----
var allSms = await _notificationRepo.GetAllSmsConfigurationsAsync(ct).ConfigureAwait(false);
var smsBySid = allSms.ToDictionary(s => s.AccountSid, s => s, StringComparer.Ordinal);
foreach (var sms in content.SmsConfigs)
@@ -439,8 +439,8 @@ public sealed class BundleImporter : IBundleImporter
}
// ---- ApiKeys ----
// Inbound API keys are not transported between environments (re-arch C4).
// New bundles never carry a keys section. A pre-C4 bundle may still contain
// Inbound API keys are not transported between environments.
// New bundles never carry a keys section. A legacy bundle may still contain
// one; we do NOT surface those keys as importable preview rows (they would
// offer Add/Overwrite actions for keys that can't be meaningfully re-created
// from a hash). They are counted, ignored, and reported at apply time.
@@ -452,7 +452,7 @@ public sealed class BundleImporter : IBundleImporter
items.Add(_diff.CompareApiMethod(m, existing));
}
// ---- M8 site/instance-scoped types ----
// ---- Site/instance-scoped types ----
// Sites/DataConnections/Instances are referenced by stable string identity
// (SiteIdentifier / connection Name / UniqueName) and resolved against the
// TARGET environment's own surrogate keys. We auto-match the source site by
@@ -493,7 +493,7 @@ public sealed class BundleImporter : IBundleImporter
}
// ---- DataConnections (site-scoped; matched by name within the auto-matched target site) ----
// C2: connection names are unique only WITHIN a site, so the preview item's
// Connection names are unique only WITHIN a site, so the preview item's
// identity is SITE-QUALIFIED (`{SiteIdentifier}/{Name}`). The diff CONTENT is
// unchanged — only the item Name is qualified (after CompareDataConnection
// returns) so two sites' same-named connections resolve to distinct items and
@@ -543,7 +543,7 @@ public sealed class BundleImporter : IBundleImporter
instDto, existing, existingTemplateName, existingSiteIdentifier, existingAreaName));
}
// ---- Required site/connection mappings (M8) ----
// ---- Required site/connection mappings ----
var (requiredSites, requiredConnections) = await BuildRequiredMappingsAsync(
content, ResolveTargetSiteAsync, ResolveTargetConnectionsAsync).ConfigureAwait(false);
@@ -556,7 +556,7 @@ public sealed class BundleImporter : IBundleImporter
/// <summary>
/// Collects the distinct set of source sites and (site, connection) pairs the
/// bundle references, auto-matching each against the TARGET environment by
/// identity, and returns the operator-facing required-mapping lists (M8 C2).
/// identity, and returns the operator-facing required-mapping lists.
/// <para>
/// Site references are drawn from every instance, every site, and every
/// data-connection in the bundle. Connection references are drawn from every
@@ -666,7 +666,7 @@ public sealed class BundleImporter : IBundleImporter
{
var blockers = new List<ImportPreviewItem>();
// ---- M8: instance template + referenced-connection blockers ----
// ---- Instance template + referenced-connection blockers ----
// The set of template names the import can satisfy = (in-bundle templates)
// (templates already in the target DB). An instance whose TemplateName is
// in neither is unresolvable.
@@ -735,7 +735,7 @@ public sealed class BundleImporter : IBundleImporter
if (bundleConnections.Contains((site, name))) continue;
var targetConns = await resolveTargetConnections(site).ConfigureAwait(false);
if (targetConns.Any(c => string.Equals(c.Name, name, StringComparison.Ordinal))) continue;
// C2: site-qualify the blocker Name so two sites' same-named-but-missing
// Site-qualify the blocker Name so two sites' same-named-but-missing
// connections surface as distinct blockers (a bare name would collide).
blockers.Add(new ImportPreviewItem(
EntityType: "Instance",
@@ -888,7 +888,7 @@ public sealed class BundleImporter : IBundleImporter
private static bool IsIdentifierChar(char c) => c == '_' || char.IsLetterOrDigit(c);
/// <summary>
/// C2: the site-qualified identity (<c>{siteIdentifier}/{connectionName}</c>) used
/// The site-qualified identity (<c>{siteIdentifier}/{connectionName}</c>) used
/// for every <c>DataConnection</c> preview item Name + blocker Name, and for the
/// matching resolution lookup in <see cref="ApplyDataConnectionsAsync"/>. Connection
/// names are unique only WITHIN a site, so a bare-name key would collapse two sites'
@@ -939,8 +939,8 @@ public sealed class BundleImporter : IBundleImporter
r => r);
var summary = new ImportSummary();
// Inbound API keys are not transported between environments (re-arch C4).
// A pre-C4 bundle may still contain a keys section; we ignore those keys
// Inbound API keys are not transported between environments.
// A legacy bundle may still contain a keys section; we ignore those keys
// entirely (never re-create them) but count them so the result can tell
// the operator to re-issue keys on this environment.
var apiKeysIgnored = content.ApiKeys?.Count ?? 0;
@@ -965,7 +965,7 @@ public sealed class BundleImporter : IBundleImporter
// pre-existing target reads, so it has no ordering dependency on
// the Apply* helpers. Failing here means the change tracker is
// still empty, which keeps the rollback contract simple on both
// the in-memory and relational providers (FU-B: intermediate
// the in-memory and relational providers (intermediate
// SaveChangesAsync between Apply* and the second-pass rewire
// would otherwise prevent the in-memory provider from undoing
// already-flushed template rows on validation failure — the
@@ -976,7 +976,7 @@ public sealed class BundleImporter : IBundleImporter
// a Skip on a dependency surfaces as a missing-reference error
// rather than silently passing.
var validationErrors = await RunSemanticValidationAsync(content, resolutionMap, ct).ConfigureAwait(false);
// M8: validate every site / connection / template reference the
// Validate every site / connection / template reference the
// site-instance payload depends on BEFORE any row is staged. Running
// this in the validation phase (not as an apply-pass guard) preserves
// the rollback contract: a structurally-unresolvable bundle fails with
@@ -992,7 +992,7 @@ public sealed class BundleImporter : IBundleImporter
throw new SemanticValidationException(validationErrors);
}
// ---- M8 site/instance-scoped apply: sites + connections FIRST ----
// ---- Site/instance-scoped apply: sites + connections FIRST ----
// Sites are the FK target for both data connections (SiteId) and
// instances (SiteId); data connections are the FK target for instance
// connection bindings (DataConnectionId) and the rewrite target for
@@ -1020,11 +1020,11 @@ public sealed class BundleImporter : IBundleImporter
await ApplyNotificationListsAsync(content.NotificationLists, resolutionMap, user, summary, ct).ConfigureAwait(false);
await ApplySmtpConfigsAsync(content.SmtpConfigs, resolutionMap, user, summary, ct).ConfigureAwait(false);
await ApplySmsConfigsAsync(content.SmsConfigs, resolutionMap, user, summary, ct).ConfigureAwait(false);
// Inbound API keys are NOT applied from a bundle (re-arch C4) — any keys
// Inbound API keys are NOT applied from a bundle — any keys
// in a legacy bundle were counted above (apiKeysIgnored) and are skipped.
await ApplyApiMethodsAsync(content.ApiMethods, resolutionMap, user, summary, ct).ConfigureAwait(false);
// FU-B / #39 + remainder of #37 — second-pass rewire of name-keyed
// Second-pass rewire of name-keyed
// FKs that can only be resolved AFTER every template's scripts and
// child rows have been staged. We flush here so Pass A can look up
// the just-persisted scripts by name and Pass B can look up the
@@ -1043,7 +1043,7 @@ public sealed class BundleImporter : IBundleImporter
await ResolveAlarmScriptLinksAsync(content.Templates, resolutionMap, user, ct).ConfigureAwait(false);
await ResolveCompositionEdgesAsync(content.Templates, resolutionMap, user, ct).ConfigureAwait(false);
// ---- M8 site/instance-scoped apply: instances LAST ----
// ---- Site/instance-scoped apply: instances LAST ----
// The instance pass needs every FK target materialised first:
// • template id — resolved by name against the just-flushed central
// config (Templates were flushed above for the alarm/composition
@@ -1058,9 +1058,9 @@ public sealed class BundleImporter : IBundleImporter
content, resolutionMap, siteBySourceIdentifier, connectionMaps,
user, summary, ct).ConfigureAwait(false);
// ---- D2 pre-commit point (#16): stale-instance computation ----
// ---- Pre-commit point: stale-instance computation ----
// Everything the import will write is staged on the change tracker at
// this point but NOT yet committed. D2 computes StaleInstanceIds here
// this point but NOT yet committed. This computes StaleInstanceIds here
// — target instances whose template was overwritten by this import and
// therefore now carry a stale flattened-config revision — and threads
// the resulting list into the ImportResult below (replacing the
@@ -1088,7 +1088,7 @@ public sealed class BundleImporter : IBundleImporter
summary.Skipped,
summary.Renamed,
},
// re-arch C4: legacy inbound API keys present in the bundle that
// Legacy inbound API keys present in the bundle that
// were ignored (not transported / not re-created here).
ApiKeysIgnored = apiKeysIgnored,
},
@@ -1220,7 +1220,7 @@ public sealed class BundleImporter : IBundleImporter
}
/// <summary>
/// #16 (M8 D2): enumerates the deployed instances stale-ed by this import.
/// Enumerates the deployed instances stale-ed by this import.
/// Overwriting a template changes the flattened-config hash of every instance
/// of that template, so a deployed instance's freshly-computed revision hash
/// will no longer match the hash captured in its <c>DeployedConfigSnapshot</c>
@@ -1896,7 +1896,7 @@ public sealed class BundleImporter : IBundleImporter
}
/// <summary>
/// FU-B / remainder of #37 — Pass A of the post-template-flush rewire.
/// Pass A of the post-template-flush rewire.
/// For every imported template (Add / Overwrite / Rename) whose bundle DTO
/// carries any alarm with <c>OnTriggerScriptName</c>, look up the
/// persisted alarm + script by name on the same template and set the FK.
@@ -1970,7 +1970,7 @@ public sealed class BundleImporter : IBundleImporter
}
/// <summary>
/// FU-B / #39 — Pass B of the post-template-flush rewire. For every
/// Pass B of the post-template-flush rewire. For every
/// imported template (Add / Overwrite / Rename) whose bundle DTO carries
/// any <c>Compositions</c>, replace the persisted template's existing
/// composition rows with new ones whose <c>ComposedTemplateId</c> is
@@ -2453,7 +2453,7 @@ public sealed class BundleImporter : IBundleImporter
return list;
}
// S10: reconstruct a recipient carrying whichever contact(s) the bundle holds.
// Reconstruct a recipient carrying whichever contact(s) the bundle holds.
// Email-only and SMS-only round-trip exactly; a recipient with both keeps both.
// Build via the email ctor when an address is present (so the historical
// non-null-email path is unchanged) and additively restore the phone number;
@@ -2544,7 +2544,7 @@ public sealed class BundleImporter : IBundleImporter
target.Credentials = dto.Secrets?.Values.TryGetValue("Credentials", out var cred) == true ? cred : null;
}
// SMS (S10b): mirrors ApplySmtpConfigsAsync exactly. SmsConfiguration is keyed by
// SMS: mirrors ApplySmtpConfigsAsync exactly. SmsConfiguration is keyed by
// AccountSid (the diff engine's natural key — analogous to SMTP's Host), so a
// Rename targets AccountSid and Overwrite matches an existing config by AccountSid.
// The provider auth token is decrypted out of the SecretsBlock via the same path
@@ -2618,9 +2618,9 @@ public sealed class BundleImporter : IBundleImporter
target.AuthToken = dto.Secrets?.Values.TryGetValue("AuthToken", out var token) == true ? token : null;
}
// ApplyApiKeysAsync was removed in re-arch C4: inbound API keys are not
// ApplyApiKeysAsync was removed: inbound API keys are not
// transported between environments, so a bundle never re-creates keys. Any keys
// present in a legacy (pre-C4) bundle are counted and ignored in ApplyAsync.
// present in a legacy bundle are counted and ignored in ApplyAsync.
private async Task ApplyApiMethodsAsync(
IReadOnlyList<ApiMethodDto> dtos,
@@ -2651,9 +2651,9 @@ public sealed class BundleImporter : IBundleImporter
}
case ResolutionAction.Overwrite when existing is not null:
existing.Script = dto.Script;
// Method→key scopes are not transported (re-arch C4) and the
// Method→key scopes are not transported and the
// ApprovedApiKeyIds column was dropped with the SQL Server ApiKey
// entity (re-arch C5): scopes are re-granted per environment in the
// entity: scopes are re-granted per environment in the
// shared ZB.MOM.WW.Auth.ApiKeys store, never via an imported bundle.
existing.ParameterDefinitions = dto.ParameterDefinitions;
existing.ReturnDefinition = dto.ReturnDefinition;
@@ -2680,9 +2680,9 @@ public sealed class BundleImporter : IBundleImporter
private static ApiMethod BuildApiMethod(ApiMethodDto dto, string? overrideName)
{
// Method→key scopes are not transported (re-arch C4); the ApprovedApiKeyIds
// column that once carried them was dropped with the SQL Server ApiKey entity
// (re-arch C5). Scopes are re-granted per environment in the shared
// Method→key scopes are not transported; the ApprovedApiKeyIds
// column that once carried them was dropped with the SQL Server ApiKey entity.
// Scopes are re-granted per environment in the shared
// ZB.MOM.WW.Auth.ApiKeys store.
return new ApiMethod(overrideName ?? dto.Name, dto.Script)
{
@@ -2693,7 +2693,7 @@ public sealed class BundleImporter : IBundleImporter
}
// ─────────────────────────────────────────────────────────────────────
// M8 D1 — site/instance-scoped apply.
// Site/instance-scoped apply.
//
// Three passes (sites → connections → instances) resolve every cross-
// environment name reference against the TARGET database's own surrogate
@@ -2716,7 +2716,7 @@ public sealed class BundleImporter : IBundleImporter
/// the same identifier resolves to <see cref="MappingAction.MapToExisting"/>,
/// otherwise <see cref="MappingAction.CreateNew"/>. <c>CreateNew</c> inserts a
/// site from the full <see cref="SiteDto"/> payload (display name, description,
/// and the verbatim Node A/B + gRPC Node A/B addresses — D3's "carry full
/// and the verbatim Node A/B + gRPC Node A/B addresses — the "carry full
/// config" decision). <c>MapToExisting</c> honours the site's
/// <see cref="ImportResolution"/>: <see cref="ResolutionAction.Skip"/> leaves
/// the target untouched; <see cref="ResolutionAction.Overwrite"/> applies the
@@ -2964,7 +2964,7 @@ public sealed class BundleImporter : IBundleImporter
}
// MapToExisting — honour the connection's own conflict resolution.
// C2: the resolution is keyed by the SITE-QUALIFIED name
// The resolution is keyed by the SITE-QUALIFIED name
// (`{SiteIdentifier}/{Name}`), matching the qualified preview-item Name —
// so a same-named connection under a different site can't pick up the
// wrong Skip/Overwrite.
@@ -2989,7 +2989,7 @@ public sealed class BundleImporter : IBundleImporter
targetNameByRef[key] = existing.Name;
}
// ---- C1 Pass 2 — referenced-but-not-carried connections ----
// ---- Pass 2 — referenced-but-not-carried connections ----
// A binding (or native-alarm-source override) can name a connection that
// exists in the TARGET database but was NOT carried in the bundle's
// DataConnections (e.g. exported without it). Preview correctly does NOT
@@ -3043,7 +3043,7 @@ public sealed class BundleImporter : IBundleImporter
}
/// <summary>
/// C1: every distinct <c>(sourceSiteIdentifier, connectionName)</c> pair an instance
/// Every distinct <c>(sourceSiteIdentifier, connectionName)</c> pair an instance
/// references — via a <see cref="InstanceConnectionBindingDto.ConnectionName"/> or a
/// non-null <see cref="InstanceNativeAlarmSourceOverrideDto.ConnectionNameOverride"/>.
/// Drives the connection-map Pass 2 that resolves references the bundle didn't carry.
@@ -3348,7 +3348,7 @@ public sealed class BundleImporter : IBundleImporter
{
continue;
}
// Resolve ConnectionName → target DataConnectionId. After the C1 Pass-2
// Resolve ConnectionName → target DataConnectionId. After Pass 2
// in ApplyDataConnectionsAsync, the map carries an entry for every
// referenced connection — carried in the bundle OR auto-matched in the
// target. A non-empty name that STILL doesn't resolve is a structural
@@ -3430,7 +3430,7 @@ public sealed class BundleImporter : IBundleImporter
}
/// <summary>
/// M8: validates every cross-environment reference the site/instance payload
/// Validates every cross-environment reference the site/instance payload
/// depends on, BEFORE any row is staged — so a structurally-unresolvable
/// bundle fails with an empty change tracker (preserving the all-or-nothing
/// rollback contract on every EF provider, including the in-memory one whose
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Transport.Import;
/// <summary>
/// Transport-004: thrown by <see cref="BundleImporter.LoadAsync"/> when the caller
/// Thrown by <see cref="BundleImporter.LoadAsync"/> when the caller
/// has exceeded the configured per-IP-per-hour unlock attempt cap
/// (<see cref="TransportOptions.MaxUnlockAttemptsPerIpPerHour"/>). The 429-equivalent
/// signal: the caller must wait for the trailing-hour window to roll forward before
@@ -3,7 +3,7 @@ using System.Collections.Concurrent;
namespace ZB.MOM.WW.ScadaBridge.Transport.Import;
/// <summary>
/// Transport-004: in-memory sliding-window rate limiter for bundle-unlock passphrase
/// In-memory sliding-window rate limiter for bundle-unlock passphrase
/// attempts, keyed by client IP. The design doc (§11) declares a per-IP-per-hour cap
/// (default 10) as a brute-force defence against a stolen bundle; this class is the
/// minimal server-side implementation.