Skip to content

Commit 2d0b003

Browse files
committed
Feat: Enhance policy evaluation ordering
1 parent 0caba57 commit 2d0b003

1 file changed

Lines changed: 36 additions & 1 deletion

File tree

src/Runtime/Internal/Evaluation/MutationPolicyEvaluator.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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>
1116
internal 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

Comments
 (0)