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;