diff --git a/src/Abstractions/Audit/IMutationAuditor.cs b/src/Abstractions/Audit/IMutationAuditor.cs
index d9278d5..a1b16bf 100644
--- a/src/Abstractions/Audit/IMutationAuditor.cs
+++ b/src/Abstractions/Audit/IMutationAuditor.cs
@@ -11,6 +11,11 @@ namespace ModularityKit.Mutator.Abstractions.Audit;
///
public interface IMutationAuditor
{
+ ///
+ /// When , the runtime may skip creating audit entries for this auditor.
+ ///
+ bool IsEnabled => true;
+
///
/// Records an audit entry for a mutation.
///
diff --git a/src/Abstractions/History/IMutationHistoryStore.cs b/src/Abstractions/History/IMutationHistoryStore.cs
index 374810f..080e1b9 100644
--- a/src/Abstractions/History/IMutationHistoryStore.cs
+++ b/src/Abstractions/History/IMutationHistoryStore.cs
@@ -27,6 +27,11 @@ namespace ModularityKit.Mutator.Abstractions.History;
///
public interface IMutationHistoryStore
{
+ ///
+ /// When , the runtime may skip creating history entries for this store.
+ ///
+ bool IsEnabled => true;
+
///
/// Persists a mutation history entry.
///
diff --git a/src/Runtime/Diagnostics/MutationAuditEntryFactory.cs b/src/Runtime/Diagnostics/MutationAuditEntryFactory.cs
index 2ef5afa..39b916d 100644
--- a/src/Runtime/Diagnostics/MutationAuditEntryFactory.cs
+++ b/src/Runtime/Diagnostics/MutationAuditEntryFactory.cs
@@ -116,7 +116,7 @@ public static MutationHistoryEntry CreateHistoryEntry(
Intent = mutation.Intent,
Context = mutation.Context,
Changes = result.Changes,
- SideEffects = result.SideEffects.ToList(),
+ SideEffects = result.SideEffects,
Timestamp = mutation.Context.Timestamp,
ExecutionTime = duration
};
diff --git a/src/Runtime/Internal/Execution/MutationExecutionOutcomeProcessor.cs b/src/Runtime/Internal/Execution/MutationExecutionOutcomeProcessor.cs
index de005bd..f2b6191 100644
--- a/src/Runtime/Internal/Execution/MutationExecutionOutcomeProcessor.cs
+++ b/src/Runtime/Internal/Execution/MutationExecutionOutcomeProcessor.cs
@@ -12,8 +12,17 @@
namespace ModularityKit.Mutator.Runtime.Internal.Execution;
///
-/// Handles blocked, failed, and completed mutation outcomes after policy evaluation and execution.
+/// Processes mutation outcomes after policy evaluation and mutation execution.
///
+///
+/// Handles policy blocked, validation failed, successfully completed, and finalized
+/// mutation outcomes. Coordinates interceptor notifications, audit recording,
+/// mutation history persistence, and metrics collection.
+///
+/// Pipeline responsible for notifying registered mutation interceptors about execution outcomes.
+/// Auditor responsible for recording mutation success and failure audit entries.
+/// Store responsible for persisting mutation history for committed mutations.
+/// Collector responsible for recording mutation execution metrics.
internal sealed class MutationExecutionOutcomeProcessor(
IInterceptorPipeline interceptorPipeline,
IMutationAuditor auditor,
@@ -28,8 +37,15 @@ internal sealed class MutationExecutionOutcomeProcessor(
private readonly IMetricsCollector _metricsCollector = metricsCollector ?? throw new ArgumentNullException(nameof(metricsCollector));
///
- /// Handles a policy-blocked mutation result.
+ /// Handles mutation that was blocked by a policy decision.
///
+ /// The type of state associated with the mutation.
+ ///
+ /// The context containing the mutation, current state, execution metadata,
+ /// cancellation token, and metrics information.
+ ///
+ /// The policy decision that blocked the mutation.
+ /// Policy blocked mutation result with audit and execution metrics finalized.
public async Task> HandleBlockedPolicyAsync(
MutationExecutionContext executionContext,
PolicyDecision policyDecision)
@@ -53,9 +69,17 @@ await AuditFailureAsync(
return await FinalizeResultAsync(executionContext, blockedResult).ConfigureAwait(false);
}
+
///
- /// Handles a validation-failed mutation result.
+ /// Handles mutation that failed validation.
///
+ /// The type of state associated with the mutation.
+ ///
+ /// The context containing the mutation, current state, execution metadata,
+ /// cancellation token, and metrics information.
+ ///
+ /// The mutation result containing validation errors.
+ /// The validation failure result with audit and execution metrics finalized.
public async Task> HandleValidationFailureAsync(
MutationExecutionContext executionContext,
MutationResult validationFailureResult)
@@ -70,8 +94,20 @@ await AuditFailureAsync(
}
///
- /// Completes a mutation result after execution and policy modifications.
+ /// Completes mutation execution after applying policy modifications and
+ /// processing successful mutation outcomes.
///
+ /// The type of state associated with the mutation.
+ ///
+ /// The context containing the mutation, current state, execution metadata,
+ /// cancellation token, and metrics information.
+ ///
+ /// The result produced by the mutation execution.
+ /// The policy decision containing any modifications to apply to the mutation result.
+ ///
+ /// The finalized mutation result after interceptor notification, auditing,
+ /// optional history persistence, and metrics processing.
+ ///
public async Task> CompleteMutationAsync(
MutationExecutionContext executionContext,
MutationResult mutationResult,
@@ -110,8 +146,13 @@ await StoreInHistoryAsync(
}
///
- /// Finalizes a runtime result by recording metrics and attaching total execution time.
+ /// Finalizes mutation result by recording execution metrics and attaching
+ /// the total execution duration to the result.
///
+ /// The type of state associated with the mutation.
+ /// The context containing execution timing and metrics information.
+ /// The mutation result to finalize.
+ /// The mutation result with finalized execution metrics.
public async Task> FinalizeResultAsync(
MutationExecutionContext executionContext,
MutationResult result)
@@ -133,6 +174,15 @@ await _metricsCollector.RecordAsync(
};
}
+ ///
+ /// Records successful mutation execution in the audit system when auditing is enabled.
+ ///
+ /// The type of state associated with the mutation.
+ /// The mutation that was executed.
+ /// The resulting mutation result.
+ /// The policy decision applied to the mutation.
+ /// The unique identifier of the mutation execution.
+ /// The total execution duration.
private async Task AuditSuccessAsync(
IMutation mutation,
MutationResult result,
@@ -140,6 +190,9 @@ private async Task AuditSuccessAsync(
string executionId,
TimeSpan duration)
{
+ if (!_auditor.IsEnabled)
+ return;
+
var entry = MutationAuditEntryFactory.CreateSuccess(
mutation,
result,
@@ -150,12 +203,23 @@ private async Task AuditSuccessAsync(
await _auditor.AuditAsync(entry).ConfigureAwait(false);
}
+ ///
+ /// Records failed mutation execution in the audit system when auditing is enabled.
+ ///
+ /// The type of state associated with the mutation.
+ /// The mutation that failed.
+ /// The resulting mutation failure.
+ /// The unique identifier of the mutation execution.
+ /// The total execution duration.
private async Task AuditFailureAsync(
IMutation mutation,
MutationResult result,
string executionId,
TimeSpan duration)
{
+ if (!_auditor.IsEnabled)
+ return;
+
var entry = MutationAuditEntryFactory.CreateFailure(
mutation,
result,
@@ -165,13 +229,26 @@ private async Task AuditFailureAsync(
await _auditor.AuditAsync(entry).ConfigureAwait(false);
}
- private async Task StoreInHistoryAsync(
+ ///
+ /// Stores successful committed mutation in the mutation history store when history
+ /// persistence is enabled and state identifier can be resolved.
+ ///
+ /// The type of state associated with the mutation.
+ /// The mutation that was executed.
+ /// The resulting mutation result.
+ /// The unique identifier of the mutation execution.
+ /// The total execution duration.
+ /// Token that can be used to cancel the history persistence operation.
+ private async Task StoreInHistoryAsync(
IMutation mutation,
MutationResult result,
string executionId,
TimeSpan duration,
CancellationToken cancellationToken)
{
+ if (!_historyStore.IsEnabled)
+ return;
+
var stateId = MutationAuditEntryFactory.ResolveStateId(mutation.Context);
if (string.IsNullOrEmpty(stateId))
return;