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
@@ -3,7 +3,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types;
namespace ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
/// <summary>
/// Central operational state row for a cached call (Site Call Audit #22, Audit Log #23 M3).
/// Central operational state row for a cached call.
/// One row per <see cref="TrackedOperationId"/> in the <c>SiteCalls</c> table — append-once
/// then monotonic status update. Status transitions are forward-only
/// (<c>Submitted → Forwarded → Attempted → Delivered|Failed|Parked|Discarded</c>); an
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Entities.Deployment;
/// <summary>
/// WP-8: Stores the deployed configuration snapshot for an instance.
/// Stores the deployed configuration snapshot for an instance.
/// Captured at deploy time; compared against template-derived (live flattened) config for staleness detection.
/// </summary>
public class DeployedConfigSnapshot
@@ -50,7 +50,7 @@ public class DeploymentRecord
public string? ErrorMessage { get; set; }
/// <summary>
/// WP-4: Optimistic concurrency token for deployment status updates.
/// Optimistic concurrency token for deployment status updates.
/// </summary>
public byte[] RowVersion { get; set; } = [];
@@ -2,7 +2,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi;
/// <summary>
/// A single point-in-time KPI measurement in the central KPI-history backbone
/// (M6 "KPI History &amp; Trends"). One row per (Source, Metric, Scope, ScopeKey)
/// ("KPI History &amp; Trends"). One row per (Source, Metric, Scope, ScopeKey)
/// captured by the recorder singleton at a sampling instant — a tall / EAV row in
/// the central <c>KpiSample</c> table.
/// </summary>
@@ -48,7 +48,7 @@ public class Notification
public string? SourceScript { get; set; }
/// <summary>
/// The originating script execution's <c>ExecutionId</c> (Audit Log #23). Carried from
/// The originating script execution's <c>ExecutionId</c>. Carried from
/// the site on the <see cref="Commons.Messages.Notification.NotificationSubmit"/> so the
/// central dispatcher can stamp the same id onto its <c>NotifyDeliver</c> audit rows,
/// correlating them with the site-emitted <c>NotifySend</c> row. Null for notifications
@@ -57,7 +57,7 @@ public class Notification
public Guid? OriginExecutionId { get; set; }
/// <summary>
/// The originating routed script execution's <c>ParentExecutionId</c> (Audit Log #23).
/// The originating routed script execution's <c>ParentExecutionId</c>.
/// Carried from the site on the <see cref="Commons.Messages.Notification.NotificationSubmit"/>
/// so the central dispatcher can stamp the same parent id onto its <c>NotifyDeliver</c>
/// audit rows, correlating them with the site-emitted <c>NotifySend</c> row. Null for
@@ -1,10 +1,10 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Entities.Schemas;
/// <summary>
/// A reusable, named JSON-Schema library entry (M9 template-level JSON-Schema library,
/// Task T32a). Schemas are referenced from inbound-API / template schema definitions via a
/// <c>{"$ref":"lib:Name"}</c> pointer resolved against this library (the resolver lands in
/// T32b). One row per named schema in the central <c>SharedSchemas</c> MS SQL table.
/// A reusable, named JSON-Schema library entry (template-level JSON-Schema library).
/// Schemas are referenced from inbound-API / template schema definitions via a
/// <c>{"$ref":"lib:Name"}</c> pointer resolved against this library. One row per
/// named schema in the central <c>SharedSchemas</c> MS SQL table.
/// </summary>
/// <remarks>
/// Persistence-ignorant POCO; the EF Core mapping lives in the Configuration Database
@@ -2,7 +2,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Entities.SecuredWrites;
/// <summary>
/// Central operational state row for a two-person ("secured") write through its
/// lifecycle (M7 OPC UA / MxGateway UX, Task T14b). One row per pending write in the
/// lifecycle. One row per pending write in the
/// central <c>PendingSecuredWrites</c> MS SQL table — append-once at submission then
/// mutated as the request is approved/rejected and executed against the target.
/// </summary>
@@ -3,7 +3,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Kpi;
/// <summary>
/// A DI-registered provider of KPI samples (M6 "KPI History &amp; Trends"),
/// A DI-registered provider of KPI samples ("KPI History &amp; Trends"),
/// implemented by each owning component and enumerated by the central recorder
/// singleton at every sampling interval. The recorder stamps a single
/// <c>capturedAtUtc</c>, fans out to every source's <see cref="CollectAsync"/>,
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Protocol;
/// <summary>
/// M7-B4 (T15): optional capability for an <see cref="IDataConnection"/>
/// Optional capability for an <see cref="IDataConnection"/>
/// implementation that supports a bounded recursive search of the server's
/// address space. A complement to <see cref="IBrowsableDataConnection"/>:
/// where browse walks one level at a time on user demand, search walks the
@@ -5,7 +5,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
/// <summary>
/// Append-only data access for the central <c>AuditLog</c> table (Audit Log #23).
/// Append-only data access for the central <c>AuditLog</c> table.
/// </summary>
/// <remarks>
/// <para>
@@ -65,7 +65,7 @@ public interface IAuditLogRepository
/// EventId uniqueness — required by <see cref="InsertIfNotExistsAsync"/> —
/// can be enforced cheaply). SQL Server rejects
/// <c>ALTER TABLE … SWITCH PARTITION</c> while a non-aligned unique index
/// is present, so the M6 implementation drops the index, creates a staging
/// is present, so the implementation drops the index, creates a staging
/// table with byte-identical schema, switches the partition's data into
/// staging, drops staging (discarding the rows), and rebuilds the unique
/// index. The CATCH branch guarantees the index is rebuilt even on partial
@@ -88,7 +88,7 @@ public interface IAuditLogRepository
Task<long> SwitchOutPartitionAsync(DateTime monthBoundary, CancellationToken ct = default);
/// <summary>
/// M5.5 (T3) per-channel retention override purge. Deletes <c>AuditLog</c> rows for a
/// Per-channel retention override purge. Deletes <c>AuditLog</c> rows for a
/// single <paramref name="channel"/> (matched against the canonical
/// <c>Category</c> column — the bare channel name, e.g. <c>ApiOutbound</c>) whose
/// <c>OccurredAtUtc</c> is strictly older than <paramref name="threshold"/>, in
@@ -128,7 +128,7 @@ public interface IAuditLogRepository
/// boundaries whose partitions contain only rows with
/// <see cref="AuditEvent.OccurredAtUtc"/> strictly older than
/// <paramref name="threshold"/>. Boundaries whose partition is empty are
/// excluded (a no-op switch is wasted work). Used by the M6 purge actor
/// excluded (a no-op switch is wasted work). Used by the purge actor
/// to enumerate retention-eligible months on every tick.
/// </summary>
/// <param name="threshold">Only partitions whose data is entirely older than this UTC datetime are returned.</param>
@@ -139,7 +139,7 @@ public interface IAuditLogRepository
CancellationToken ct = default);
/// <summary>
/// Audit Log (#23) M7 Bundle E (T13) — returns aggregate counts over the
/// Returns aggregate counts over the
/// trailing <paramref name="window"/> driving the central Health
/// dashboard's Audit KPI tiles.
/// </summary>
@@ -185,7 +185,7 @@ public interface IAuditLogRepository
CancellationToken ct = default);
/// <summary>
/// Audit Log ParentExecutionId feature (Task 8) — given any
/// Audit Log ParentExecutionId feature — given any
/// <paramref name="executionId"/> in an execution chain, returns the whole
/// chain rooted at the topmost ancestor: one <see cref="ExecutionTreeNode"/>
/// per distinct execution, summarising its <c>AuditLog</c> rows. The Central
@@ -239,7 +239,7 @@ public interface IAuditLogRepository
Task<IReadOnlyList<string>> GetDistinctSourceNodesAsync(CancellationToken ct = default);
/// <summary>
/// M5.6 (T5) one-time operational backfill: sets <c>SourceNode</c> to
/// One-time operational backfill: sets <c>SourceNode</c> to
/// <paramref name="sentinel"/> on every row where <c>SourceNode IS NULL</c>
/// and <c>OccurredAtUtc &lt; <paramref name="before"/></c>, in bounded
/// batches of <paramref name="batchSize"/> rows, looping until no further
@@ -107,7 +107,7 @@ public interface IDeploymentManagerRepository
/// <returns>A task representing the asynchronous operation.</returns>
Task DeleteSystemArtifactDeploymentAsync(int id, CancellationToken cancellationToken = default);
// WP-8: DeployedConfigSnapshot
// DeployedConfigSnapshot
/// <summary>
/// Gets the deployed config snapshot for an instance.
/// </summary>
@@ -17,7 +17,7 @@ public interface IExternalSystemRepository
/// Returns the external system with the given name, or <c>null</c> if no such
/// system exists. A name-keyed lookup so hot-path resolution (e.g. a script's
/// <c>ExternalSystem.Call()</c>) does not have to fetch every system and filter
/// in memory on each call (ExternalSystemGateway-011).
/// in memory on each call.
/// </summary>
/// <param name="name">The external system name.</param>
/// <param name="cancellationToken">Cancellation token.</param>
@@ -68,7 +68,7 @@ public interface IExternalSystemRepository
/// Returns the method with the given name belonging to the given external system,
/// or <c>null</c> if no such method exists. A name-keyed lookup so hot-path
/// resolution does not have to fetch every method of the system and filter in
/// memory on each call (ExternalSystemGateway-011).
/// memory on each call.
/// </summary>
/// <param name="externalSystemId">The external system ID.</param>
/// <param name="methodName">The method name.</param>
@@ -121,8 +121,7 @@ public interface IExternalSystemRepository
/// Returns the database connection definition with the given name, or <c>null</c>
/// if no such connection exists. A name-keyed lookup so hot-path resolution (e.g.
/// a script's <c>Database.Connection()</c> / <c>Database.CachedWrite()</c>) does
/// not have to fetch every connection and filter in memory on each call
/// (ExternalSystemGateway-011).
/// not have to fetch every connection and filter in memory on each call.
/// </summary>
/// <param name="name">The database connection name.</param>
/// <param name="cancellationToken">Cancellation token.</param>
@@ -4,7 +4,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
public interface IInboundApiRepository
{
// ApiKey persistence retired (re-arch C5): inbound API keys live in the shared
// ApiKey persistence retired: inbound API keys live in the shared
// ZB.MOM.WW.Auth.ApiKeys SQLite store, not the SQL Server configuration DB. The
// former GetApiKeyByIdAsync / GetAllApiKeysAsync / GetApiKeyByValueAsync /
// AddApiKeyAsync / UpdateApiKeyAsync / DeleteApiKeyAsync / GetApprovedKeysForMethodAsync
@@ -4,7 +4,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Kpi;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
/// <summary>
/// Data access for the central KPI-history backbone (M6 "KPI History &amp; Trends")
/// Data access for the central KPI-history backbone ("KPI History &amp; Trends")
/// — the tall / EAV <c>KpiSample</c> table in central MS SQL. Backs the recorder
/// singleton's bulk write, the bucketed query path that feeds the reusable trend
/// chart, and the retention purge. Implementation lives in the Configuration
@@ -3,10 +3,10 @@ using ZB.MOM.WW.ScadaBridge.Commons.Entities.SecuredWrites;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
/// <summary>
/// Operational-state data access for the central <c>PendingSecuredWrites</c> table
/// (M7 OPC UA / MxGateway UX, Task T14b). One row per pending two-person secured
/// Operational-state data access for the central <c>PendingSecuredWrites</c> table.
/// One row per pending two-person secured
/// write; rows are inserted at submission and mutated as the request is decided and
/// executed. Mirrors the <c>SiteCalls</c> (Site Call Audit #22) repository shape.
/// executed. Mirrors the <c>SiteCalls</c> repository shape.
/// </summary>
public interface ISecuredWriteRepository
{
@@ -58,8 +58,8 @@ public interface ISecuredWriteRepository
/// <summary>
/// Atomically flips a row from <c>Pending</c> to <c>Approved</c>, stamping the
/// verifier identity, comment, and decision time, but ONLY if the row is still
/// <c>Pending</c>. This is the compare-and-swap guard for the two-verifier race
/// (M7 / T14b): two verifiers may approve the same write concurrently, but the
/// <c>Pending</c>. This is the compare-and-swap guard for the two-verifier race:
/// two verifiers may approve the same write concurrently, but the
/// conditional <c>WHERE Status='Pending'</c> guarantees exactly one wins. The
/// loser observes <c>false</c> and must not relay the write.
/// </summary>
@@ -3,10 +3,10 @@ using ZB.MOM.WW.ScadaBridge.Commons.Entities.Schemas;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
/// <summary>
/// Data access for the central <c>SharedSchemas</c> JSON-Schema library table
/// (M9 template-level JSON-Schema library, Task T32a). One row per named schema; the
/// Data access for the central <c>SharedSchemas</c> JSON-Schema library table.
/// One row per named schema; the
/// unique <see cref="SharedSchema.Name"/> is the lookup key used by the <c>lib:Name</c>
/// <c>$ref</c> resolver (T32b).
/// <c>$ref</c> resolver.
/// </summary>
public interface ISharedSchemaRepository
{
@@ -5,15 +5,15 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
/// <summary>
/// Operational-state data access for the central <c>SiteCalls</c> table
/// (Site Call Audit #22, Audit Log #23 M3 Bundle B). One row per
/// Operational-state data access for the central <c>SiteCalls</c> table.
/// One row per
/// <see cref="TrackedOperationId"/>; sites remain the source of truth and this
/// table is an eventually-consistent mirror fed by best-effort gRPC telemetry
/// plus periodic reconciliation pulls.
/// </summary>
/// <remarks>
/// <para>
/// Unlike the partitioned append-only <c>AuditLog</c> (M1), this table holds
/// Unlike the partitioned append-only <c>AuditLog</c>, this table holds
/// mutable operational state. <see cref="UpsertAsync"/> is insert-if-not-exists
/// then monotonic update — a status update with rank less than or equal to the
/// stored status is a silent no-op so out-of-order telemetry, duplicate gRPC
@@ -21,8 +21,8 @@ public interface ITemplateEngineRepository
/// Bulk variant of <see cref="GetTemplateWithChildrenAsync(int, CancellationToken)"/>
/// that fetches every template whose <see cref="Template.Name"/> matches one of
/// <paramref name="names"/> in a single SQL/EF query, eager-loading
/// Attributes / Alarms / Scripts / Compositions. Resolves the Transport-008
/// N+1 in <c>BundleImporter.PreviewAsync</c> — names that don't match an
/// Attributes / Alarms / Scripts / Compositions. Resolves the N+1
/// in <c>BundleImporter.PreviewAsync</c> — names that don't match an
/// existing template are omitted from the result rather than producing a
/// null entry, so callers should look up by name into the returned list.
/// </summary>
@@ -3,12 +3,12 @@ using ZB.MOM.WW.Audit;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
/// <summary>
/// Boundary-side abstraction for emitting Audit Log (#23) events.
/// Boundary-side abstraction for emitting Audit Log events.
/// Implementations on the site write to local SQLite hot-path; on central they write to MS SQL directly.
/// Failures must NEVER abort the user-facing action.
/// </summary>
/// <remarks>
/// C3 (Task 2.5): the event type is the canonical <see cref="ZB.MOM.WW.Audit.AuditEvent"/>.
/// The event type is the canonical <see cref="ZB.MOM.WW.Audit.AuditEvent"/>.
/// The local seam is retained (rather than collapsed onto <c>ZB.MOM.WW.Audit.IAuditWriter</c>)
/// so it stays a distinct DI binding from <see cref="ICentralAuditWriter"/> and so the many
/// existing site/central implementations and test fakes keep their identity.
@@ -3,7 +3,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
/// <summary>
/// Audit Log #23 (M3 Bundle E — Tasks E4/E5): site-side hook the
/// Site-side hook the
/// store-and-forward retry loop invokes after every cached-call attempt and
/// at terminal-state transitions, so the audit pipeline can emit
/// <c>ApiCallCached</c>/<c>DbWriteCached</c> per-attempt rows and the
@@ -61,28 +61,28 @@ public interface ICachedCallLifecycleObserver
/// <param name="DurationMs">Duration of the attempt in milliseconds (null when not measured).</param>
/// <param name="SourceInstanceId">Originating instance, when known.</param>
/// <param name="ExecutionId">
/// Audit Log #23 (ExecutionId Task 4): the originating script execution's
/// The originating script execution's
/// per-run correlation id, threaded through the store-and-forward buffer from
/// the cached-call enqueue path. The audit bridge stamps it onto the
/// retry-loop <c>ApiCallCached</c>/<c>DbWriteCached</c> Attempted and
/// <c>CachedResolve</c> rows so they correlate with the rest of the run.
/// <c>null</c> for rows buffered before Task 4 (back-compat).
/// <c>null</c> for rows buffered before this field was introduced (back-compat).
/// </param>
/// <param name="SourceScript">
/// Audit Log #23 (ExecutionId Task 4): the originating script identifier,
/// The originating script identifier,
/// threaded alongside <paramref name="ExecutionId"/> so the retry-loop audit
/// rows carry the same <c>SourceScript</c> provenance the script-side cached
/// rows already do. <c>null</c> when not known.
/// </param>
/// <param name="ParentExecutionId">
/// Audit Log #23 (ParentExecutionId Task 6): the <c>ExecutionId</c> of the
/// The <c>ExecutionId</c> of the
/// inbound-API request that spawned the originating script execution,
/// threaded through the store-and-forward buffer alongside
/// <paramref name="ExecutionId"/>. The audit bridge stamps it onto the
/// retry-loop <c>ApiCallCached</c>/<c>DbWriteCached</c> Attempted and
/// <c>CachedResolve</c> rows so they correlate back to the spawning run.
/// <c>null</c> for a non-routed run and for rows buffered before Task 6
/// (back-compat).
/// <c>null</c> for a non-routed run and for rows buffered before this field
/// was introduced (back-compat).
/// </param>
public sealed record CachedCallAttemptContext(
TrackedOperationId TrackedOperationId,
@@ -3,8 +3,8 @@ using ZB.MOM.WW.ScadaBridge.Commons.Messages.Integration;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
/// <summary>
/// Site-side fan-out abstraction for cached-call lifecycle telemetry
/// (Audit Log #23 / M3). One <see cref="CachedCallTelemetry"/> packet carries
/// Site-side fan-out abstraction for cached-call lifecycle telemetry.
/// One <see cref="CachedCallTelemetry"/> packet carries
/// both an audit row and an operational <c>SiteCalls</c> upsert; the
/// implementation routes the audit half through <see cref="IAuditWriter"/>
/// and the operational half through the site-local tracking SQLite store.
@@ -12,7 +12,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
/// <remarks>
/// <para>
/// Defined in Commons so the script runtime (and the StoreAndForward retry
/// loop, Bundle E4) can take a dependency on the abstraction rather than on
/// loop) can take a dependency on the abstraction rather than on
/// the concrete forwarder living inside <c>ZB.MOM.WW.ScadaBridge.AuditLog</c> — the
/// existing dependency arrow runs from <c>SiteRuntime</c> to Commons, not to
/// AuditLog.
@@ -25,26 +25,26 @@ public interface IDatabaseGateway
/// Submits a SQL write to the store-and-forward engine for reliable delivery.
/// </summary>
/// <param name="trackedOperationId">
/// Audit Log #23 (M3): caller-supplied tracking id used as the
/// Caller-supplied tracking id used as the
/// store-and-forward message id so the S&amp;F retry loop can read it
/// back via <c>StoreAndForwardMessage.Id</c> and emit per-attempt /
/// terminal cached-write telemetry under the same id. Defaults to
/// <c>null</c> — when omitted the S&amp;F engine mints a fresh GUID and no
/// M3 telemetry is correlated (pre-M3 caller behaviour).
/// telemetry is correlated.
/// </param>
/// <param name="executionId">
/// Audit Log #23 (ExecutionId Task 4): the originating script execution's
/// The originating script execution's
/// per-run correlation id. When the write is buffered on a transient
/// failure this is threaded onto the S&amp;F message so the retry-loop
/// cached-write audit rows carry it. <c>null</c> when not threaded.
/// </param>
/// <param name="sourceScript">
/// Audit Log #23 (ExecutionId Task 4): the originating script identifier,
/// The originating script identifier,
/// threaded onto the buffered S&amp;F message alongside
/// <paramref name="executionId"/>. <c>null</c> when not known.
/// </param>
/// <param name="parentExecutionId">
/// Audit Log #23 (ParentExecutionId Task 6): the <c>ExecutionId</c> of the
/// The <c>ExecutionId</c> of the
/// inbound-API request that spawned the originating script execution.
/// When the write is buffered on a transient failure this is threaded onto
/// the S&amp;F message alongside <paramref name="executionId"/> so the
@@ -57,7 +57,7 @@ public interface IDatabaseGateway
/// <param name="originInstanceName">Optional name of the instance that originated the write.</param>
/// <param name="cancellationToken">Cancellation token for the buffering operation.</param>
/// <returns>
/// M2.3 (#7): an <see cref="ExternalCallResult"/> mirroring the External-System
/// An <see cref="ExternalCallResult"/> mirroring the External-System
/// API path (<c>IExternalSystemClient.CachedCallAsync</c>). The write is
/// attempted immediately:
/// <list type="bullet">
@@ -32,27 +32,27 @@ public interface IExternalSystemClient
/// <param name="originInstanceName">The instance name originating the call, or null.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <param name="trackedOperationId">
/// Audit Log #23 (M3): caller-supplied tracking id used as the
/// Caller-supplied tracking id used as the
/// store-and-forward message id so the S&amp;F retry loop can read it
/// back via <c>StoreAndForwardMessage.Id</c> and emit per-attempt /
/// terminal cached-call telemetry under the same id. Defaults to
/// <c>null</c> — when omitted the S&amp;F engine mints a fresh GUID and no
/// M3 telemetry is correlated (the legacy behaviour pre-M3 callers rely
/// telemetry is correlated (the legacy behaviour older callers rely
/// on).
/// </param>
/// <param name="executionId">
/// Audit Log #23 (ExecutionId Task 4): the originating script execution's
/// The originating script execution's
/// per-run correlation id. When the call is buffered on a transient
/// failure this is threaded onto the S&amp;F message so the retry-loop
/// cached-call audit rows carry it. <c>null</c> when not threaded.
/// </param>
/// <param name="sourceScript">
/// Audit Log #23 (ExecutionId Task 4): the originating script identifier,
/// The originating script identifier,
/// threaded onto the buffered S&amp;F message alongside
/// <paramref name="executionId"/>. <c>null</c> when not known.
/// </param>
/// <param name="parentExecutionId">
/// Audit Log #23 (ParentExecutionId Task 6): the <c>ExecutionId</c> of the
/// The <c>ExecutionId</c> of the
/// inbound-API request that spawned the originating script execution.
/// When the call is buffered on a transient failure this is threaded onto
/// the S&amp;F message alongside <paramref name="executionId"/> so the
@@ -81,7 +81,7 @@ public record ExternalCallResult(
string? ErrorMessage,
bool WasBuffered = false)
{
// Commons-021: thread-safe lazy parse — `Lazy<T>` with the default
// Thread-safe lazy parse — `Lazy<T>` with the default
// `LazyThreadSafetyMode.ExecutionAndPublication` guarantees that two
// concurrent readers see the same `DynamicJsonElement` instance, the
// `JsonDocument.Parse` runs at most once, and the published value is
@@ -97,7 +97,7 @@ public record ExternalCallResult(
/// <summary>
/// Parsed response as a dynamic object. Returns null if ResponseJson is null or empty.
/// Access properties directly: result.Response.result, result.Response.items[0].name, etc.
/// Thread-safe: concurrent readers share a single parsed instance (Commons-021).
/// Thread-safe: concurrent readers share a single parsed instance.
/// </summary>
public dynamic? Response => _response.Value;
}
@@ -1,6 +1,6 @@
using ZB.MOM.WW.ScadaBridge.Commons.Types;
// Commons-018: physically lives under Interfaces/Services/ to match the
// Physically lives under Interfaces/Services/ to match the
// established subfolder convention (REQ-COM-5b), but the namespace stays
// `ZB.MOM.WW.ScadaBridge.Commons.Interfaces` to avoid a cascading update to 9+ consumer
// files across ZB.MOM.WW.ScadaBridge.SiteRuntime, ZB.MOM.WW.ScadaBridge.AuditLog and ZB.MOM.WW.ScadaBridge.Host.
@@ -12,7 +12,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces;
/// Site-local source of truth for cached-operation tracking
/// (<c>ExternalSystem.CachedCall</c> / <c>Database.CachedWrite</c>) — alongside the
/// Store-and-Forward buffer, this is the row that <c>Tracking.Status(id)</c>
/// reads (Audit Log #23 / M3). One row per <see cref="TrackedOperationId"/>;
/// reads. One row per <see cref="TrackedOperationId"/>;
/// terminal rows are purged after a configurable retention window
/// (default 7 days).
/// </summary>
@@ -120,7 +120,7 @@ public interface IOperationTrackingStore
CancellationToken ct = default);
/// <summary>
/// Reconciliation read (Site Call Audit #22): return tracking rows whose
/// Reconciliation read: return tracking rows whose
/// <c>UpdatedAtUtc</c> is at or after <paramref name="sinceUtc"/> as
/// <see cref="SiteCallOperational"/> projections, ordered by
/// <c>UpdatedAtUtc</c> ascending and capped at <paramref name="batchSize"/>.
@@ -1,4 +1,4 @@
// Commons-018: physically lives under Interfaces/Services/ to match the
// Physically lives under Interfaces/Services/ to match the
// established subfolder convention (REQ-COM-5b), but the namespace stays
// `ZB.MOM.WW.ScadaBridge.Commons.Interfaces` to avoid a cascading update to consumers
// across ZB.MOM.WW.ScadaBridge.AuditLog and ZB.MOM.WW.ScadaBridge.ConfigurationDatabase. Adopting
@@ -8,8 +8,8 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces;
/// <summary>
/// Abstraction over the central AuditLog partition-function roll-forward
/// operation. M6-T5 introduces a daily-cadence hosted service
/// (<c>AuditLogPartitionMaintenanceService</c>) that calls
/// operation. A daily-cadence hosted service
/// (<c>AuditLogPartitionMaintenanceService</c>) calls
/// <see cref="EnsureLookaheadAsync"/> to make sure
/// <c>pf_AuditLog_Month</c> always has at least <c>LookaheadMonths</c> of
/// future boundaries available — otherwise inserts past the highest
@@ -5,7 +5,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
/// <summary>
/// Site-local audit-log queue surface consumed by the site
/// <c>SiteAuditTelemetryActor</c> drain loop and the M6
/// <c>SiteAuditTelemetryActor</c> drain loop and the
/// <c>SiteStreamGrpcServer.PullAuditEvents</c> reconciliation handler.
/// Extracted from <c>SqliteAuditWriter</c> so both consumers can be
/// unit-tested against a stub without touching SQLite; the
@@ -15,7 +15,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
/// <remarks>
/// Lives in Commons (rather than alongside <c>SqliteAuditWriter</c> in
/// <c>ZB.MOM.WW.ScadaBridge.AuditLog</c>) because <c>ZB.MOM.WW.ScadaBridge.Communication</c> — which
/// hosts the M6 gRPC pull handler — must depend on this interface and
/// hosts the gRPC pull handler — must depend on this interface and
/// <c>ZB.MOM.WW.ScadaBridge.AuditLog</c> already depends on <c>ZB.MOM.WW.ScadaBridge.Communication</c>.
/// Pulling the interface up to Commons breaks the would-be cycle while
/// keeping the implementation in the AuditLog component.
@@ -34,7 +34,7 @@ public interface ISiteAuditQueue
/// <see cref="MarkForwardedAsync"/> will yield the same rows again.
/// </summary>
/// <remarks>
/// AuditLog-001: cached-lifecycle audit kinds
/// Cached-lifecycle audit kinds
/// (<see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.CachedSubmit"/>,
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.ApiCallCached"/>,
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.DbWriteCached"/>,
@@ -51,7 +51,7 @@ public interface ISiteAuditQueue
Task<IReadOnlyList<AuditEvent>> ReadPendingAsync(int limit, CancellationToken ct = default);
/// <summary>
/// AuditLog-001: returns up to <paramref name="limit"/> rows in
/// Returns up to <paramref name="limit"/> rows in
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Pending"/>
/// whose audit kind belongs to the cached-call lifecycle
/// vocabulary (<see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.CachedSubmit"/>,
@@ -71,7 +71,7 @@ public interface ISiteAuditQueue
/// transport specified in Component-AuditLog.md §"Cached Operations —
/// Combined Telemetry": cached rows MUST flow with their matching
/// <c>SiteCalls</c> upsert through one MS SQL transaction at central. The
/// pre-AuditLog-001 implementation drained cached rows through the
/// prior implementation drained cached rows through the
/// audit-only path, leaving the operational half unsent and the central
/// dual-write handler unreachable. Returning them via this dedicated read
/// surface lets the new drain join with the tracking store before push.
@@ -93,7 +93,7 @@ public interface ISiteAuditQueue
Task MarkForwardedAsync(IReadOnlyList<Guid> eventIds, CancellationToken ct = default);
/// <summary>
/// M6 reconciliation-pull read surface: returns up to <paramref name="batchSize"/>
/// Reconciliation-pull read surface: returns up to <paramref name="batchSize"/>
/// rows whose <see cref="AuditEvent.OccurredAtUtc"/> &gt;= <paramref name="sinceUtc"/>
/// and whose <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState"/> is still
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Pending"/> or
@@ -115,7 +115,7 @@ public interface ISiteAuditQueue
DateTime sinceUtc, int batchSize, CancellationToken ct = default);
/// <summary>
/// M6 reconciliation-pull commit surface: flips the supplied EventIds to
/// Reconciliation-pull commit surface: flips the supplied EventIds to
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Reconciled"/>,
/// but ONLY for rows currently in
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Pending"/> or
@@ -129,7 +129,7 @@ public interface ISiteAuditQueue
Task MarkReconciledAsync(IReadOnlyList<Guid> eventIds, CancellationToken ct = default);
/// <summary>
/// M6 Bundle E (T6) health-metric surface: returns a point-in-time snapshot
/// Health-metric surface: returns a point-in-time snapshot
/// of the site queue's pending count + oldest pending timestamp + on-disk
/// SQLite file size. Surfaced on
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Messages.Health.SiteHealthReport"/> as
@@ -5,7 +5,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Transport;
/// audit log entries emitted by the audited repository methods invoked during
/// ApplyAsync. AuditService reads this and stamps every AuditLogEntry it writes.
/// <para>
/// Thread-safety / concurrency contract (Transport-009): the in-tree
/// Thread-safety / concurrency contract: the in-tree
/// implementation backs <see cref="BundleImportId"/> with an
/// <see cref="System.Threading.AsyncLocal{T}"/> so each logical asynchronous
/// call chain — every distinct <c>BundleImporter.ApplyAsync</c> invocation —
@@ -30,7 +30,7 @@ public interface IBundleImporter
/// <param name="ct">Cancellation token.</param>
/// <param name="nameMap">
/// The operator-supplied resolution of every source-environment site and connection
/// name the bundle references (M8 D1). Each entry is either
/// name the bundle references. Each entry is either
/// <see cref="MappingAction.MapToExisting"/> (bind to an existing target site/connection)
/// or <see cref="MappingAction.CreateNew"/> (create one from the bundle payload). A
/// site or connection that the bundle references but that has no explicit entry here is
@@ -4,7 +4,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Transport;
/// Computes the CURRENT flattened-config revision hash of a deployed instance —
/// the same value the deployment pipeline produces and stores in
/// <c>DeployedConfigSnapshot.RevisionHash</c>. Transport's bundle importer uses
/// this to enumerate stale instances after a template overwrite (#16): an
/// this to enumerate stale instances after a template overwrite: an
/// instance is stale when its freshly-computed hash no longer matches the hash
/// captured at deploy time.
/// <para>
@@ -3,8 +3,8 @@ using ZB.MOM.WW.Audit;
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
/// <summary>
/// Akka message sent to the central <c>AuditLogIngestActor</c> (Audit Log #23,
/// M2 site-sync pipeline) carrying a batch of <see cref="AuditEvent"/> rows
/// Akka message sent to the central <c>AuditLogIngestActor</c> (site-sync
/// pipeline) carrying a batch of <see cref="AuditEvent"/> rows
/// decoded by the <c>SiteStreamGrpcServer</c> from a site's
/// <c>IngestAuditEvents</c> gRPC RPC. The actor stamps
/// <see cref="AuditEvent.IngestedAtUtc"/> and writes the rows idempotently to
@@ -4,8 +4,8 @@ using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
/// <summary>
/// Akka message sent to the central <c>AuditLogIngestActor</c> (Audit Log #23 M3
/// Bundle D dual-write transaction) carrying a batch of combined audit +
/// Akka message sent to the central <c>AuditLogIngestActor</c> (dual-write
/// transaction) carrying a batch of combined audit +
/// site-call telemetry packets decoded by the <c>SiteStreamGrpcServer</c> from a
/// site's <c>IngestCachedTelemetry</c> gRPC RPC. For each entry the actor writes
/// the <see cref="AuditEvent"/> row AND the <see cref="SiteCall"/> upsert inside
@@ -4,7 +4,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
/// <summary>
/// Site Calls UI -> Central: paginated, filtered query over the central
/// <c>SiteCalls</c> table (Site Call Audit #22). All filter fields are optional;
/// <c>SiteCalls</c> table. All filter fields are optional;
/// <see cref="StuckOnly"/> restricts results to stuck cached calls. Mirrors
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Messages.Notification.NotificationOutboxQueryRequest"/>
/// but uses keyset paging (<see cref="AfterCreatedAtUtc"/> + <see cref="AfterId"/>)
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
/// <summary>
/// Outcome of a Site Call Audit (#22) Retry/Discard relay — distinguishes the
/// Outcome of a Site Call Audit Retry/Discard relay — distinguishes the
/// three cases the Central UI Site Calls page must surface differently.
/// </summary>
/// <remarks>
@@ -3,8 +3,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
/// <summary>
/// Akka message sent to the central <c>SiteCallAuditActor</c> (Site Call Audit
/// #22, Audit Log #23 M3 Bundle C) carrying one <see cref="SiteCall"/> row to
/// Akka message sent to the central <c>SiteCallAuditActor</c> carrying one <see cref="SiteCall"/> row to
/// be persisted via <c>ISiteCallAuditRepository.UpsertAsync</c>. The repository
/// performs an insert-if-not-exists then monotonic update — duplicate gRPC
/// packets and reconciliation pulls can both feed the actor without rolling
@@ -13,7 +12,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
/// <remarks>
/// Lives in <c>ZB.MOM.WW.ScadaBridge.Commons</c> rather than <c>ZB.MOM.WW.ScadaBridge.SiteCallAudit</c>
/// so the gRPC server in <c>ZB.MOM.WW.ScadaBridge.Communication</c> can construct it
/// without taking a project reference on the actor's host project (Bundle D
/// adds the IngestCachedTelemetry RPC that will Tell this command).
/// without taking a project reference on the actor's host project — needed
/// once the IngestCachedTelemetry RPC that will Tell this command is added.
/// </remarks>
public sealed record UpsertSiteCallCommand(SiteCall SiteCall);
@@ -8,7 +8,6 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
/// when the upsert reached the repository without throwing (including the
/// monotonic-no-op case where the stored status' rank wins) and <c>false</c>
/// when persistence raised an exception. The actor itself stays alive in
/// either case — audit-write failures must NEVER abort the user-facing action
/// (Audit Log #23 §13).
/// either case — audit-write failures must NEVER abort the user-facing action.
/// </summary>
public sealed record UpsertSiteCallReply(TrackedOperationId TrackedOperationId, bool Accepted);
@@ -8,7 +8,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.DebugView;
/// </summary>
/// <remarks>
/// <para>
/// <b>Additive-only contract (M2.11):</b> <see cref="InstanceNotFound"/> is an
/// <b>Additive-only contract:</b> <see cref="InstanceNotFound"/> is an
/// optional trailing parameter with a default of <see langword="false"/> so every
/// existing positional constructor call and every existing serialized wire frame
/// remains valid. Callers that receive a snapshot with
@@ -33,7 +33,7 @@ public record DebugViewSnapshot(
IReadOnlyList<AttributeValueChanged> AttributeValues,
IReadOnlyList<AlarmStateChanged> AlarmStates,
DateTimeOffset SnapshotTimestamp,
// M2.11 — additive field: true when the requested instance is not registered
// Additive field: true when the requested instance is not registered
// on this site. Defaults to false so all existing call sites and wire
// frames are unaffected.
bool InstanceNotFound = false);
@@ -22,26 +22,26 @@ public record SiteHealthReport(
IReadOnlyDictionary<string, TagQualityCounts>? DataConnectionTagQuality = null,
int ParkedMessageCount = 0,
IReadOnlyList<NodeStatus>? ClusterNodes = null,
// Audit Log (#23) M2 Bundle G: per-interval count of FallbackAuditWriter
// Per-interval count of FallbackAuditWriter
// primary failures (SQLite throws routed to the drop-oldest ring). Surfaces
// a sustained audit-write outage on /monitoring/health. Defaults to 0 so
// existing producers / tests that don't construct the field stay valid.
int SiteAuditWriteFailures = 0,
// Audit Log (#23) M5 Bundle C: per-interval count of payload-filter
// Per-interval count of payload-filter
// redactor over-redactions (header / body / SQL parameter stages all
// throwing → field replaced with the "<redacted: redactor error>"
// marker). Surfaces a misconfigured / catastrophic regex on
// /monitoring/health. Defaults to 0 for back-compat with existing
// producers and tests that don't construct the field.
int AuditRedactionFailure = 0,
// Audit Log (#23) M6 Bundle E (T6): point-in-time snapshot of the
// Point-in-time snapshot of the
// site-local SQLite audit-log queue (pending count, oldest pending row,
// on-disk bytes). Populated by the site-side SiteAuditBacklogReporter
// hosted service every 30 s. Defaults to null so existing producers /
// tests that don't refresh the snapshot stay valid; the central health
// surface treats null as "no data yet" rather than a zeroed queue.
SiteAuditBacklogSnapshot? SiteAuditBacklog = null,
// Site Event Logging (#12) M2.16 (#30): cumulative count of event-log write
// Site Event Logging: cumulative count of event-log write
// failures (SQLite error, disk full, bounded-queue overflow drop) since the
// logger was created. Populated by the site-side SiteEventLogFailureCountReporter
// hosted service. Point-in-time (not reset on collect) — mirrors the
@@ -5,7 +5,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.InboundApi;
/// Used by Route.To("instanceCode").Call("scriptName", params).
/// </summary>
/// <param name="ParentExecutionId">
/// Audit Log #23 (ParentExecutionId): the spawning execution's <c>ExecutionId</c>
/// ParentExecutionId: the spawning execution's <c>ExecutionId</c>
/// — for an inbound-API-routed call this is the inbound request's per-request
/// execution id. The site records it as the routed script execution's
/// <c>ParentExecutionId</c> so a spawned execution points back at its spawner.
@@ -34,7 +34,7 @@ public record RouteToCallResponse(
/// Request to read attribute(s) from a remote instance.
/// </summary>
/// <param name="ParentExecutionId">
/// Audit Log #23 (ParentExecutionId): mirrors <see cref="RouteToCallRequest.ParentExecutionId"/>.
/// ParentExecutionId: mirrors <see cref="RouteToCallRequest.ParentExecutionId"/>.
/// For an inbound-API-routed read this is the inbound request's per-request execution id;
/// future site-side audit emission for routed reads can stamp it as <c>ParentExecutionId</c>
/// so the inbound→site execution-tree link survives the read path. Additive trailing
@@ -61,7 +61,7 @@ public record RouteToGetAttributesResponse(
/// Request to write attribute(s) on a remote instance.
/// </summary>
/// <param name="ParentExecutionId">
/// Audit Log #23 (ParentExecutionId): mirrors <see cref="RouteToCallRequest.ParentExecutionId"/>.
/// ParentExecutionId: mirrors <see cref="RouteToCallRequest.ParentExecutionId"/>.
/// For an inbound-API-routed write this is the inbound request's per-request execution id;
/// site-side audit emission for the underlying device / static-attribute write can stamp
/// it as <c>ParentExecutionId</c> so the inbound→site execution-tree link survives the
@@ -93,7 +93,7 @@ public record RouteToSetAttributesResponse(
/// times out.
/// </summary>
/// <param name="ParentExecutionId">
/// Audit Log #23 (ParentExecutionId): mirrors <see cref="RouteToCallRequest.ParentExecutionId"/>.
/// ParentExecutionId: mirrors <see cref="RouteToCallRequest.ParentExecutionId"/>.
/// For an inbound-API-routed wait this is the inbound request's per-request execution id;
/// future site-side audit emission for routed waits can stamp it as <c>ParentExecutionId</c>
/// so the inbound→site execution-tree link survives the wait path. Additive trailing
@@ -3,7 +3,7 @@ using ZB.MOM.WW.Audit;
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Integration;
/// <summary>
/// Audit Log (#23) telemetry envelope sent from a site to central over gRPC.
/// Audit Log telemetry envelope sent from a site to central over gRPC.
/// At-least-once delivery; central is idempotent on <see cref="AuditEvent.EventId"/>.
/// See Component-AuditLog.md "Ingestion" for the handoff contract.
/// </summary>
@@ -4,8 +4,8 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types;
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Integration;
/// <summary>
/// Combined audit + operational telemetry packet for cached outbound calls
/// (Audit Log #23 / M3). The site emits one packet per lifecycle event
/// Combined audit + operational telemetry packet for cached outbound calls.
/// The site emits one packet per lifecycle event
/// — <c>Submit</c> (Audit kind <c>CachedSubmit</c>), per-attempt
/// <c>ApiCallCached</c>/<c>DbWriteCached</c>, terminal <c>CachedResolve</c> —
/// and central writes the <see cref="AuditEvent"/> row plus the
@@ -18,16 +18,16 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Integration;
/// <para>
/// Both inner records carry the same <c>TrackedOperationId</c> — the
/// idempotency key end-to-end. The <see cref="AuditEvent.CorrelationId"/>
/// pattern (used by Audit Log #23 to thread cached-call rows together) is
/// pattern (used by Audit Log to thread cached-call rows together) is
/// honoured by the site emitter; the packet itself is shape-only and makes no
/// independent correlation guarantees.
/// </para>
/// <para>
/// Additive-only per Commons REQ-COM-5a (M2 reviewer note) — this is a new
/// message, not a rename of any existing M2 envelope.
/// Additive-only per Commons REQ-COM-5a — this is a new
/// message, not a rename of any existing envelope.
/// </para>
/// </remarks>
/// <param name="Audit">The Audit Log #23 row to insert at central.</param>
/// <param name="Audit">The Audit Log row to insert at central.</param>
/// <param name="Operational">The <c>SiteCalls</c> upsert mirroring this lifecycle event.</param>
public sealed record CachedCallTelemetry(
AuditEvent Audit,
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Integration;
/// <summary>
/// Audit Log (#23) periodic reconciliation pull request: central asks a site for
/// Audit Log periodic reconciliation pull request: central asks a site for
/// audit events since the given UTC watermark, up to <paramref name="BatchSize"/>.
/// Acts as the fallback when streaming telemetry is lost. See Component-AuditLog.md "Ingestion".
/// </summary>
@@ -3,7 +3,7 @@ using ZB.MOM.WW.Audit;
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Integration;
/// <summary>
/// Audit Log (#23) periodic reconciliation pull response: the next batch of site
/// Audit Log periodic reconciliation pull response: the next batch of site
/// audit events plus a <paramref name="MoreAvailable"/> flag signalling the caller
/// to advance the watermark and pull again. See Component-AuditLog.md "Ingestion".
/// </summary>
@@ -3,7 +3,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Integration;
/// <summary>
/// Site Call Audit (#22) periodic reconciliation pull response: the next batch of
/// Site Call Audit periodic reconciliation pull response: the next batch of
/// site cached-call operational rows (the eventually-consistent <c>SiteCalls</c>
/// mirror's self-heal feed) plus a <paramref name="MoreAvailable"/> flag signalling
/// the caller to advance the watermark and pull again. Mirrors
@@ -1,12 +1,12 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
// ─────────────────────────────────────────────────────────────────────────────
// T17 / D6 — OPC UA server-certificate trust management.
// OPC UA server-certificate trust management.
//
// Cert trust is SITE-LOCAL: there is no central persistence of trusted server
// certificates. The trusted-peer PKI store lives on each site node's file
// system, so a trust/remove decision must reach BOTH site nodes (node-a and
// node-b) or the two PKI stores diverge across failover (Decision D6).
// node-b) or the two PKI stores diverge across failover.
//
// The public commands below are handled by the site Deployment Manager
// singleton (active node only). For trust/remove it broadcasts the
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
// M9-T32c — schema-library authoring commands. The reusable named JSON-Schema
// library (the SharedSchema entity + ISharedSchemaRepository, T32a) gains its CRUD
// Schema-library authoring commands. The reusable named JSON-Schema
// library (the SharedSchema entity + ISharedSchemaRepository) gains its CRUD
// surface here. These records travel the same HTTP / ClusterClient management
// boundary as every other *Command and are auto-discovered by reflection in
// ManagementCommandRegistry (no manual registry entry needed).
@@ -1,10 +1,10 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
// ============================================================================
// Two-person ("secured") write commands (M7 OPC UA / MxGateway UX, Task T14b).
// Two-person ("secured") write commands.
//
// An Operator SUBMITS a pending secured write against an MxGateway data
// connection; a distinct Verifier later APPROVES (executes — Task C3) or
// connection; a distinct Verifier later APPROVES (executes) or
// REJECTS it. Separation of duties is enforced at the handler: a write may not
// be verified by the same principal that submitted it. ListSecuredWrites is a
// read-only query (any authenticated user). Role gating lives in
@@ -33,9 +33,9 @@ public record SubmitSecuredWriteCommand(
string? Comment);
/// <summary>
/// Verifier request to approve (and execute — handled by Task C3) a pending
/// Verifier request to approve (and execute) a pending
/// secured write. Declared here so the secured-write contract is complete; the
/// approve→execute relay handler and dispatch arm are implemented in C3.
/// approve→execute relay handler and dispatch arm are implemented separately.
/// </summary>
/// <param name="Id">Identity of the pending secured write.</param>
/// <param name="Comment">Optional free-text comment supplied by the verifier.</param>
@@ -5,7 +5,7 @@ public record GetTemplateCommand(int TemplateId);
public record CreateTemplateCommand(string Name, string? Description, int? ParentTemplateId);
/// <summary>
/// Updates a template. Optional fields use leave-unchanged semantics (followup #5):
/// Updates a template. Optional fields use leave-unchanged semantics:
/// a <c>null</c> <see cref="Description"/> keeps the stored description (pass an empty
/// string to clear it), and a <c>null</c> <see cref="ParentTemplateId"/> keeps the
/// existing parent (the parent is immutable; a non-null value that differs is rejected).
@@ -15,7 +15,7 @@ public record DeleteTemplateCommand(int TemplateId);
public record ValidateTemplateCommand(int TemplateId);
/// <summary>
/// Read-only authoring query (M9/T26a): returns the EFFECTIVE inherited member
/// Read-only authoring query: returns the EFFECTIVE inherited member
/// set for a template — computed fresh from the full inheritance chain
/// (arbitrary depth), annotated per member with origin + lock state — plus a
/// staleness summary comparing the template's stored rows against the resolved
@@ -52,7 +52,7 @@ public record ListTemplateNativeAlarmSourcesCommand(int TemplateId);
// MinTimeBetweenRuns mirrors the TemplateScript.MinTimeBetweenRuns TimeSpan throttle/re-fire interval;
// ExecutionTimeoutSeconds mirrors the per-script TemplateScript.ExecutionTimeoutSeconds override (seconds;
// null/non-positive falls back to the site's global default). Both were previously settable only via
// Transport bundle import — these fields close the CLI/UI authoring gap (#54). Additive-only: never reorder.
// Transport bundle import — these fields close the CLI/UI authoring gap. Additive-only: never reorder.
public record AddTemplateScriptCommand(int TemplateId, string Name, string Code, string? TriggerType, string? TriggerConfiguration, bool IsLocked, string? ParameterDefinitions = null, string? ReturnDefinition = null, TimeSpan? MinTimeBetweenRuns = null, int? ExecutionTimeoutSeconds = null);
public record UpdateTemplateScriptCommand(int ScriptId, string Name, string Code, string? TriggerType, string? TriggerConfiguration, bool IsLocked, string? ParameterDefinitions = null, string? ReturnDefinition = null, TimeSpan? MinTimeBetweenRuns = null, int? ExecutionTimeoutSeconds = null);
public record DeleteTemplateScriptCommand(int ScriptId);
@@ -8,7 +8,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
/// name lists and exports every entity of every supported type.
/// <para>
/// Inbound API keys are intentionally not selectable: per the inbound-API-key
/// re-architecture (C4) keys are not transported between environments; only API
/// re-architecture keys are not transported between environments; only API
/// methods travel. Re-create keys and re-grant their method scopes on the
/// destination via the admin UI/CLI.
/// </para>
@@ -25,13 +25,13 @@ public sealed record ExportBundleCommand(
bool IncludeDependencies,
string? Passphrase,
string SourceEnvironment,
// Additive (M8 B4): site/instance-scoped selection. Sites resolve by
// Additive: site/instance-scoped selection. Sites resolve by
// SiteIdentifier (preferred) or Name; instances resolve by UniqueName.
// Defaulted null so every existing positional caller keeps compiling; the
// handler normalizes null to "select nothing" (or everything under All=true).
IReadOnlyList<string>? SiteNames = null,
IReadOnlyList<string>? InstanceNames = null,
// Additive (S10b): SMS provider config selection, mirroring
// Additive: SMS provider config selection, mirroring
// SmtpConfigurationNames. SmsConfiguration is keyed by AccountSid (no Name
// column), so tokens are AccountSid values. Defaulted null so every existing
// positional caller keeps compiling.
@@ -59,17 +59,17 @@ public sealed record PreviewBundleResult(
int ModifiedCount,
int IdenticalCount,
int BlockerCount,
// Additive (M8 D3): site/connection references the operator must resolve
// Additive: site/connection references the operator must resolve
// before import, carried verbatim from ImportPreview. Defaulted to empty so
// every existing positional caller keeps compiling.
IReadOnlyList<RequiredSiteMapping>? RequiredSiteMappings = null,
IReadOnlyList<RequiredConnectionMapping>? RequiredConnectionMappings = null)
{
/// <summary>Site references the operator must resolve before import (M8). Never null.</summary>
/// <summary>Site references the operator must resolve before import. Never null.</summary>
public IReadOnlyList<RequiredSiteMapping> RequiredSiteMappings { get; init; } =
RequiredSiteMappings ?? Array.Empty<RequiredSiteMapping>();
/// <summary>Connection references the operator must resolve before import (M8). Never null.</summary>
/// <summary>Connection references the operator must resolve before import. Never null.</summary>
public IReadOnlyList<RequiredConnectionMapping> RequiredConnectionMappings { get; init; } =
RequiredConnectionMappings ?? Array.Empty<RequiredConnectionMapping>();
}
@@ -108,7 +108,7 @@ public sealed record ConnectionMappingSpec(
/// <c>"overwrite"</c>, <c>"rename"</c>. Rename mints a unique suffix per row.
/// </para>
/// <para>
/// M8 (D3): <paramref name="SiteMappings"/> / <paramref name="ConnectionMappings"/>
/// <paramref name="SiteMappings"/> / <paramref name="ConnectionMappings"/>
/// supply explicit operator resolutions for the source-environment site/connection
/// references the bundle carries; the handler merges them with the preview's
/// auto-matches and the <paramref name="CreateMissingSites"/> /
@@ -5,14 +5,14 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Notification;
/// Fire-and-forget with ack; the site retries until a <see cref="NotificationSubmitAck"/> is received.
/// </summary>
/// <param name="OriginExecutionId">
/// The originating script execution's <c>ExecutionId</c> (Audit Log #23). Stamped at
/// The originating script execution's <c>ExecutionId</c>. Stamped at
/// <c>Notify.Send</c> time and carried, inside the serialized payload, through the site
/// store-and-forward buffer so the central dispatcher can echo it onto the
/// <c>NotifyDeliver</c> audit rows. Additive trailing member — null for messages built
/// before the field existed, or for notifications raised outside a script execution.
/// </param>
/// <param name="OriginParentExecutionId">
/// The originating routed script execution's <c>ParentExecutionId</c> (Audit Log #23).
/// The originating routed script execution's <c>ParentExecutionId</c>.
/// Stamped at <c>Notify.Send</c> time and carried, inside the serialized payload, through
/// the site store-and-forward buffer so the central dispatcher can echo it onto the
/// <c>NotifyDeliver</c> audit rows. Additive trailing member — null for messages built
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.ScriptExecution;
/// <param name="ParentExecutionId">
/// Audit Log #23 (ParentExecutionId): the spawning execution's <c>ExecutionId</c>.
/// The spawning execution's <c>ExecutionId</c>.
/// For an inbound-API-routed call this is the inbound request's per-request
/// execution id (carried in from <c>RouteToCallRequest.ParentExecutionId</c>);
/// the routed script execution records it as its <c>ParentExecutionId</c> so a
@@ -10,7 +10,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
/// byte-deterministic output (System.Text.Json respects declared order).
/// </summary>
/// <remarks>
/// C1 of the ScadaBridge audit re-architecture (Task 2.5). Pure types only.
/// Pure types only.
/// </remarks>
public sealed record AuditDetails
{
@@ -26,7 +26,6 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
/// System.Text.Json honours declared order, so serialization is stable across calls.</item>
/// </list>
/// </para>
/// <para>C1 of the ScadaBridge audit re-architecture (Task 2.5).</para>
/// </remarks>
public static class AuditDetailsCodec
{
@@ -15,7 +15,6 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
/// that maps onto the canonical <c>Category</c> field.</item>
/// </list>
/// </para>
/// <para>C1 of the ScadaBridge audit re-architecture (Task 2.5).</para>
/// </remarks>
public static class AuditFieldBuilders
{
@@ -18,7 +18,6 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
/// <item>All other statuses (<c>Submitted</c>, <c>Forwarded</c>, <c>Attempted</c>,
/// <c>Skipped</c>) → <see cref="AuditOutcome.Success"/>.</item>
/// </list>
/// <para>C1 of the ScadaBridge audit re-architecture (Task 2.5).</para>
/// </remarks>
public static class AuditOutcomeProjector
{
@@ -5,7 +5,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
/// <summary>
/// Transitional canonical ⇄ 24-column shim for the two AuditLog storage
/// implementations (site SQLite, central SQL Server). C3 keeps the existing
/// implementations (site SQLite, central SQL Server). Keeps the existing
/// 24-column tables UNCHANGED; this helper decomposes a canonical
/// <see cref="ZB.MOM.WW.Audit.AuditEvent"/> into the typed domain values the
/// columns expect (Channel/Kind/Status enums + the <see cref="AuditDetails"/>
@@ -13,12 +13,11 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
/// </summary>
/// <remarks>
/// <para>
/// C3 of the ScadaBridge audit re-architecture (Task 2.5). The canonical record
/// The canonical record
/// only carries Action/Category/Outcome at the top level and stashes every
/// ScadaBridge domain field inside <c>DetailsJson</c>; the legacy storage rows
/// carry the domain fields as typed columns. This shim bridges the two without
/// any schema change. C4 replaces the site shim with the real DetailsJson
/// schema; C5 the central one.
/// any schema change.
/// </para>
/// <para>
/// <c>ForwardState</c> is deliberately NOT part of this projection — it is a
@@ -163,7 +162,7 @@ public static class AuditRowProjection
/// <summary>
/// Returns a copy of <paramref name="evt"/> with the central-side ingest timestamp
/// stamped into its <c>DetailsJson</c> (<see cref="AuditDetails.IngestedAtUtc"/>).
/// C3 transitional shim: <c>IngestedAtUtc</c> is a DetailsJson field on the canonical
/// <c>IngestedAtUtc</c> is a DetailsJson field on the canonical
/// record, so the central ingest paths stamp it here rather than on a top-level
/// property as the legacy bespoke record allowed.
/// </summary>
@@ -12,11 +12,11 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
/// identically everywhere — no per-site drift.
/// </summary>
/// <remarks>
/// <para>C3 of the ScadaBridge audit re-architecture (Task 2.5). The canonical
/// <para>The canonical
/// record is the type at every seam, emit site, DTO boundary, and redactor; the
/// ScadaBridge domain fields ride in <c>DetailsJson</c> via
/// <see cref="AuditDetailsCodec"/>.</para>
/// <para>Mapping (see Task 2.5 spec):
/// <para>Mapping:
/// <list type="bullet">
/// <item><c>Action</c> = <see cref="AuditFieldBuilders.BuildAction"/>(channel, kind).</item>
/// <item><c>Category</c> = <see cref="AuditFieldBuilders.BuildCategory"/>(channel) (= channel name).</item>
@@ -2,7 +2,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
/// <summary>
/// Point-in-time operational metrics for the central <c>SiteCalls</c> table
/// (Site Call Audit #22), surfaced on the health dashboard. The cached-call
/// surfaced on the health dashboard. The cached-call
/// counterpart of <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Notifications.NotificationKpiSnapshot"/>;
/// mirrors its shape so the Central UI Site Calls KPI tiles can reuse the
/// Notification Outbox tile layout.
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types;
/// <summary>
/// Audit Log (#23) M7 Bundle E (T13) — point-in-time KPI snapshot for the central
/// Point-in-time KPI snapshot for the central
/// Health dashboard's "Audit" tile group. Aggregates volume + error counts over
/// the trailing window from the central <c>AuditLog</c> table and combines them
/// with the global pending backlog summed across every site's
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
/// <summary>
/// Top-level Audit Log (#23) channel — the trust boundary the audited action crosses.
/// Top-level Audit Log channel — the trust boundary the audited action crosses.
/// One of: outbound API call, outbound DB write, notification send/deliver, inbound API request,
/// or a two-person ("secured") write through its submit/approve/reject/execute lifecycle.
/// </summary>
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
/// <summary>
/// Site-local Audit Log (#23) forwarding state, tracked only in the site SQLite hot-path.
/// Site-local Audit Log forwarding state, tracked only in the site SQLite hot-path.
/// Central rows leave this null. <c>Pending</c> = not yet sent; <c>Forwarded</c> = telemetry sent
/// and acked; <c>Reconciled</c> = confirmed present centrally via the periodic pull fallback.
/// The site retention purge MUST NOT drop a row whose state is still <c>Pending</c>.
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
/// <summary>
/// Specific Audit Log (#23) event kind within a channel — what action produced the row.
/// Specific Audit Log event kind within a channel — what action produced the row.
/// Cached variants emit multiple rows per operation (submit → forward → attempt → resolve).
/// The <c>SecuredWrite*</c> kinds emit one row per two-person-write lifecycle event
/// (submit → approve → execute, or submit → reject).
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
/// <summary>
/// Lifecycle status of an Audit Log (#23) event row.
/// Lifecycle status of an Audit Log event row.
/// Cached operations produce multiple rows tracking <c>Submitted → Forwarded → Attempted → Delivered/Parked/Discarded</c>.
/// <c>Skipped</c> is used when an action was short-circuited (e.g. dry-run) but should still be audited.
/// </summary>
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
/// <summary>
/// WP-9: Categories for store-and-forward messages.
/// Categories for store-and-forward messages.
/// </summary>
public enum StoreAndForwardCategory
{
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
/// <summary>
/// WP-9: Status of a store-and-forward message.
/// Status of a store-and-forward message.
/// </summary>
public enum StoreAndForwardMessageStatus
{
@@ -25,7 +25,7 @@ public sealed record ConfigurationDiff
/// <summary>
/// Diff entries for connection configurations, keyed by connection name.
/// Surfaces standalone endpoint/protocol/failover drift that does not show
/// up as a per-attribute binding change (TemplateEngine-018).
/// up as a per-attribute binding change.
/// </summary>
public IReadOnlyList<DiffEntry<ConnectionConfig>> ConnectionChanges { get; init; } = [];
}
@@ -16,7 +16,7 @@ public sealed record ValidationResult
/// <summary>
/// Produces a compact, human-readable summary of the validation errors instead of a
/// flat semicolon-joined dump (followup #8). The old behaviour concatenated one clause
/// flat semicolon-joined dump. The old behaviour concatenated one clause
/// per error — for an instance with 50194 unbound attributes that is a wall of text
/// unreadable in a CLI/UI toast. This groups errors by <see cref="ValidationCategory"/>
/// and, within a category, rolls entries up by "module" (the entity's canonical name up
@@ -183,7 +183,7 @@ public enum ValidationCategory
NativeAlarmSourceInvalid,
/// <summary>
/// M9-T32b: a script/method parameter or return JSON Schema contains a
/// A script/method parameter or return JSON Schema contains a
/// <c>{"$ref":"lib:Name"}</c> reference that could not be resolved against the
/// shared-schema library — dangling, cyclic, or over-depth. Deploy-blocking.
/// </summary>
@@ -64,7 +64,7 @@ public sealed class InboundApiSchema
/// <summary>
/// Parses a stored definition string into an <see cref="InboundApiSchema"/>,
/// resolving any <c>{"$ref":"lib:Name"}</c> library references (M9-T32b) through
/// resolving any <c>{"$ref":"lib:Name"}</c> library references through
/// the caller-supplied <paramref name="resolveRef"/> seam.
///
/// <para>
@@ -117,7 +117,7 @@ public sealed class InboundApiSchema
/// Parses a stored definition string into an <see cref="InboundApiSchema"/>,
/// resolving <c>{"$ref":"lib:Name"}</c> library references through the
/// caller-supplied <paramref name="resolveRef"/> seam, and COLLECTING (rather than
/// throwing on) any references that cannot be resolved (M9-T32b).
/// throwing on) any references that cannot be resolved.
///
/// <para>
/// This is the deploy-time entry point: a dangling, cyclic, or over-depth
@@ -176,7 +176,7 @@ public sealed class InboundApiSchema
throw new JsonException($"Schema nesting exceeds the maximum allowed depth of {MaxDepth}.");
}
// $ref resolution (M9-T32b): a {"$ref":"lib:Name"} node is replaced by the
// $ref resolution: a {"$ref":"lib:Name"} node is replaced by the
// referenced schema, resolved through the caller-supplied seam. Dangling,
// cyclic, and over-depth refs are recorded as unresolved (the caller decides
// whether to throw or collect) and parse continues with a shape-only schema.
@@ -243,7 +243,7 @@ public sealed class InboundApiSchema
private const string UnresolvedRefType = "ref";
/// <summary>
/// M9-T32b — cheap pre-flight check: does this definition JSON contain ANY
/// Cheap pre-flight check: does this definition JSON contain ANY
/// <c>$ref</c> token at all? Lets a caller (e.g. the InboundAPI runtime path) skip the
/// shared-schema library pre-load entirely when a schema uses no references — so a
/// <c>$ref</c>-free method pays NO extra cost beyond today. The check is intentionally
@@ -532,7 +532,7 @@ public sealed class InboundApiSchema
return;
}
// Reject undeclared fields (defensive, consistent with InboundAPI-010's
// Reject undeclared fields (defensive, consistent with the
// top-level "unexpected parameter" rejection) — a typo'd nested field is
// surfaced instead of silently ignored. Skipped when no fields are
// declared (a bare {"type":"object"} stays shape-only, like the legacy
@@ -609,7 +609,7 @@ public sealed record InboundApiSchemaField(string Name, bool Required, InboundAp
/// <summary>
/// A single <c>{"$ref":"lib:Name"}</c> reference that could NOT be resolved during
/// <see cref="InboundApiSchema.ParseWithRefs"/> (M9-T32b). The reference <see cref="Name"/>
/// <see cref="InboundApiSchema.ParseWithRefs"/>. The reference <see cref="Name"/>
/// is kept SEPARATE from the diagnostic <see cref="Reason"/> so a message can render the
/// pointer cleanly (e.g. <c>schema 'lib:Foo' could not be resolved (cyclic reference)</c>)
/// rather than embedding the annotation inside the <c>lib:</c>-looking string.
@@ -643,7 +643,7 @@ public sealed record UnresolvedSchemaRef(string Name, string? Reason)
}
/// <summary>
/// The outcome of <see cref="InboundApiSchema.ParseWithRefs"/> (M9-T32b): the parsed
/// The outcome of <see cref="InboundApiSchema.ParseWithRefs"/>: the parsed
/// schema (with <c>{"$ref":"lib:Name"}</c> references resolved where possible) plus the
/// references that could NOT be resolved — dangling (the seam returned <c>null</c> or no
/// seam was supplied), cyclic, or over-depth. A non-empty <see cref="UnresolvedReferences"/>
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Kpi;
/// <summary>
/// Canonical <em>charted</em> KPI metric-name identifiers (M6 "KPI History &amp;
/// Canonical <em>charted</em> KPI metric-name identifiers ("KPI History &amp;
/// Trends") — the value of <see cref="ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi.KpiSample.Metric"/>
/// for every metric a Central UI trend chart renders. Each owning
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Kpi.IKpiSampleSource"/> emits
@@ -30,7 +30,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Kpi;
public static class KpiMetrics
{
/// <summary>
/// Charted Notification Outbox (#21) metrics — <see cref="KpiSources.NotificationOutbox"/>.
/// Charted Notification Outbox metrics — <see cref="KpiSources.NotificationOutbox"/>.
/// Rendered by the Central UI Notification Outbox KPIs trend panel.
/// </summary>
public static class NotificationOutbox
@@ -46,7 +46,7 @@ public static class KpiMetrics
}
/// <summary>
/// Charted Site Call Audit (#22) metrics — <see cref="KpiSources.SiteCallAudit"/>.
/// Charted Site Call Audit metrics — <see cref="KpiSources.SiteCallAudit"/>.
/// Rendered by the Central UI Site Calls report trend panel.
/// </summary>
public static class SiteCallAudit
@@ -62,7 +62,7 @@ public static class KpiMetrics
}
/// <summary>
/// Charted Audit Log (#23) metrics — <see cref="KpiSources.AuditLog"/>.
/// Charted Audit Log metrics — <see cref="KpiSources.AuditLog"/>.
/// Rendered by the Central UI Audit Log page trend panel.
/// </summary>
public static class AuditLog
@@ -78,7 +78,7 @@ public static class KpiMetrics
}
/// <summary>
/// Charted Site Health (#11) metrics — <see cref="KpiSources.SiteHealth"/>.
/// Charted Site Health metrics — <see cref="KpiSources.SiteHealth"/>.
/// Rendered by the Central UI Health-dashboard per-site trend panel.
/// </summary>
public static class SiteHealth
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Kpi;
/// <summary>
/// Canonical KPI scope discriminators (M6 "KPI History &amp; Trends") — the value of
/// Canonical KPI scope discriminators ("KPI History &amp; Trends") — the value of
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi.KpiSample.Scope"/>. Each
/// constant's value equals its name. The companion
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi.KpiSample.ScopeKey"/> qualifies
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Kpi;
/// <summary>
/// Pure, deterministic downsampling helper for KPI series charting (M6 "KPI History &amp; Trends").
/// Pure, deterministic downsampling helper for KPI series charting ("KPI History &amp; Trends").
/// Reduces a raw <see cref="KpiSeriesPoint"/> series to at most <c>maxPoints</c> points using
/// last-value-per-bucket / gauge semantics — suitable for step/area charts where the most
/// recent value in a window best represents that window.
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Kpi;
/// <summary>
/// A single bucketed point of a KPI series (M6 "KPI History &amp; Trends") — the
/// A single bucketed point of a KPI series ("KPI History &amp; Trends") — the
/// aggregated value of one series over the bucket starting at
/// <see cref="BucketStartUtc"/>. Returned by the bucketed query path and the
/// reusable trend chart.
@@ -1,22 +1,22 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Kpi;
/// <summary>
/// Canonical KPI source identifiers (M6 "KPI History &amp; Trends") — the value of
/// Canonical KPI source identifiers ("KPI History &amp; Trends") — the value of
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi.KpiSample.Source"/> and the
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Kpi.IKpiSampleSource.Source"/>
/// each owning component reports. Each constant's value equals its name.
/// </summary>
public static class KpiSources
{
/// <summary>Notification Outbox (#21) delivery KPIs.</summary>
/// <summary>Notification Outbox delivery KPIs.</summary>
public const string NotificationOutbox = "NotificationOutbox";
/// <summary>Site Call Audit (#22) cached-call KPIs.</summary>
/// <summary>Site Call Audit cached-call KPIs.</summary>
public const string SiteCallAudit = "SiteCallAudit";
/// <summary>Audit Log (#23) ingest / backlog KPIs.</summary>
/// <summary>Audit Log ingest / backlog KPIs.</summary>
public const string AuditLog = "AuditLog";
/// <summary>Site Health (#11) monitoring KPIs.</summary>
/// <summary>Site Health monitoring KPIs.</summary>
public const string SiteHealth = "SiteHealth";
}
@@ -90,7 +90,7 @@ public class ScriptParameters : IReadOnlyDictionary<string, object?>
// that cannot be converted is a caller/script bug, not "not supplied":
// throw with a descriptive message rather than silently returning null
// (which a script would misread as absent). This mirrors Get<T>() and the
// array/list element paths. See Commons-003.
// array/list element paths.
var converted = ConvertScalar(value, underlyingType, key);
return (T)converted;
}
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types;
/// <summary>
/// Audit Log (#23) M6 Bundle E (T6) — point-in-time snapshot of the site-local
/// Point-in-time snapshot of the site-local
/// SQLite audit-log queue health, surfaced on
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Messages.Health.SiteHealthReport"/> as
/// <c>SiteAuditBacklog</c> and refreshed periodically by the
@@ -2,7 +2,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types;
/// <summary>
/// Operational state of one cached call as seen by the site, carried on the
/// combined <c>CachedCallTelemetry</c> packet (Audit Log #23 / M3) and persisted
/// combined <c>CachedCallTelemetry</c> packet and persisted
/// at central as the <c>SiteCalls</c> row mirroring the call's status.
/// </summary>
/// <remarks>
@@ -3,7 +3,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types;
/// <summary>
/// Strongly-typed identifier for a cached outbound operation
/// (<c>ExternalSystem.CachedCall</c> / <c>Database.CachedWrite</c>) — the unified
/// tracking handle introduced by Audit Log #23 (M3). The same id is the
/// tracking handle introduced by Audit Log. The same id is the
/// idempotency key end-to-end: it is stamped on every <c>AuditLog</c> row
/// produced for the operation's lifecycle (CachedSubmit → ApiCallCached /
/// DbWriteCached × N attempts → CachedResolve) and is the PK on the central
@@ -2,7 +2,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types;
/// <summary>
/// Site-local snapshot of a cached operation's tracking state, returned by the
/// <c>Tracking.Status(TrackedOperationId)</c> script API (Audit Log #23 / M3).
/// <c>Tracking.Status(TrackedOperationId)</c> script API.
/// </summary>
/// <param name="Id">Tracking handle returned by <c>CachedCall</c>/<c>CachedWrite</c>.</param>
/// <param name="Kind">
@@ -29,7 +29,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types;
/// Cluster node that submitted the cached call (e.g. <c>"node-a"</c> /
/// <c>"node-b"</c>), captured at enqueue time. Null on rows persisted before
/// the SourceNode stamping migration; stamping itself is wired in a later task.
/// Commons-023: trailing-optional with a <c>= null</c> default, matching the
/// Trailing-optional with a <c>= null</c> default, matching the
/// SourceNode rollout convention now used on <c>SiteCallSummary</c>,
/// <c>SiteCallDetail</c>, <c>NotificationSummary</c> and <c>NotificationDetail</c>
/// — so existing positional construction sites keep compiling as new
@@ -16,7 +16,7 @@ public enum MappingAction
}
/// <summary>
/// Resolves one site referenced by an incoming bundle (M8 site/instance-scoped
/// Resolves one site referenced by an incoming bundle (site/instance-scoped
/// transport). <paramref name="TargetSiteIdentifier"/> is required when
/// <paramref name="Action"/> is <see cref="MappingAction.MapToExisting"/> and null
/// when it is <see cref="MappingAction.CreateNew"/>.
@@ -3,7 +3,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Transport;
public sealed class BundleSession
{
/// <summary>
/// Commons-016: legacy per-session lockout threshold (kept on this type for the
/// Legacy per-session lockout threshold (kept on this type for the
/// shim <see cref="Locked"/> getter). The authoritative, server-side per-bundle
/// counter is bounded by <c>TransportOptions.MaxUnlockAttemptsPerSession</c>
/// (default also <c>3</c>) and is what <c>BundleImporter.LoadAsync</c> consults.
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Transport;
// ApiKeys is intentionally absent: inbound API keys are not transported between
// environments (re-arch C4). Only API methods are summarised.
// environments. Only API methods are summarised.
public sealed record BundleSummary(
int Templates,
int TemplateFolders,
@@ -11,12 +11,12 @@ public sealed record BundleSummary(
int NotificationLists,
int SmtpConfigs,
int ApiMethods,
// Additive (M8 A1): site/instance-scoped artifacts. Defaulted to 0 so manifests
// Additive: site/instance-scoped artifacts. Defaulted to 0 so manifests
// written by older exporters (which omit these JSON properties) deserialize fine.
int Sites = 0,
int DataConnections = 0,
int Instances = 0,
// Additive (S10b): SMS provider config count, mirroring SmtpConfigs. Defaulted to
// Additive: SMS provider config count, mirroring SmtpConfigs. Defaulted to
// 0 so manifests written by older exporters (which omit this JSON property)
// deserialize fine.
int SmsConfigs = 0);
@@ -5,7 +5,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Transport;
/// the bundle manifest (plaintext) so the importer can derive the per-bundle key and
/// initialise the cipher without prior knowledge of the passphrase.
/// <para>
/// Commons-015: invariants are enforced in the constructor so a malformed envelope
/// Invariants are enforced in the constructor so a malformed envelope
/// (unknown algorithm, unsupported KDF, weak iteration count, null salt/IV) is
/// rejected at the type boundary rather than failing inside
/// <see cref="System.Security.Cryptography.AesGcm"/> with a misleading exception.
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Transport;
// Inbound API keys are intentionally absent from the transport selection: per the
// inbound-API-key re-architecture (commit C4) keys are NOT carried between
// inbound-API-key re-architecture, keys are NOT carried between
// environments. They live in the per-environment SQLite store (per-env pepper +
// secret-shown-once) and are re-created/re-granted via the admin UI/CLI on the
// destination. Only API *methods* travel in a bundle.
@@ -14,21 +14,21 @@ public sealed record ExportSelection(
IReadOnlyList<int> SmtpConfigurationIds,
IReadOnlyList<int> ApiMethodIds,
bool IncludeDependencies,
// Additive (M8 A1): site/instance-scoped export. Defaulted to empty so every
// Additive: site/instance-scoped export. Defaulted to empty so every
// existing positional caller keeps compiling; older callers select no sites/instances.
IReadOnlyList<int>? SiteIds = null,
IReadOnlyList<int>? InstanceIds = null,
// Additive (S10b): SMS provider config export, mirroring SmtpConfigurationIds.
// Additive: SMS provider config export, mirroring SmtpConfigurationIds.
// Defaulted null (trailing) so every existing positional caller keeps compiling;
// older callers select no SMS configs.
IReadOnlyList<int>? SmsConfigurationIds = null)
{
/// <summary>Sites selected for site/instance-scoped export (M8). Never null.</summary>
/// <summary>Sites selected for site/instance-scoped export. Never null.</summary>
public IReadOnlyList<int> SiteIds { get; init; } = SiteIds ?? Array.Empty<int>();
/// <summary>Instances selected for site/instance-scoped export (M8). Never null.</summary>
/// <summary>Instances selected for site/instance-scoped export. Never null.</summary>
public IReadOnlyList<int> InstanceIds { get; init; } = InstanceIds ?? Array.Empty<int>();
/// <summary>SMS provider configurations selected for export (S10b). Never null.</summary>
/// <summary>SMS provider configurations selected for export. Never null.</summary>
public IReadOnlyList<int> SmsConfigurationIds { get; init; } = SmsConfigurationIds ?? Array.Empty<int>();
}
@@ -12,8 +12,8 @@ public sealed record ImportPreviewItem(
string? BlockerReason);
/// <summary>
/// A site reference in an incoming bundle that the operator must resolve before import
/// (M8 A1). <paramref name="AutoMatchTargetIdentifier"/> is the destination site the
/// A site reference in an incoming bundle that the operator must resolve before import.
/// <paramref name="AutoMatchTargetIdentifier"/> is the destination site the
/// importer auto-matched by identifier, or null when no match was found.
/// </summary>
public sealed record RequiredSiteMapping(
@@ -23,7 +23,7 @@ public sealed record RequiredSiteMapping(
/// <summary>
/// A connection reference (scoped to a source site) in an incoming bundle that the
/// operator must resolve before import (M8 A1). <paramref name="AutoMatchTargetName"/>
/// operator must resolve before import. <paramref name="AutoMatchTargetName"/>
/// is the destination connection the importer auto-matched by name, or null when no
/// match was found.
/// </summary>
@@ -35,16 +35,16 @@ public sealed record RequiredConnectionMapping(
public sealed record ImportPreview(
Guid SessionId,
IReadOnlyList<ImportPreviewItem> Items,
// Additive (M8 A1): site/connection references the operator must resolve before
// Additive: site/connection references the operator must resolve before
// applying. Defaulted to empty so every existing positional caller keeps compiling.
IReadOnlyList<RequiredSiteMapping>? RequiredSiteMappings = null,
IReadOnlyList<RequiredConnectionMapping>? RequiredConnectionMappings = null)
{
/// <summary>Site references the operator must resolve before import (M8). Never null.</summary>
/// <summary>Site references the operator must resolve before import. Never null.</summary>
public IReadOnlyList<RequiredSiteMapping> RequiredSiteMappings { get; init; } =
RequiredSiteMappings ?? Array.Empty<RequiredSiteMapping>();
/// <summary>Connection references the operator must resolve before import (M8). Never null.</summary>
/// <summary>Connection references the operator must resolve before import. Never null.</summary>
public IReadOnlyList<RequiredConnectionMapping> RequiredConnectionMappings { get; init; } =
RequiredConnectionMappings ?? Array.Empty<RequiredConnectionMapping>();
}
@@ -9,6 +9,6 @@ public sealed record ImportResult(
IReadOnlyList<int> StaleInstanceIds,
string AuditEventCorrelation,
// Number of legacy inbound API keys found in the bundle that were ignored
// (re-arch C4 — keys are not transported; re-create them on this environment).
// (keys are not transported; re-create them on this environment).
// Defaults to 0 so existing positional construction sites stay source-compatible.
int ApiKeysIgnored = 0);