sqlinsight-pro/src/SQLInsight.Rules/Engine/RuleEvaluation.cs
Søren Eggert Lundsteen Olsen 244153e9e4 Rules the version does not support are "not applicable", not "not measurable"
On SQL Server 2005 twenty rules stood as "not measurable" (Query Store,
system_health, memory columns …) between the real gaps, and counted in the
overview's "regler ikke målbare". They are not gaps: the version simply
lacks what they look at.

- New RuleOutcome.NotApplicable (last in the enum: outcomes are stored as
  numbers, so existing rows keep their meaning).
- A rule or collector missing only capabilities inherent to the instance
  (version-gated, plan cache memory columns, or Azure-managed) is not
  applicable, with the version each needs: "Ikke relevant for SQL Server
  2005: kræver QueryStore (fra SQL Server 2016)". Missing settings or rights
  (HADR not enabled …), collector failures and permission errors stay
  "not measurable". CollectedData.MarkNotApplicable carries this from
  collectors to the rules that use their data; community rules below their
  minimumVersion are not applicable too.
- Counts are unchanged in shape: the overview, KPI, JSON API and Prometheus
  count outcomes 2 and 3 only. The instance page lists the rest in a
  collapsed "Ikke relevant for SQL Server 2005 (n)" (details/summary, no
  JS) after the real gaps. Report controls whose core rule does not apply
  count neither as met nor as not measured.

Tests: engine (version vs. setting vs. collected data), inherent
capabilities, the existing version tests now expect not applicable, report
control status, and the web page and overview count.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 16:05:39 +02:00

61 lines
2 KiB
C#

using SQLInsight.Core.Findings;
namespace SQLInsight.Rules.Engine;
/// <summary>
/// What a rule concluded. Created through the static factory methods.
/// </summary>
public sealed record RuleEvaluation
{
private RuleEvaluation(RuleOutcome outcome, IReadOnlyList<Finding> findings, string? reason)
{
Outcome = outcome;
Findings = findings;
Reason = reason;
}
public RuleOutcome Outcome { get; }
public IReadOnlyList<Finding> Findings { get; }
/// <summary>Why the rule could not be measured, if it could not.</summary>
public string? Reason { get; }
public static RuleEvaluation Passed() => new(RuleOutcome.Passed, [], null);
public static RuleEvaluation Found(params Finding[] findings)
{
ArgumentNullException.ThrowIfNull(findings);
if (findings.Length == 0)
{
throw new ArgumentException("At least one finding is required. Use Passed() when there is none.", nameof(findings));
}
return new(RuleOutcome.Findings, findings, null);
}
public static RuleEvaluation NotMeasurable(string reason) => new(RuleOutcome.NotMeasurable, [], reason);
public static RuleEvaluation NotApplicable(string reason) => new(RuleOutcome.NotApplicable, [], reason);
}
public enum RuleOutcome
{
/// <summary>The rule ran and found nothing wrong.</summary>
Passed,
/// <summary>The rule ran and found one or more problems.</summary>
Findings,
/// <summary>The rule could not be evaluated on this instance. This is never the same as <see cref="Passed"/>.</summary>
NotMeasurable,
/// <summary>The rule failed while running. This is never the same as <see cref="Passed"/>.</summary>
Error,
/// <summary>
/// The rule does not apply to this kind of instance: its SQL Server version lacks what the rule looks at (Query
/// Store on 2005 …), or Azure manages it. Not a gap in the monitoring, so not counted as not measurable.
/// Last in the enum: outcomes are stored as numbers.
/// </summary>
NotApplicable,
}