Files
git.stella-ops.org/src/__Libraries/StellaOps.Metrics/Kpi/KpiModels.cs

217 lines
5.6 KiB
C#

namespace StellaOps.Metrics.Kpi;
/// <summary>
/// Quality KPIs for explainable triage.
/// </summary>
public sealed record TriageQualityKpis
{
/// <summary>
/// Reporting period start.
/// </summary>
public required DateTimeOffset PeriodStart { get; init; }
/// <summary>
/// Reporting period end.
/// </summary>
public required DateTimeOffset PeriodEnd { get; init; }
/// <summary>
/// Tenant ID (null for global).
/// </summary>
public string? TenantId { get; init; }
/// <summary>
/// Reachability KPIs.
/// </summary>
public required ReachabilityKpis Reachability { get; init; }
/// <summary>
/// Runtime KPIs.
/// </summary>
public required RuntimeKpis Runtime { get; init; }
/// <summary>
/// Explainability KPIs.
/// </summary>
public required ExplainabilityKpis Explainability { get; init; }
/// <summary>
/// Replay/Determinism KPIs.
/// </summary>
public required ReplayKpis Replay { get; init; }
/// <summary>
/// Unknown budget KPIs.
/// </summary>
public required UnknownBudgetKpis Unknowns { get; init; }
/// <summary>
/// Operational KPIs.
/// </summary>
public required OperationalKpis Operational { get; init; }
}
public sealed record ReachabilityKpis
{
/// <summary>
/// Total findings analyzed.
/// </summary>
public required int TotalFindings { get; init; }
/// <summary>
/// Findings with non-UNKNOWN reachability.
/// </summary>
public required int WithKnownReachability { get; init; }
/// <summary>
/// Percentage with known reachability.
/// </summary>
public decimal PercentKnown => TotalFindings > 0
? (decimal)WithKnownReachability / TotalFindings * 100
: 0;
/// <summary>
/// Breakdown by reachability state.
/// </summary>
public required IReadOnlyDictionary<string, int> ByState { get; init; }
/// <summary>
/// Findings confirmed unreachable.
/// </summary>
public int ConfirmedUnreachable =>
ByState.GetValueOrDefault("ConfirmedUnreachable", 0);
/// <summary>
/// Noise reduction (unreachable / total).
/// </summary>
public decimal NoiseReductionPercent => TotalFindings > 0
? (decimal)ConfirmedUnreachable / TotalFindings * 100
: 0;
}
public sealed record RuntimeKpis
{
/// <summary>
/// Total findings in environments with sensors.
/// </summary>
public required int TotalWithSensorDeployed { get; init; }
/// <summary>
/// Findings with runtime observations.
/// </summary>
public required int WithRuntimeCorroboration { get; init; }
/// <summary>
/// Coverage percentage.
/// </summary>
public decimal CoveragePercent => TotalWithSensorDeployed > 0
? (decimal)WithRuntimeCorroboration / TotalWithSensorDeployed * 100
: 0;
/// <summary>
/// Breakdown by posture.
/// </summary>
public required IReadOnlyDictionary<string, int> ByPosture { get; init; }
}
public sealed record ExplainabilityKpis
{
/// <summary>
/// Total verdicts generated.
/// </summary>
public required int TotalVerdicts { get; init; }
/// <summary>
/// Verdicts with reason steps.
/// </summary>
public required int WithReasonSteps { get; init; }
/// <summary>
/// Verdicts with at least one proof pointer.
/// </summary>
public required int WithProofPointer { get; init; }
/// <summary>
/// Verdicts that are "complete" (both reason steps AND proof pointer).
/// </summary>
public required int FullyExplainable { get; init; }
/// <summary>
/// Explainability completeness percentage.
/// </summary>
public decimal CompletenessPercent => TotalVerdicts > 0
? (decimal)FullyExplainable / TotalVerdicts * 100
: 0;
}
public sealed record ReplayKpis
{
/// <summary>
/// Total replay attempts.
/// </summary>
public required int TotalAttempts { get; init; }
/// <summary>
/// Successful replays (identical verdict).
/// </summary>
public required int Successful { get; init; }
/// <summary>
/// Replay success rate.
/// </summary>
public decimal SuccessRate => TotalAttempts > 0
? (decimal)Successful / TotalAttempts * 100
: 0;
/// <summary>
/// Common failure reasons.
/// </summary>
public required IReadOnlyDictionary<string, int> FailureReasons { get; init; }
}
public sealed record UnknownBudgetKpis
{
/// <summary>
/// Total environments tracked.
/// </summary>
public required int TotalEnvironments { get; init; }
/// <summary>
/// Budget breaches by environment.
/// </summary>
public required IReadOnlyDictionary<string, int> BreachesByEnvironment { get; init; }
/// <summary>
/// Total overrides/exceptions granted.
/// </summary>
public required int OverridesGranted { get; init; }
/// <summary>
/// Average override age (days).
/// </summary>
public decimal AvgOverrideAgeDays { get; init; }
}
public sealed record OperationalKpis
{
/// <summary>
/// Median time to first verdict (seconds).
/// </summary>
public required double MedianTimeToVerdictSeconds { get; init; }
/// <summary>
/// Cache hit rate for graphs/proofs.
/// </summary>
public required decimal CacheHitRate { get; init; }
/// <summary>
/// Average evidence size per scan (bytes).
/// </summary>
public required long AvgEvidenceSizeBytes { get; init; }
/// <summary>
/// 95th percentile verdict time (seconds).
/// </summary>
public required double P95VerdictTimeSeconds { get; init; }
}