sprints enhancements

This commit is contained in:
StellaOps Bot
2025-12-25 19:52:30 +02:00
parent ef6ac36323
commit b8b2d83f4a
138 changed files with 25133 additions and 594 deletions

View File

@@ -43,6 +43,18 @@ internal sealed class PolicyEvaluator
}
public PolicyEvaluationResult Evaluate(PolicyEvaluationRequest request)
{
return Evaluate(request, injectedScore: null);
}
/// <summary>
/// Evaluate a policy with an optional pre-computed EWS score.
/// When injectedScore is provided, it will be used instead of computing EWS from context.
/// This is primarily for testing score-based policy rules.
/// </summary>
public PolicyEvaluationResult Evaluate(
PolicyEvaluationRequest request,
global::StellaOps.Signals.EvidenceWeightedScore.EvidenceWeightedScoreResult? injectedScore)
{
if (request is null)
{
@@ -54,8 +66,8 @@ internal sealed class PolicyEvaluator
throw new ArgumentNullException(nameof(request.Document));
}
// Pre-compute EWS so it's available during rule evaluation for score-based rules
var precomputedScore = PrecomputeEvidenceWeightedScore(request.Context);
// Use injected score if provided, otherwise compute from context
var precomputedScore = injectedScore ?? PrecomputeEvidenceWeightedScore(request.Context);
var evaluator = new PolicyExpressionEvaluator(request.Context, precomputedScore);
var orderedRules = request.Document.Rules

View File

@@ -282,9 +282,34 @@ internal sealed class PolicyExpressionEvaluator
{
var leftValue = Evaluate(left, scope).Raw;
var rightValue = Evaluate(right, scope).Raw;
// For ScoreScope, use the numeric value for comparison
if (leftValue is ScoreScope leftScope)
{
leftValue = leftScope.ScoreValue;
}
if (rightValue is ScoreScope rightScope)
{
rightValue = rightScope.ScoreValue;
}
// Normalize numeric types for comparison (decimal vs int, etc.)
if (IsNumeric(leftValue) && IsNumeric(rightValue))
{
var leftDecimal = Convert.ToDecimal(leftValue, CultureInfo.InvariantCulture);
var rightDecimal = Convert.ToDecimal(rightValue, CultureInfo.InvariantCulture);
return new EvaluationValue(comparer(leftDecimal, rightDecimal));
}
return new EvaluationValue(comparer(leftValue, rightValue));
}
private static bool IsNumeric(object? value)
{
return value is decimal or double or float or int or long or short or byte;
}
private EvaluationValue CompareNumeric(PolicyExpression left, PolicyExpression right, EvaluationScope scope, Func<decimal, decimal, bool> comparer)
{
var leftValue = Evaluate(left, scope);
@@ -314,6 +339,13 @@ internal sealed class PolicyExpressionEvaluator
return true;
}
// Support direct score comparisons (score >= 70)
if (value.Raw is ScoreScope scoreScope)
{
number = scoreScope.ScoreValue;
return true;
}
number = 0m;
return false;
}
@@ -384,6 +416,7 @@ internal sealed class PolicyExpressionEvaluator
int i => i,
long l => l,
string s when decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) => value,
ScoreScope scoreScope => scoreScope.ScoreValue,
_ => null,
};
}
@@ -968,6 +1001,11 @@ internal sealed class PolicyExpressionEvaluator
this.score = score;
}
/// <summary>
/// Gets the numeric score value for direct comparison (e.g., score >= 80).
/// </summary>
public decimal ScoreValue => score.Score;
public EvaluationValue Get(string member) => member.ToLowerInvariant() switch
{
// Core score value (allows direct comparison: score >= 80)