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);
+ }
+}