diff --git a/src/ScadaLink.Commons/Types/Enums/AuditChannel.cs b/src/ScadaLink.Commons/Types/Enums/AuditChannel.cs new file mode 100644 index 0000000..c3b26d3 --- /dev/null +++ b/src/ScadaLink.Commons/Types/Enums/AuditChannel.cs @@ -0,0 +1,13 @@ +namespace ScadaLink.Commons.Types.Enums; + +/// +/// Top-level Audit Log (#23) channel — the trust boundary the audited action crosses. +/// One of: outbound API call, outbound DB write, notification send/deliver, or inbound API request. +/// +public enum AuditChannel +{ + ApiOutbound, + DbOutbound, + Notification, + ApiInbound +} diff --git a/src/ScadaLink.Commons/Types/Enums/AuditForwardState.cs b/src/ScadaLink.Commons/Types/Enums/AuditForwardState.cs new file mode 100644 index 0000000..dac799f --- /dev/null +++ b/src/ScadaLink.Commons/Types/Enums/AuditForwardState.cs @@ -0,0 +1,14 @@ +namespace ScadaLink.Commons.Types.Enums; + +/// +/// Site-local Audit Log (#23) forwarding state, tracked only in the site SQLite hot-path. +/// Central rows leave this null. Pending = not yet sent; Forwarded = telemetry sent +/// and acked; Reconciled = confirmed present centrally via the periodic pull fallback. +/// The site retention purge MUST NOT drop a row whose state is still Pending. +/// +public enum AuditForwardState +{ + Pending, + Forwarded, + Reconciled +} diff --git a/src/ScadaLink.Commons/Types/Enums/AuditKind.cs b/src/ScadaLink.Commons/Types/Enums/AuditKind.cs new file mode 100644 index 0000000..faac09f --- /dev/null +++ b/src/ScadaLink.Commons/Types/Enums/AuditKind.cs @@ -0,0 +1,20 @@ +namespace ScadaLink.Commons.Types.Enums; + +/// +/// Specific Audit Log (#23) event kind within a channel — what action produced the row. +/// Cached variants emit multiple rows per operation (submit → forward → attempt → resolve). +/// See alog.md §4 for the full taxonomy. +/// +public enum AuditKind +{ + ApiCall, + ApiCallCached, + DbWrite, + DbWriteCached, + NotifySend, + NotifyDeliver, + InboundRequest, + InboundAuthFailure, + CachedSubmit, + CachedResolve +} diff --git a/src/ScadaLink.Commons/Types/Enums/AuditStatus.cs b/src/ScadaLink.Commons/Types/Enums/AuditStatus.cs new file mode 100644 index 0000000..fdedb8d --- /dev/null +++ b/src/ScadaLink.Commons/Types/Enums/AuditStatus.cs @@ -0,0 +1,18 @@ +namespace ScadaLink.Commons.Types.Enums; + +/// +/// Lifecycle status of an Audit Log (#23) event row. +/// Cached operations produce multiple rows tracking Submitted → Forwarded → Attempted → Delivered/Parked/Discarded. +/// Skipped is used when an action was short-circuited (e.g. dry-run) but should still be audited. +/// +public enum AuditStatus +{ + Submitted, + Forwarded, + Attempted, + Delivered, + Failed, + Parked, + Discarded, + Skipped +} diff --git a/tests/ScadaLink.Commons.Tests/Types/Enums/AuditEnumTests.cs b/tests/ScadaLink.Commons.Tests/Types/Enums/AuditEnumTests.cs new file mode 100644 index 0000000..c9470a2 --- /dev/null +++ b/tests/ScadaLink.Commons.Tests/Types/Enums/AuditEnumTests.cs @@ -0,0 +1,72 @@ +using ScadaLink.Commons.Types.Enums; + +namespace ScadaLink.Commons.Tests.Types.Enums; + +/// +/// Asserts the exact member sets of the Audit Log (#23) enums. +/// Lock-in tests; any addition/removal/rename is a deliberate design change +/// that must come with a corresponding update to alog.md §4. +/// +public class AuditEnumTests +{ + [Fact] + public void AuditChannel_HasExactlyExpectedMembers() + { + var expected = new[] { "ApiOutbound", "DbOutbound", "Notification", "ApiInbound" }; + var actual = Enum.GetValues(typeof(AuditChannel)) + .Cast() + .Select(x => x.ToString()) + .ToArray(); + + Assert.Equal(expected.Length, actual.Length); + Assert.Equal(expected, actual); + } + + [Fact] + public void AuditKind_HasExactlyTenExpectedMembers() + { + var expected = new[] + { + "ApiCall", "ApiCallCached", "DbWrite", "DbWriteCached", + "NotifySend", "NotifyDeliver", "InboundRequest", "InboundAuthFailure", + "CachedSubmit", "CachedResolve", + }; + var actual = Enum.GetValues(typeof(AuditKind)) + .Cast() + .Select(x => x.ToString()) + .ToArray(); + + Assert.Equal(10, actual.Length); + Assert.Equal(expected, actual); + } + + [Fact] + public void AuditStatus_HasExactlyEightExpectedMembers() + { + var expected = new[] + { + "Submitted", "Forwarded", "Attempted", "Delivered", + "Failed", "Parked", "Discarded", "Skipped", + }; + var actual = Enum.GetValues(typeof(AuditStatus)) + .Cast() + .Select(x => x.ToString()) + .ToArray(); + + Assert.Equal(8, actual.Length); + Assert.Equal(expected, actual); + } + + [Fact] + public void AuditForwardState_HasExactlyExpectedMembers() + { + var expected = new[] { "Pending", "Forwarded", "Reconciled" }; + var actual = Enum.GetValues(typeof(AuditForwardState)) + .Cast() + .Select(x => x.ToString()) + .ToArray(); + + Assert.Equal(expected.Length, actual.Length); + Assert.Equal(expected, actual); + } +}