// ----------------------------------------------------------------------------- // IKpiRepository.cs // Sprint: SPRINT_20260121_034_BinaryIndex_golden_corpus_foundation // Task: GCF-004 - Define KPI tracking schema and infrastructure // Description: Repository interface for KPI tracking and baseline management // ----------------------------------------------------------------------------- using System.Collections.Immutable; namespace StellaOps.BinaryIndex.GroundTruth.Abstractions; /// /// Repository for recording and querying validation KPIs. /// public interface IKpiRepository { /// /// Records KPIs from a validation run. /// /// The KPIs to record. /// Cancellation token. /// The recorded KPI entry ID. Task RecordAsync(ValidationKpis kpis, CancellationToken ct = default); /// /// Gets the active baseline for a tenant and corpus version. /// /// The tenant ID. /// The corpus version. /// Cancellation token. /// The active baseline, or null if none exists. Task GetBaselineAsync( string tenantId, string corpusVersion, CancellationToken ct = default); /// /// Sets a new baseline from a validation run. /// /// The validation run ID to use as baseline. /// Who is setting the baseline. /// Reason for setting the baseline. /// Cancellation token. /// The created baseline. Task SetBaselineAsync( Guid runId, string createdBy, string? reason = null, CancellationToken ct = default); /// /// Compares a validation run against the active baseline. /// /// The validation run ID to compare. /// Cancellation token. /// The regression check result. Task CompareAsync( Guid runId, CancellationToken ct = default); /// /// Gets KPIs for a specific validation run. /// /// The run ID. /// Cancellation token. /// The KPIs, or null if not found. Task GetByRunIdAsync(Guid runId, CancellationToken ct = default); /// /// Gets recent validation runs for a tenant. /// /// The tenant ID. /// Maximum number of runs to return. /// Cancellation token. /// Recent validation runs. Task> GetRecentAsync( string tenantId, int limit = 10, CancellationToken ct = default); /// /// Gets KPI trends over time. /// /// The tenant ID. /// Optional corpus version filter. /// Start date for trend data. /// Cancellation token. /// KPI trend data points. Task> GetTrendAsync( string tenantId, string? corpusVersion = null, DateTimeOffset? since = null, CancellationToken ct = default); } /// /// Recorded validation KPIs. /// public sealed record ValidationKpis { /// /// Gets the unique run ID. /// public required Guid RunId { get; init; } /// /// Gets the tenant ID. /// public required string TenantId { get; init; } /// /// Gets the corpus version. /// public required string CorpusVersion { get; init; } /// /// Gets the scanner version. /// public string ScannerVersion { get; init; } = "0.0.0"; /// /// Gets the number of pairs validated. /// public required int PairCount { get; init; } /// /// Gets the mean function match rate (0-100). /// public double? FunctionMatchRateMean { get; init; } /// /// Gets the minimum function match rate (0-100). /// public double? FunctionMatchRateMin { get; init; } /// /// Gets the maximum function match rate (0-100). /// public double? FunctionMatchRateMax { get; init; } /// /// Gets the mean false-negative rate (0-100). /// public double? FalseNegativeRateMean { get; init; } /// /// Gets the maximum false-negative rate (0-100). /// public double? FalseNegativeRateMax { get; init; } /// /// Gets the count of pairs with 3/3 SBOM hash stability. /// public int SbomHashStability3of3Count { get; init; } /// /// Gets the count of pairs with 2/3 SBOM hash stability. /// public int SbomHashStability2of3Count { get; init; } /// /// Gets the count of pairs with 1/3 SBOM hash stability. /// public int SbomHashStability1of3Count { get; init; } /// /// Gets the count of reconstruction-equivalent pairs. /// public int ReconstructionEquivCount { get; init; } /// /// Gets the total pairs tested for reconstruction. /// public int ReconstructionTotalCount { get; init; } /// /// Gets the median verify time in milliseconds. /// public int? VerifyTimeMedianMs { get; init; } /// /// Gets the p95 verify time in milliseconds. /// public int? VerifyTimeP95Ms { get; init; } /// /// Gets the p99 verify time in milliseconds. /// public int? VerifyTimeP99Ms { get; init; } /// /// Gets the precision (0-1). /// public double? Precision { get; init; } /// /// Gets the recall (0-1). /// public double? Recall { get; init; } /// /// Gets the F1 score (0-1). /// public double? F1Score { get; init; } /// /// Gets the deterministic replay rate (0-1). /// public double? DeterministicReplayRate { get; init; } /// /// Gets the total functions in post-patch binaries. /// public int TotalFunctionsPost { get; init; } /// /// Gets the matched functions count. /// public int MatchedFunctions { get; init; } /// /// Gets the total true patched functions. /// public int TotalTruePatched { get; init; } /// /// Gets the missed patched functions count. /// public int MissedPatched { get; init; } /// /// Gets when the run was computed. /// public DateTimeOffset ComputedAt { get; init; } = DateTimeOffset.UtcNow; /// /// Gets when the run started. /// public DateTimeOffset? StartedAt { get; init; } /// /// Gets when the run completed. /// public DateTimeOffset? CompletedAt { get; init; } /// /// Gets per-pair KPI results. /// public ImmutableArray? PairResults { get; init; } } /// /// Per-pair KPI results. /// public sealed record PairKpis { /// /// Gets the pair ID. /// public required string PairId { get; init; } /// /// Gets the CVE ID. /// public required string CveId { get; init; } /// /// Gets the package name. /// public required string PackageName { get; init; } /// /// Gets the function match rate (0-100). /// public double? FunctionMatchRate { get; init; } /// /// Gets the false-negative rate (0-100). /// public double? FalseNegativeRate { get; init; } /// /// Gets the SBOM hash stability (0-3). /// public int SbomHashStability { get; init; } /// /// Gets whether the binary is reconstruction-equivalent. /// public bool? ReconstructionEquivalent { get; init; } /// /// Gets the total functions in the post-patch binary. /// public int TotalFunctionsPost { get; init; } /// /// Gets the matched functions count. /// public int MatchedFunctions { get; init; } /// /// Gets the total known patched functions. /// public int TotalPatchedFunctions { get; init; } /// /// Gets the patched functions detected. /// public int PatchedFunctionsDetected { get; init; } /// /// Gets the verify time in milliseconds. /// public int? VerifyTimeMs { get; init; } /// /// Gets whether validation succeeded. /// public bool Success { get; init; } = true; /// /// Gets the error message if validation failed. /// public string? ErrorMessage { get; init; } /// /// Gets the SBOM hash. /// public string? SbomHash { get; init; } } /// /// KPI baseline for regression detection. /// public sealed record KpiBaseline { /// /// Gets the baseline ID. /// public required Guid BaselineId { get; init; } /// /// Gets the tenant ID. /// public required string TenantId { get; init; } /// /// Gets the corpus version. /// public required string CorpusVersion { get; init; } /// /// Gets the baseline precision (0-1). /// public required double PrecisionBaseline { get; init; } /// /// Gets the baseline recall (0-1). /// public required double RecallBaseline { get; init; } /// /// Gets the baseline F1 score (0-1). /// public required double F1Baseline { get; init; } /// /// Gets the baseline false-negative rate (0-1). /// public required double FnRateBaseline { get; init; } /// /// Gets the baseline p95 verify time in milliseconds. /// public required int VerifyP95BaselineMs { get; init; } /// /// Gets the precision warning delta (percentage points). /// public double PrecisionWarnDelta { get; init; } = 0.005; /// /// Gets the precision fail delta (percentage points). /// public double PrecisionFailDelta { get; init; } = 0.010; /// /// Gets the recall warning delta. /// public double RecallWarnDelta { get; init; } = 0.005; /// /// Gets the recall fail delta. /// public double RecallFailDelta { get; init; } = 0.010; /// /// Gets the false-negative rate warning delta. /// public double FnRateWarnDelta { get; init; } = 0.005; /// /// Gets the false-negative rate fail delta. /// public double FnRateFailDelta { get; init; } = 0.010; /// /// Gets the verify time warning delta percentage. /// public double VerifyWarnDeltaPct { get; init; } = 10.0; /// /// Gets the verify time fail delta percentage. /// public double VerifyFailDeltaPct { get; init; } = 20.0; /// /// Gets the source validation run ID. /// public Guid? SourceRunId { get; init; } /// /// Gets when the baseline was created. /// public DateTimeOffset CreatedAt { get; init; } /// /// Gets who created the baseline. /// public required string CreatedBy { get; init; } /// /// Gets the reason for creating the baseline. /// public string? Reason { get; init; } /// /// Gets whether this is the active baseline. /// public bool IsActive { get; init; } = true; } /// /// Result of a regression check. /// public sealed record RegressionCheckResult { /// /// Gets the check ID. /// public required Guid CheckId { get; init; } /// /// Gets the validation run ID. /// public required Guid RunId { get; init; } /// /// Gets the baseline ID. /// public required Guid BaselineId { get; init; } /// /// Gets the precision delta (current - baseline). /// public double? PrecisionDelta { get; init; } /// /// Gets the recall delta. /// public double? RecallDelta { get; init; } /// /// Gets the F1 delta. /// public double? F1Delta { get; init; } /// /// Gets the false-negative rate delta. /// public double? FnRateDelta { get; init; } /// /// Gets the verify p95 delta percentage. /// public double? VerifyP95DeltaPct { get; init; } /// /// Gets the overall status. /// public required RegressionStatus OverallStatus { get; init; } /// /// Gets the precision status. /// public required RegressionStatus PrecisionStatus { get; init; } /// /// Gets the recall status. /// public required RegressionStatus RecallStatus { get; init; } /// /// Gets the false-negative rate status. /// public required RegressionStatus FnRateStatus { get; init; } /// /// Gets the verify time status. /// public required RegressionStatus VerifyTimeStatus { get; init; } /// /// Gets the determinism status. /// public required RegressionStatus DeterminismStatus { get; init; } /// /// Gets when the check was performed. /// public DateTimeOffset CheckedAt { get; init; } = DateTimeOffset.UtcNow; /// /// Gets any notes about the check. /// public string? Notes { get; init; } } /// /// Status of a regression check metric. /// public enum RegressionStatus { /// /// Metric passed threshold checks. /// Pass, /// /// Metric is within warning threshold. /// Warn, /// /// Metric failed threshold check. /// Fail, /// /// Metric improved over baseline. /// Improved } /// /// KPI trend data point. /// public sealed record KpiTrendPoint { /// /// Gets the run ID. /// public required Guid RunId { get; init; } /// /// Gets the timestamp. /// public required DateTimeOffset Timestamp { get; init; } /// /// Gets the corpus version. /// public required string CorpusVersion { get; init; } /// /// Gets the precision. /// public double? Precision { get; init; } /// /// Gets the recall. /// public double? Recall { get; init; } /// /// Gets the F1 score. /// public double? F1Score { get; init; } /// /// Gets the false-negative rate. /// public double? FalseNegativeRate { get; init; } /// /// Gets the verify time p95 in milliseconds. /// public int? VerifyTimeP95Ms { get; init; } /// /// Gets the deterministic replay rate. /// public double? DeterministicReplayRate { get; init; } }