@@ -8,6 +8,11 @@ namespace ModularityKit.Mutator.Runtime.Internal.Evaluation;
88/// <summary>
99/// Evaluates registered mutation policies in runtime priority order.
1010/// </summary>
11+ /// <remarks>
12+ /// The evaluator resolves policies from the registry, applies deterministic
13+ /// priority ordering, invokes each policy with optional timeout handling, and
14+ /// returns the first blocking or modifying decision.
15+ /// </remarks>
1116internal sealed class MutationPolicyEvaluator (
1217 IPolicyRegistry policyRegistry ,
1318 MutationEngineOptions options )
@@ -32,7 +37,10 @@ public async Task<PolicyDecision> EvaluateAsync<TState>(
3237 {
3338 var policies = _policyRegistry . GetPolicies < TState > ( ) ;
3439
35- foreach ( var policy in policies . OrderByDescending ( p => p . Priority ) )
40+ foreach ( var policy in policies
41+ . OrderByDescending ( p => p . Priority )
42+ . ThenBy ( p => p . Name , StringComparer . Ordinal )
43+ . ThenBy ( p => p . GetType ( ) . FullName ?? string . Empty , StringComparer . Ordinal ) )
3644 {
3745 var decision = await EvaluatePolicyAsync (
3846 policy ,
@@ -47,6 +55,21 @@ public async Task<PolicyDecision> EvaluateAsync<TState>(
4755 return PolicyDecision . Allow ( ) ;
4856 }
4957
58+ /// <summary>
59+ /// Evaluates a single policy with optional runtime timeout handling.
60+ /// </summary>
61+ /// <typeparam name="TState">The state type handled by the policy.</typeparam>
62+ /// <param name="policy">The policy to evaluate.</param>
63+ /// <param name="mutation">The mutation being evaluated.</param>
64+ /// <param name="state">The current state snapshot.</param>
65+ /// <param name="cancellationToken">Token used to cancel policy evaluation.</param>
66+ /// <returns>The decision produced by the policy.</returns>
67+ /// <exception cref="PolicyEvaluationTimeoutException">
68+ /// Thrown when policy evaluation exceeds the configured timeout.
69+ /// </exception>
70+ /// <exception cref="PolicyEvaluationException">
71+ /// Thrown when the policy evaluation fails with a non-cancellation exception.
72+ /// </exception>
5073 private async Task < PolicyDecision > EvaluatePolicyAsync < TState > (
5174 IMutationPolicy < TState > policy ,
5275 IMutation < TState > mutation ,
@@ -82,6 +105,18 @@ private async Task<PolicyDecision> EvaluatePolicyAsync<TState>(
82105 }
83106 }
84107
108+ /// <summary>
109+ /// Invokes a policy and normalizes unexpected failures into policy evaluation exceptions.
110+ /// </summary>
111+ /// <typeparam name="TState">The state type handled by the policy.</typeparam>
112+ /// <param name="policy">The policy to invoke.</param>
113+ /// <param name="mutation">The mutation being evaluated.</param>
114+ /// <param name="state">The current state snapshot.</param>
115+ /// <param name="cancellationToken">Token used to cancel policy evaluation.</param>
116+ /// <returns>The decision produced by the policy.</returns>
117+ /// <exception cref="PolicyEvaluationException">
118+ /// Thrown when the policy evaluation fails with a non-cancellation exception.
119+ /// </exception>
85120 private static async Task < PolicyDecision > InvokePolicyAsync < TState > (
86121 IMutationPolicy < TState > policy ,
87122 IMutation < TState > mutation ,
0 commit comments