using ZB.MOM.WW.Audit; using ZB.MOM.WW.ScadaBridge.Commons.Types; namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services; /// /// Site-local audit-log queue surface consumed by the site /// SiteAuditTelemetryActor drain loop and the M6 /// SiteStreamGrpcServer.PullAuditEvents reconciliation handler. /// Extracted from SqliteAuditWriter so both consumers can be /// unit-tested against a stub without touching SQLite; the /// SqliteAuditWriter production type implements this interface /// and DI wires the same singleton instance to every consumer. /// /// /// Lives in Commons (rather than alongside SqliteAuditWriter in /// ZB.MOM.WW.ScadaBridge.AuditLog) because ZB.MOM.WW.ScadaBridge.Communication — which /// hosts the M6 gRPC pull handler — must depend on this interface and /// ZB.MOM.WW.ScadaBridge.AuditLog already depends on ZB.MOM.WW.ScadaBridge.Communication. /// Pulling the interface up to Commons breaks the would-be cycle while /// keeping the implementation in the AuditLog component. /// /// Only the methods the drain and pull paths need are exposed — the /// hot-path WriteAsync stays on /// (script-thread surface), separated by concern so each side can be /// mocked independently. /// public interface ISiteAuditQueue { /// /// Returns up to rows currently in /// , /// oldest first. Idempotent — repeated calls before /// will yield the same rows again. /// /// /// AuditLog-001: cached-lifecycle audit kinds /// (, /// , /// , /// ) are /// EXCLUDED from this result — they ride the combined-telemetry drain via /// + the central /// OnCachedTelemetryAsync dual-write transaction. The audit-only /// drain handled by this method covers everything else (sync ApiCall / /// DbWrite, NotifySend, InboundRequest, etc.). /// /// Maximum number of rows to return. /// Cancellation token. Task> ReadPendingAsync(int limit, CancellationToken ct = default); /// /// AuditLog-001: returns up to rows in /// /// whose audit kind belongs to the cached-call lifecycle /// vocabulary (, /// , /// , /// ), /// oldest first. The site-side SiteAuditTelemetryActor drains these /// rows separately, joining each with the matching operational tracking row /// (IOperationTrackingStore.GetStatusAsync) before pushing the /// combined CachedTelemetryBatch via /// ISiteStreamAuditClient.IngestCachedTelemetryAsync. Idempotent — /// repeated calls before yield the same /// rows again. /// /// /// The two-drain partition is the production wiring of the combined-telemetry /// transport specified in Component-AuditLog.md §"Cached Operations — /// Combined Telemetry": cached rows MUST flow with their matching /// SiteCalls upsert through one MS SQL transaction at central. The /// pre-AuditLog-001 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. /// /// Maximum number of rows to return. /// Cancellation token. Task> ReadPendingCachedTelemetryAsync(int limit, CancellationToken ct = default); /// /// Flips the supplied EventIds from /// to /// . /// Non-existent or already-forwarded ids are silent no-ops. /// /// Event IDs to mark as forwarded. /// Cancellation token. Task MarkForwardedAsync(IReadOnlyList eventIds, CancellationToken ct = default); /// /// M6 reconciliation-pull read surface: returns up to /// rows whose >= /// and whose is still /// or /// . /// /// /// Rows in the brief race window between site-Forwarded and central-ingest are /// intentionally included: the central reconciliation puller dedups on /// , so re-shipping is safe and avoids losing rows /// whose telemetry ack was acted on locally but never landed centrally. Ordering /// is oldest first with /// as the deterministic tiebreaker. /// /// Lower bound timestamp (UTC). /// Maximum number of rows to return. /// Cancellation token. Task> ReadPendingSinceAsync( DateTime sinceUtc, int batchSize, CancellationToken ct = default); /// /// M6 reconciliation-pull commit surface: flips the supplied EventIds to /// , /// but ONLY for rows currently in /// or /// . /// Rows already in /// are left untouched (idempotent re-call). Non-existent ids are silent no-ops. /// /// Event IDs to mark as reconciled. /// Cancellation token. Task MarkReconciledAsync(IReadOnlyList eventIds, CancellationToken ct = default); /// /// M6 Bundle E (T6) 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 /// as /// SiteAuditBacklog by the periodic SiteAuditBacklogReporter /// hosted service so a stuck site→central drain is visible on the central /// health dashboard. Safe to call concurrently with hot-path writes — /// implementations are expected to take the same connection lock used by /// the hot-path INSERT batch and the drain queries. /// /// Cancellation token. Task GetBacklogStatsAsync(CancellationToken ct = default); }