namespace StellaOps.Evidence.Bundle; /// A complete evidence bundle for a single finding/alert. public sealed class EvidenceBundle { public string BundleId { get; init; } = Guid.NewGuid().ToString("N"); public string SchemaVersion { get; init; } = "1.1"; public required string AlertId { get; init; } public required string ArtifactId { get; init; } public ReachabilityEvidence? Reachability { get; init; } public CallStackEvidence? CallStack { get; init; } public ProvenanceEvidence? Provenance { get; init; } public VexStatusEvidence? VexStatus { get; init; } public DiffEvidence? Diff { get; init; } public GraphRevisionEvidence? GraphRevision { get; init; } // Sprint: SPRINT_20260112_008_LB_binary_diff_evidence_models (BINDIFF-LB-002) public BinaryDiffEvidence? BinaryDiff { get; init; } public required EvidenceHashSet Hashes { get; init; } public required DateTimeOffset CreatedAt { get; init; } public int ComputeCompletenessScore() { var score = 0; if (Reachability?.Status == EvidenceStatus.Available) score++; if (CallStack?.Status == EvidenceStatus.Available) score++; if (Provenance?.Status == EvidenceStatus.Available) score++; if (VexStatus?.Status == EvidenceStatus.Available) score++; // BINDIFF-LB-002: Include binary diff in completeness scoring if (BinaryDiff?.Status == EvidenceStatus.Available) score++; return score; } public EvidenceStatusSummary CreateStatusSummary() => new() { Reachability = Reachability?.Status ?? EvidenceStatus.Unavailable, CallStack = CallStack?.Status ?? EvidenceStatus.Unavailable, Provenance = Provenance?.Status ?? EvidenceStatus.Unavailable, VexStatus = VexStatus?.Status ?? EvidenceStatus.Unavailable, Diff = Diff?.Status ?? EvidenceStatus.Unavailable, GraphRevision = GraphRevision?.Status ?? EvidenceStatus.Unavailable, // BINDIFF-LB-002: Include binary diff status BinaryDiff = BinaryDiff?.Status ?? EvidenceStatus.Unavailable }; public EvidenceBundlePredicate ToSigningPredicate() => new() { BundleId = BundleId, AlertId = AlertId, ArtifactId = ArtifactId, CompletenessScore = ComputeCompletenessScore(), Hashes = Hashes, StatusSummary = CreateStatusSummary(), CreatedAt = CreatedAt, SchemaVersion = SchemaVersion }; }