docs+code: close Theme 1 — 24 design-doc / XML-doc drift findings

Doc/XML-comment drift + small adherence fixes across 17 modules. Highlights:
- Host-017: site CoordinatedShutdown ordering — SiteStreamGrpcServer gains
  CancelAllStreams() (refuse new streams, cancel active), wired into
  Program.cs site branch via ApplicationStopping.
- InboundAPI-021: ParentExecutionId now travels on RouteToGet/SetAttributes
  symmetric with RouteToCallRequest; RouteHelper stamps from _parentExecutionId.
- ClusterInfra-012: ClusterOptionsValidator now requires both seed nodes.
- Comm-018: SiteCommunicationActor.HeartbeatMessage.IsActive derived from
  cluster leader check (was hardcoded true).
- DM-020: reconciliation audit row attributes the current user, not prior deployer.
- SEL-019: EventLogPurgeService early-exits on standby via active-node check.
- Plus comment/XML-doc accuracy fixes across AuditLog, ConfigurationDatabase,
  NotificationOutbox, SiteRuntime, SiteCallAudit; doc refreshes for Component-
  Commons / -ManagementService / -CLI / -ExternalSystemGateway / -HealthMonitoring
  / -Transport / -ConfigurationDatabase; CD-023 index-name doc alignment.

11 new regression tests (RouteHelper x4, SiteStreamGrpcServer x2,
ClusterOptionsValidator x1, SiteCommunicationActor x1, DeploymentService x1,
EventLogPurgeService x3). Build clean (0 warnings); InboundAPI/Communication/
Host suites all green. README regenerated: 112 open (was 136).
This commit is contained in:
Joseph Doherty
2026-05-28 06:28:31 -04:00
parent e3ca9af1be
commit 487859bff0
51 changed files with 940 additions and 188 deletions
+61 -16
View File
@@ -39,9 +39,11 @@ Commons must define shared primitive and utility types used across multiple comp
- **`TrackedOperationKind` enum**: ExternalCall, DatabaseWrite. Discriminates the two cached-call kinds carried by a tracked operation (notifications are tracked separately via the `NotificationType` enum).
- **`TrackedOperationStatus` enum**: Pending, Retrying, Delivered, Parked, Failed, Discarded. The unified lifecycle state shared by all tracked store-and-forward operations. This is the operation's externally-observable lifecycle status in the site-local tracking table (the status record); it is related to but distinct from the S&F buffer's own `StoreAndForwardMessageStatus`, which tracks a buffered message's retry state within the buffer (the retry mechanism). `Failed` (permanent failure) has no notification analogue — notifications use only the other five states (the `NotificationStatus` enum omits `Failed`).
- **`AuditChannel` enum**: ApiOutbound, DbOutbound, Notification, ApiInbound. Discriminates the script-trust-boundary channel that produced an `AuditEvent`. Owned by the Audit Log component.
- **`AuditKind` enum**: SyncCall, CachedEnqueued, CachedAttempt, CachedTerminal, SyncWrite, SyncRead, Enqueued, Attempt, Terminal, Completed. Channel-specific event kind — the valid `Kind` values for each `AuditChannel` are listed in the Audit Log component design (`Component-AuditLog.md`).
- **`AuditStatus` enum**: Success, TransientFailure, PermanentFailure, Enqueued, Retrying, Delivered, Parked, Discarded. Outcome of a single audit event row; superset of `TrackedOperationStatus` to also cover one-shot sync calls.
- **`AuditEvent`**: A record carrying every column of the central `AuditLog` row — `EventId` (GUID, idempotency key), `OccurredAtUtc`, `IngestedAtUtc`, `Channel` (`AuditChannel`), `Kind` (`AuditKind`), `CorrelationId`, `SourceSiteId`, `SourceInstanceId`, `SourceScript`, `Actor`, `Target`, `Status` (`AuditStatus`), `HttpStatus`, `DurationMs`, `ErrorMessage`, `ErrorDetail`, `RequestSummary`, `ResponseSummary`, `PayloadTruncated`, `Extra` — plus a site-only `ForwardState` (`Pending` | `Forwarded` | `Reconciled`) used by the site SQLite write-buffer's telemetry/reconciliation loop. `IngestedAtUtc` is unset at the site and stamped on central ingest. See `Component-AuditLog.md` for the persistence schema and ingest semantics.
- **`AuditKind` enum**: ApiCall, ApiCallCached, DbWrite, DbWriteCached, NotifySend, NotifyDeliver, InboundRequest, InboundAuthFailure, CachedSubmit, CachedResolve. Channel-specific event kind — the valid `Kind` values for each `AuditChannel` are listed in the Audit Log component design (`Component-AuditLog.md`).
- **`AuditStatus` enum**: Submitted, Forwarded, Attempted, Delivered, Failed, Parked, Discarded, Skipped. Lifecycle status of an audit event row; cached operations transit Submitted → Forwarded → Attempted → Delivered/Parked/Discarded. `Skipped` covers short-circuited (e.g. dry-run) actions that should still be audited.
- **`AuditForwardState` enum**: Pending, Forwarded, Reconciled. Site-local SQLite flag governing the telemetry/reconciliation loop (set on a row but never sent to central).
- **`AuditEvent`**: A record carrying every column of the central `AuditLog` row — `EventId` (GUID, idempotency key), `OccurredAtUtc`, `IngestedAtUtc`, `Channel` (`AuditChannel`), `Kind` (`AuditKind`), `CorrelationId`, `ExecutionId`, `ParentExecutionId`, `SourceSiteId`, `SourceNode`, `SourceInstanceId`, `SourceScript`, `Actor`, `Target`, `Status` (`AuditStatus`), `HttpStatus`, `DurationMs`, `ErrorMessage`, `ErrorDetail`, `RequestSummary`, `ResponseSummary`, `PayloadTruncated`, `Extra` — plus a site-only `ForwardState` (`AuditForwardState`) used by the site SQLite write-buffer's telemetry/reconciliation loop. `IngestedAtUtc` is unset at the site and stamped on central ingest. See `Component-AuditLog.md` for the persistence schema and ingest semantics.
- **`SiteCall`**: A record carrying the central `SiteCalls` operational-mirror row — `TrackedOperationId`, `SourceSiteId`, `SourceNode`, `Kind`, `Target`, `Status`, `RetryCount`, key timestamps, and provenance — fed by site `CachedCallTelemetry` and the periodic reconciliation pull.
Types defined here must be immutable and thread-safe.
@@ -76,7 +78,7 @@ Entity classes are organized by domain area:
- **Inbound API**: `ApiKey`, `ApiMethod`.
- **Security**: `LdapGroupMapping`, `SiteScopeRule`.
- **Deployment**: `DeploymentRecord`, `SystemArtifactDeploymentRecord`, `DeployedConfigSnapshot`.
- **Audit**: `AuditLogEntry`.
- **Audit**: `AuditLogEntry` (configuration-change audit, owned by Configuration Database), `AuditEvent` (centralized Audit Log row, see REQ-COM-1), `SiteCall` (`SiteCalls` operational-mirror row).
The **`Notification`** entity is the persistence-ignorant POCO for a row of the central `Notifications` table — the durable notification queue owned by the Notification Outbox. It is a plain class with properties for `NotificationId` (GUID, the idempotency key), `Type` (`NotificationType` enum discriminator), `ListName`, `Subject`, `Body`, `TypeData` (a JSON string — the type-agnostic extensibility hook), `Status` (`NotificationStatus` enum), `RetryCount`, `LastError`, `ResolvedTargets`, the provenance fields `SourceSiteId` / `SourceInstanceId` / `SourceScript`, and the UTC timestamps `SiteEnqueuedAt`, `CreatedAt`, `LastAttemptAt`, `NextAttemptAt`, `DeliveredAt`. As with every entity class it has no EF dependency; the Configuration Database component supplies the Fluent API mapping, value conversions, and indexes. The `Type` and `Status` enums (`NotificationType`: `Email`, `Teams`, …; `NotificationStatus`: `Pending`, `Retrying`, `Delivered`, `Parked`, `Discarded`) are defined under `Types/Enums/` per REQ-COM-1.
@@ -92,6 +94,7 @@ Commons must define repository interfaces that consuming components use for data
- `INotificationRepository` — Notification lists (including the `Type` field), recipients, SMTP configuration.
- `INotificationOutboxRepository` — The `Notifications` table: insert-if-not-exists ingest on `NotificationId`, due-row polling (`Pending` rows and `Retrying` rows past `NextAttemptAt`), status transitions, KPI aggregate queries, and the bulk delete of terminal rows used by the daily purge job.
- `ISiteCallAuditRepository` — The `SiteCalls` table: insert-if-not-exists ingest on `TrackedOperationId`, upsert-on-newer-status from telemetry and reconciliation pulls, KPI aggregate queries, and the bulk delete of terminal rows used by the daily purge job.
- `IAuditLogRepository` — The central `AuditLog` table (Audit Log #23): insert-if-not-exists ingest on `EventId`, keyset-paged query, monthly partition switch-out and boundary inspection, KPI snapshots, recursive execution-tree walks, and distinct-source-node enumeration.
- `ISiteRepository` — Sites, data connections, and their site assignments.
- `ICentralUiRepository` — Read-oriented queries spanning multiple domain areas for display purposes.
@@ -113,6 +116,13 @@ Commons must define service interfaces for cross-cutting concerns that multiple
- **`INotificationDeliveryService`**: Sends notifications to a named notification list, routing transient failures to store-and-forward. Implemented by the Notification Service, consumed by the script runtime context.
- **`IAuditWriter`**: Site-local hot-path interface for appending an `AuditEvent` to the site SQLite `AuditLog`: `Task WriteAsync(AuditEvent evt, CancellationToken ct)`. Single durable INSERT, `ForwardState = Pending`. Consumed by the script-trust-boundary call paths (External System Gateway, Database layer, Store-and-Forward Engine). Implementation lives in the Audit Log component.
- **`ICentralAuditWriter`**: Central direct-write interface for central-originated audit rows (Inbound API request completion, Notification Outbox dispatcher attempts/terminals): `Task WriteAsync(AuditEvent evt, CancellationToken ct)`, with insert-if-not-exists semantics on `EventId` so retried handlers cannot produce duplicates. Implementation lives in the Audit Log component.
- **`ISiteAuditQueue`**: Site-local queue handing off `AuditEvent` rows from the hot path to the gRPC telemetry forwarder. Implementation lives in the Audit Log component.
- **`ICachedCallLifecycleObserver`** / **`ICachedCallTelemetryForwarder`**: Bridge between the Store-and-Forward Engine's cached-call lifecycle transitions and the central `CachedCallTelemetry` packet (combined audit + operational state). Implementations live in the Audit Log component.
- **`INodeIdentityProvider`**: Resolves the writing node's `SourceNode` label (`node-a` / `node-b` / `central-a` / `central-b`) stamped on every audit row, notification, and site-call.
- **`IOperationTrackingStore`**: Site-local SQLite-backed status record store for tracked store-and-forward operations (`Tracking.Status(id)`).
- **`IPartitionMaintenance`**: Central monthly partition-switch / retention purge job hook used by the Audit Log partition maintenance service.
Bundle transport interfaces (`IBundleExporter`, `IBundleImporter`, `IBundleSessionStore`, `IAuditCorrelationContext`) live alongside the data types in `Interfaces/Transport/` and are owned by the Transport component (#24); they are defined in Commons so other components (Configuration Database for audit correlation, Central UI for the import workflow) can depend on the abstraction without taking a Transport dependency.
These interfaces are defined in Commons so that consuming components depend only on the abstraction, not on the implementing component.
@@ -159,19 +169,36 @@ ScadaLink.Commons/
│ ├── ValueFormatter.cs # culture-invariant value-to-string helper
│ ├── DynamicJsonElement.cs # dynamic JSON wrapper for scripts
│ ├── TrackedOperationId.cs # tracked store-and-forward operation ID (GUID)
│ ├── AuditLogKpiSnapshot.cs # central AuditLog KPI tile shape
│ ├── SiteAuditBacklogSnapshot.cs # per-site audit-forward backlog snapshot
│ ├── SiteCallOperational.cs # SiteCalls operational-row projection
│ ├── TrackingStatusSnapshot.cs # site-local Tracking.Status(id) projection
│ ├── Enums/ # InstanceState, DeploymentStatus, AlarmState,
│ │ # AlarmLevel, AlarmTriggerType, ConnectionHealth,
│ │ # DataType, StoreAndForwardCategory,
│ │ # StoreAndForwardMessageStatus,
│ │ # NotificationType, NotificationStatus,
│ │ # TrackedOperationKind, TrackedOperationStatus,
│ │ # AuditChannel, AuditKind, AuditStatus
├── Audit/ # AuditEvent record (site + central audit row)
│ │ # AuditChannel, AuditKind, AuditStatus,
# AuditForwardState
│ ├── Audit/ # AuditLogPaging, AuditLogQueryFilter,
│ │ # AuditQueryParamParsers, ExecutionTreeNode,
│ │ # SiteCallKpiSnapshot, SiteCallPaging,
│ │ # SiteCallQueryFilter, SiteCallSiteKpiSnapshot
│ ├── DataConnections/ # OPC UA endpoint config value objects + enums
│ ├── Flattening/ # FlattenedConfiguration, ConfigurationDiff,
│ │ # DeploymentPackage, ValidationResult
│ ├── InboundApi/ # ApiKeyHasher, ParameterDefinition
│ ├── Notifications/ # NotificationKpiSnapshot, NotificationOutboxFilter,
│ │ # SiteNotificationKpiSnapshot
│ ├── Transport/ # Transport bundle value objects: BundleManifest,
│ │ # BundleSession, BundleSummary, EncryptionMetadata,
│ │ # ExportSelection, ImportPreview, ImportResolution,
│ │ # ImportResult, ManifestContentEntry
│ └── Scripts/ # AlarmContext, ScriptScope
├── Interfaces/ # Shared interfaces by concern
│ ├── IOperationTrackingStore.cs # site-local tracked-operation status store
│ ├── IPartitionMaintenance.cs # central partition-switch / retention purge hook
│ ├── Protocol/ # REQ-COM-2: Protocol abstraction (IDataConnection, etc.)
│ ├── Repositories/ # REQ-COM-4: Per-component repository interfaces
│ │ ├── ITemplateEngineRepository.cs
@@ -182,16 +209,26 @@ ScadaLink.Commons/
│ │ ├── INotificationRepository.cs
│ │ ├── INotificationOutboxRepository.cs
│ │ ├── ISiteCallAuditRepository.cs
│ │ ├── IAuditLogRepository.cs
│ │ ├── ISiteRepository.cs
│ │ └── ICentralUiRepository.cs
── Services/ # REQ-COM-4a: Cross-cutting service interfaces
├── IAuditService.cs
├── IAuditWriter.cs
├── ICentralAuditWriter.cs
├── IDatabaseGateway.cs
├── IExternalSystemClient.cs
├── IInstanceLocator.cs
── INotificationDeliveryService.cs
── Services/ # REQ-COM-4a: Cross-cutting service interfaces
├── IAuditService.cs
├── IAuditWriter.cs
├── ICentralAuditWriter.cs
├── ISiteAuditQueue.cs
├── ICachedCallLifecycleObserver.cs
├── ICachedCallTelemetryForwarder.cs
── INodeIdentityProvider.cs
│ │ ├── IDatabaseGateway.cs
│ │ ├── IExternalSystemClient.cs
│ │ ├── IInstanceLocator.cs
│ │ └── INotificationDeliveryService.cs
│ └── Transport/ # Bundle transport interfaces (Transport #24):
│ ├── IAuditCorrelationContext.cs
│ ├── IBundleExporter.cs
│ ├── IBundleImporter.cs
│ └── IBundleSessionStore.cs
├── Entities/ # REQ-COM-3: Domain entity POCOs, by domain area
│ ├── Templates/ # Template, TemplateAttribute, TemplateAlarm,
│ │ # TemplateScript, TemplateComposition, TemplateFolder
@@ -207,7 +244,9 @@ ScadaLink.Commons/
│ ├── Deployment/ # DeploymentRecord, SystemArtifactDeploymentRecord,
│ │ # DeployedConfigSnapshot
│ ├── Scripts/ # SharedScript
│ └── Audit/ # AuditLogEntry
│ └── Audit/ # AuditLogEntry (config-change audit),
│ # AuditEvent (centralized AuditLog row),
│ # SiteCall (SiteCalls operational mirror)
├── Messages/ # REQ-COM-5: Cross-component message contracts, by concern
│ ├── Deployment/
│ ├── Lifecycle/
@@ -227,7 +266,13 @@ ScadaLink.Commons/
│ ├── InboundApi/ # Route.To() request messages
│ ├── RemoteQuery/ # event-log and parked-message query messages,
│ │ # parked-operation retry/discard commands
── Management/ # HTTP/ClusterClient management commands + registry
── Audit/ # Audit Log (#23) + Site Call Audit (#22) ingest:
│ │ # IngestAuditEventsCommand/Reply,
│ │ # IngestCachedTelemetryCommand/Reply,
│ │ # UpsertSiteCallCommand/Reply, SiteCallQueries,
│ │ # SiteCallRelayMessages
│ └── Management/ # HTTP/ClusterClient management commands + registry,
│ # including TransportCommands (Export/Preview/Import bundle)
├── Serialization/ # OpcUaEndpointConfigSerializer (typed↔legacy JSON)
└── Validators/ # OpcUaEndpointConfigValidator
```