using Microsoft.Extensions.Logging; using StellaOps.Policy.Determinization.Models; namespace StellaOps.Policy.Engine.Gates.Determinization; /// /// Builds signal snapshots for determinization evaluation by querying signal repositories. /// public sealed class SignalSnapshotBuilder : ISignalSnapshotBuilder { private readonly ISignalRepository _signalRepository; private readonly TimeProvider _timeProvider; private readonly ILogger _logger; public SignalSnapshotBuilder( ISignalRepository signalRepository, TimeProvider timeProvider, ILogger logger) { _signalRepository = signalRepository; _timeProvider = timeProvider; _logger = logger; } public async Task BuildAsync( string cveId, string componentPurl, CancellationToken ct = default) { ArgumentException.ThrowIfNullOrWhiteSpace(cveId); ArgumentException.ThrowIfNullOrWhiteSpace(componentPurl); _logger.LogDebug( "Building signal snapshot for CVE {CveId} on {Purl}", cveId, componentPurl); var snapshotAt = _timeProvider.GetUtcNow(); var subjectKey = BuildSubjectKey(cveId, componentPurl); // Query all signals in parallel var signalsTask = _signalRepository.GetSignalsAsync(subjectKey, ct); var signals = await signalsTask; // Build snapshot from retrieved signals var snapshot = SignalSnapshot.Empty(cveId, componentPurl, snapshotAt); foreach (var signal in signals) { snapshot = ApplySignal(snapshot, signal); } _logger.LogDebug( "Built signal snapshot for CVE {CveId} on {Purl}: {SignalCount} signals present", cveId, componentPurl, signals.Count); return snapshot; } private static string BuildSubjectKey(string cveId, string componentPurl) => $"{cveId}::{componentPurl}"; private SignalSnapshot ApplySignal(SignalSnapshot snapshot, Signal signal) { // This is a placeholder implementation // In a real implementation, this would map Signal objects to SignalState instances // based on signal type and update the appropriate field in the snapshot return snapshot; } } /// /// Repository for retrieving signals. /// public interface ISignalRepository { /// /// Get all signals for the given subject key. /// Task> GetSignalsAsync(string subjectKey, CancellationToken ct = default); } /// /// Represents a signal retrieved from storage. /// public sealed record Signal { public required string Type { get; init; } public required string SubjectKey { get; init; } public required DateTimeOffset ObservedAt { get; init; } public required object? Evidence { get; init; } }