using System; using System.Collections.Immutable; using System.Linq; namespace StellaOps.Vexer.Policy; public interface IVexPolicyDiagnostics { VexPolicyDiagnosticsReport GetDiagnostics(); } public sealed record VexPolicyDiagnosticsReport( string Version, string RevisionId, string Digest, int ErrorCount, int WarningCount, DateTimeOffset GeneratedAt, ImmutableArray Issues, ImmutableArray Recommendations, ImmutableDictionary ActiveOverrides); public sealed class VexPolicyDiagnostics : IVexPolicyDiagnostics { private readonly IVexPolicyProvider _policyProvider; private readonly TimeProvider _timeProvider; public VexPolicyDiagnostics( IVexPolicyProvider policyProvider, TimeProvider? timeProvider = null) { _policyProvider = policyProvider ?? throw new ArgumentNullException(nameof(policyProvider)); _timeProvider = timeProvider ?? TimeProvider.System; } public VexPolicyDiagnosticsReport GetDiagnostics() { var snapshot = _policyProvider.GetSnapshot(); var issues = snapshot.Issues; var errorCount = issues.Count(static issue => issue.Severity == VexPolicyIssueSeverity.Error); var warningCount = issues.Count(static issue => issue.Severity == VexPolicyIssueSeverity.Warning); var overrides = snapshot.ConsensusOptions.ProviderOverrides .OrderBy(static pair => pair.Key, StringComparer.Ordinal) .ToImmutableDictionary(); var recommendations = BuildRecommendations(errorCount, warningCount, overrides); return new VexPolicyDiagnosticsReport( snapshot.Version, snapshot.RevisionId, snapshot.Digest, errorCount, warningCount, _timeProvider.GetUtcNow(), issues, recommendations, overrides); } private static ImmutableArray BuildRecommendations( int errorCount, int warningCount, ImmutableDictionary overrides) { var messages = ImmutableArray.CreateBuilder(); if (errorCount > 0) { messages.Add("Resolve policy errors before running consensus; defaults are used while errors persist."); } if (warningCount > 0) { messages.Add("Review policy warnings via CLI/Web diagnostics and adjust configuration as needed."); } if (overrides.Count > 0) { messages.Add($"Provider overrides active for: {string.Join(", ", overrides.Keys)}."); } messages.Add("Refer to docs/ARCHITECTURE_VEXER.md for policy upgrade and diagnostics guidance."); return messages.ToImmutable(); } }