// -----------------------------------------------------------------------------
// 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; }
}