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
@@ -10,7 +10,7 @@ namespace ZB.MOM.WW.ScadaBridge.Transport.Serialization;
/// <b>Important — unknown-property tolerance:</b>
/// <see cref="JsonUnmappedMemberHandling"/> is left at its default
/// (<c>Skip</c>); setting it to <c>Disallow</c> would break backward-
/// compatible deserialization of pre-C4 bundles, which may carry a top-level
/// compatible deserialization of older bundles, which may carry a top-level
/// <c>apiKeys</c> array and/or <c>ApprovedApiKeyIds</c> fields inside
/// <c>apiMethods[]</c> entries. That tolerance is load-bearing and must be
/// preserved.
@@ -16,7 +16,7 @@ namespace ZB.MOM.WW.ScadaBridge.Transport.Serialization;
/// on the application side of the bundle boundary.
/// </summary>
// ApiKeys is intentionally absent: inbound API keys are not transported between
// environments (re-arch C4). The aggregate only carries API methods.
// environments. The aggregate only carries API methods.
public sealed record EntityAggregate(
IReadOnlyList<TemplateFolder> TemplateFolders,
IReadOnlyList<Template> Templates,
@@ -28,15 +28,15 @@ public sealed record EntityAggregate(
IReadOnlyList<SmtpConfiguration> SmtpConfigurations,
IReadOnlyList<ApiMethod> ApiMethods)
{
// M8: site/instance-scoped entities. Init-only with empty-array defaults so
// Site/instance-scoped entities. Init-only with empty-array defaults so
// existing positional `new EntityAggregate(...)` callers keep compiling and
// never see a null collection; new callers opt in via object-initializer.
public IReadOnlyList<Site> Sites { get; init; } = Array.Empty<Site>();
public IReadOnlyList<DataConnection> DataConnections { get; init; } = Array.Empty<DataConnection>();
public IReadOnlyList<Instance> Instances { get; init; } = Array.Empty<Instance>();
// SMS (S10): carried alongside SmtpConfigurations. Init-only with an empty
// default for the same source-compat reason as the M8 collections above —
// SMS: carried alongside SmtpConfigurations. Init-only with an empty
// default for the same source-compat reason as the site/instance collections above —
// every existing positional `new EntityAggregate(...)` caller keeps compiling
// and never sees null; producers that resolve SMS config opt in via
// object-initializer.
@@ -52,7 +52,7 @@ public sealed record EntityAggregate(
/// <para>
/// <see cref="ApiKeys"/> is a <b>legacy, read-only</b> field retained purely for
/// backward-compatible deserialization of bundles produced before the
/// inbound-API-key re-architecture (C4). New exports never populate it (it stays
/// inbound-API-key re-architecture. New exports never populate it (it stays
/// <c>null</c> and is dropped from the JSON by the serializer's
/// <c>WhenWritingNull</c> policy); the importer counts any keys present in an old
/// bundle, ignores them, and surfaces a note — keys are re-created per environment.
@@ -69,7 +69,7 @@ public sealed record BundleContentDto(
IReadOnlyList<ApiMethodDto> ApiMethods,
IReadOnlyList<ApiKeyDto>? ApiKeys = null)
{
// M8: site/instance-scoped payloads. Modeled as init-only properties with
// Site/instance-scoped payloads. Modeled as init-only properties with
// empty-array defaults (rather than additional positional ctor params) for
// two reasons:
// 1. Forward-compat: deserializing an OLDER bundle whose content blob has
@@ -85,9 +85,9 @@ public sealed record BundleContentDto(
public IReadOnlyList<DataConnectionDto> DataConnections { get; init; } = Array.Empty<DataConnectionDto>();
public IReadOnlyList<InstanceDto> Instances { get; init; } = Array.Empty<InstanceDto>();
// SMS (S10): central-only SMS provider configs, carried alongside SmtpConfigs.
// SMS: central-only SMS provider configs, carried alongside SmtpConfigs.
// Modeled as an init-only property with an empty default (NOT a positional ctor
// param) for the same two reasons as the M8 site/instance arrays above:
// param) for the same two reasons as the site/instance arrays above:
// 1. Forward-compat: deserializing a bundle written before SMS support leaves
// this at Array.Empty<SmsConfigDto>() — consumers always see an empty list,
// never null.
@@ -146,7 +146,7 @@ public sealed record TemplateScriptDto(
string? ReturnDefinition,
bool IsLocked,
TimeSpan? MinTimeBetweenRuns,
// M2.5 (#9): per-script execution timeout (seconds). Additive trailing field;
// Per-script execution timeout (seconds). Additive trailing field;
// null on bundles written before this field existed.
int? ExecutionTimeoutSeconds = null);
@@ -189,12 +189,12 @@ public sealed record NotificationListDto(
public sealed record NotificationRecipientDto(
string Name,
// S10: nullable so an SMS-only recipient (no email) round-trips faithfully
// Nullable so an SMS-only recipient (no email) round-trips faithfully
// instead of being coerced to an empty string. Email-only recipients (the
// historical case) still carry a non-null address; the entity enforces that at
// least one contact is present.
string? EmailAddress,
// S10: SMS recipients carry an E.164 phone number instead of (or in addition
// SMS recipients carry an E.164 phone number instead of (or in addition
// to) an email. Trailing + nullable so a bundle written before SMS support
// deserializes this as null (backward-compatible); the serializer's
// WhenWritingNull policy keeps it out of email-only bundles' JSON.
@@ -228,8 +228,9 @@ public sealed record SmsConfigDto(
TimeSpan RetryDelay,
SecretsBlock? Secrets);
// Legacy DTO: only deserialized from pre-C4 bundles so the importer can count and
// ignore the keys they contain. New exports never emit an ApiKeys array.
// Legacy DTO: only deserialized from bundles produced before the inbound-API-key
// re-architecture so the importer can count and ignore the keys they contain.
// New exports never emit an ApiKeys array.
public sealed record ApiKeyDto(
string Name,
string KeyHash,
@@ -237,7 +238,7 @@ public sealed record ApiKeyDto(
SecretsBlock? Secrets);
// ApprovedApiKeyIds is intentionally absent: it linked methods to keys that are no
// longer transported (re-arch C4). Scopes are re-granted per environment. The field
// longer transported. Scopes are re-granted per environment. The field
// in any old bundle is simply ignored on read.
public sealed record ApiMethodDto(
string Name,
@@ -246,7 +247,7 @@ public sealed record ApiMethodDto(
string? ReturnDefinition,
int TimeoutSeconds);
// --- M8: site/instance-scoped transport DTOs --------------------------------
// --- Site/instance-scoped transport DTOs --------------------------------
// These travel alongside the original central-config DTOs above. Sites and
// instances are referenced by their stable string identities (SiteIdentifier,
// UniqueName, TemplateName) rather than database ids so a bundle resolves
@@ -29,7 +29,7 @@ public sealed class EntitySerializer
var folderNameById = aggregate.TemplateFolders.ToDictionary(f => f.Id, f => f.Name);
var templateNameById = aggregate.Templates.ToDictionary(t => t.Id, t => t.Name);
// M8 name-link lookups. Instances/data-connections reference their owning
// Name-link lookups. Instances/data-connections reference their owning
// site by the portable SiteIdentifier (not the EF surrogate SiteId); a
// connection binding references its DataConnection by Name. Build both
// id→name maps once so the projections below resolve in O(1).
@@ -138,7 +138,7 @@ public sealed class EntitySerializer
NotificationLists: aggregate.NotificationLists.Select(nl => new NotificationListDto(
Name: nl.Name,
Type: nl.Type,
// S10: carry BOTH contacts. Keep any recipient that has at least
// Carry BOTH contacts. Keep any recipient that has at least
// one contact (email OR phone) — SMS-only recipients have a null
// EmailAddress and would have been dropped by the old email-only
// filter. EmailAddress/PhoneNumber are nullable on the DTO so a
@@ -172,7 +172,7 @@ public sealed class EntitySerializer
RetryDelay: smtp.RetryDelay,
Secrets: secrets);
}).ToList(),
// Inbound API keys are not transported between environments (re-arch C4):
// Inbound API keys are not transported between environments:
// the bundle carries API methods only. ApiMethod.ApprovedApiKeyIds is also
// excluded — it references keys that aren't in the bundle; method→key scopes
// are re-granted per environment via the admin UI/CLI. The legacy ApiKeys
@@ -184,7 +184,7 @@ public sealed class EntitySerializer
ReturnDefinition: m.ReturnDefinition,
TimeoutSeconds: m.TimeoutSeconds)).ToList())
{
// M8 site/instance-scoped payloads. These are init-only (non-positional)
// Site/instance-scoped payloads. These are init-only (non-positional)
// on BundleContentDto, so they're set via object-initializer here.
Sites = aggregate.Sites.Select(s => new SiteDto(
SiteIdentifier: s.SiteIdentifier,
@@ -218,7 +218,7 @@ public sealed class EntitySerializer
FailoverRetryCount: c.FailoverRetryCount,
Secrets: secretValues.Count > 0 ? new SecretsBlock(secretValues) : null);
}).ToList(),
// SMS (S10): mirror the SMTP secret handling exactly — the provider
// SMS: mirror the SMTP secret handling exactly — the provider
// auth token (never a public field) rides inside the SecretsBlock, so a
// "share without secrets" export can drop it as a unit. Omit the secret
// entirely when the token is null/empty so the importer's TryGetValue
@@ -248,7 +248,7 @@ public sealed class EntitySerializer
UniqueName: inst.UniqueName,
TemplateName: templateNameById.TryGetValue(inst.TemplateId, out var tn) ? tn : string.Empty,
SiteIdentifier: siteIdentifierBySiteId.TryGetValue(inst.SiteId, out var isid) ? isid : string.Empty,
// TODO(M8): Areas don't travel in the bundle yet — EntityAggregate
// TODO: Areas don't travel in the bundle yet — EntityAggregate
// carries no Areas collection, so there's no id→name lookup. Emit
// null until area transport is added; the importer leaves AreaId null.
AreaName: null,
@@ -268,7 +268,7 @@ public sealed class EntitySerializer
ConditionFilterOverride: o.ConditionFilterOverride)).ToList(),
// Connection bindings reference their DataConnection by NAME — the
// numeric DataConnectionId FK can't survive a cross-environment
// bundle, so the importer (D1) resolves ConnectionName→target FK at
// bundle, so the importer resolves ConnectionName→target FK at
// apply time. If the FK doesn't resolve in this aggregate (orphan
// row), the name comes through empty.
ConnectionBindings: inst.ConnectionBindings.Select(b => new InstanceConnectionBindingDto(
@@ -424,7 +424,7 @@ public sealed class EntitySerializer
var list = new NotificationList(dto.Name) { Id = ix + 1, Type = dto.Type };
foreach (var r in dto.Recipients)
{
// S10: reconstruct whichever contact(s) the bundle carries.
// Reconstruct whichever contact(s) the bundle carries.
// Email-present recipients use the email ctor (unchanged
// historical path) and additively restore the phone number;
// phone-only recipients (null email) take the SMS factory so we
@@ -453,7 +453,7 @@ public sealed class EntitySerializer
})
.ToList();
// SMS (S10): mirror the SMTP path — restore AccountSid/FromNumber and decrypt
// SMS: mirror the SMTP path — restore AccountSid/FromNumber and decrypt
// the auth token back out of the SecretsBlock (null when the key was omitted
// because the source token was null/empty).
var smsConfigurations = content.SmsConfigs
@@ -469,7 +469,7 @@ public sealed class EntitySerializer
})
.ToList();
// Inbound API keys are not transported (re-arch C4) — content.ApiKeys is a
// Inbound API keys are not transported — content.ApiKeys is a
// legacy field only present on pre-C4 bundles; it is ignored here. The
// BundleImporter is responsible for counting and reporting any such keys.
// ApiMethod.ApprovedApiKeyIds is likewise not reconstructed: scopes are
@@ -484,7 +484,7 @@ public sealed class EntitySerializer
})
.ToList();
// M8: sites first — assign synthetic ids by ordinal. Addresses are carried
// Sites first — assign synthetic ids by ordinal. Addresses are carried
// verbatim; the importer decides whether to keep or rewrite them.
var sites = content.Sites
.Select((dto, ix) => new Site(dto.Name, dto.SiteIdentifier)
@@ -516,7 +516,7 @@ public sealed class EntitySerializer
// Instances: resolve template + site by name/identifier. Areas don't travel
// (see export TODO), so AreaId stays null. Connection bindings keep their
// resolved DataConnection NAME on the wire DTO — the importer (D1) reads
// resolved DataConnection NAME on the wire DTO — the importer reads
// bindings from BundleContentDto.Instances[].ConnectionBindings directly and
// resolves ConnectionName→the target environment's DataConnectionId at apply
// time. FromBundleContent is NOT on the importer's path (BundleImporter walks
@@ -13,7 +13,7 @@ public sealed class ManifestBuilder
{
public const int CurrentBundleFormatVersion = 1;
// Schema minor version. Bumped 1.0 → 1.1 in M8 to carry the additive
// Schema minor version. Bumped 1.0 → 1.1 to carry the additive
// site/dataConnection/instance summary counts (and their content arrays).
// Minor bumps are additive-only: ManifestValidator gates solely on
// BundleFormatVersion, so an older "1.0" bundle still validates Ok.