using System.Collections.Immutable; namespace StellaOps.Excititor.Core; public sealed record VexConsensusPolicyOptions { public const string BaselineVersion = "baseline/v1"; public VexConsensusPolicyOptions( string? version = null, double vendorWeight = 1.0, double distroWeight = 0.9, double platformWeight = 0.7, double hubWeight = 0.5, double attestationWeight = 0.6, IEnumerable>? providerOverrides = null) { Version = string.IsNullOrWhiteSpace(version) ? BaselineVersion : version.Trim(); VendorWeight = NormalizeWeight(vendorWeight); DistroWeight = NormalizeWeight(distroWeight); PlatformWeight = NormalizeWeight(platformWeight); HubWeight = NormalizeWeight(hubWeight); AttestationWeight = NormalizeWeight(attestationWeight); ProviderOverrides = NormalizeOverrides(providerOverrides); } public string Version { get; } public double VendorWeight { get; } public double DistroWeight { get; } public double PlatformWeight { get; } public double HubWeight { get; } public double AttestationWeight { get; } public ImmutableDictionary ProviderOverrides { get; } private static double NormalizeWeight(double weight) { if (double.IsNaN(weight) || double.IsInfinity(weight)) { throw new ArgumentOutOfRangeException(nameof(weight), "Weight must be a finite number."); } if (weight <= 0) { return 0; } if (weight >= 1) { return 1; } return weight; } private static ImmutableDictionary NormalizeOverrides( IEnumerable>? overrides) { if (overrides is null) { return ImmutableDictionary.Empty; } var builder = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal); foreach (var (key, weight) in overrides) { if (string.IsNullOrWhiteSpace(key)) { continue; } builder[key.Trim()] = NormalizeWeight(weight); } return builder.ToImmutable(); } }