using StellaOps.Determinism; namespace StellaOps.Provcache.Events; /// /// Event published when an advisory feed advances to a new epoch. /// Provcache subscribers use this to invalidate cache entries /// that were computed against older feed epochs. /// /// /// Stream name: stellaops:events:feed-epoch-advanced /// public sealed record FeedEpochAdvancedEvent { /// /// Stream name for feed epoch events. /// public const string StreamName = "stellaops:events:feed-epoch-advanced"; /// /// Event type identifier for serialization. /// public const string EventType = "feed.epoch.advanced.v1"; /// /// Unique identifier for this event instance. /// public required Guid EventId { get; init; } /// /// Timestamp when the event occurred (UTC). /// public required DateTimeOffset Timestamp { get; init; } /// /// The feed identifier (e.g., "cve", "ghsa", "osv", "redhat-oval"). /// public required string FeedId { get; init; } /// /// The previous epoch identifier. /// Format varies by feed (e.g., "2024-12-24T12:00:00Z", "v2024.52"). /// public required string PreviousEpoch { get; init; } /// /// The new epoch identifier. /// public required string NewEpoch { get; init; } /// /// When the new epoch became effective. /// Cache entries with feed_epoch older than this should be invalidated. /// public required DateTimeOffset EffectiveAt { get; init; } /// /// Number of advisories added in this epoch (for metrics). /// public int? AdvisoriesAdded { get; init; } /// /// Number of advisories modified in this epoch (for metrics). /// public int? AdvisoriesModified { get; init; } /// /// Number of advisories withdrawn in this epoch (for metrics). /// public int? AdvisoriesWithdrawn { get; init; } /// /// Tenant ID if multi-tenant (null for global feeds). /// public string? TenantId { get; init; } /// /// Correlation ID for distributed tracing. /// public string? CorrelationId { get; init; } /// /// Creates a new FeedEpochAdvancedEvent. /// /// The feed identifier. /// The previous epoch identifier. /// The new epoch identifier. /// When the new epoch became effective. /// Number of advisories added (for metrics). /// Number of advisories modified (for metrics). /// Number of advisories withdrawn (for metrics). /// Tenant ID if multi-tenant. /// Correlation ID for tracing. /// Optional event ID (defaults to new GUID). /// Optional timestamp (defaults to current UTC time). /// Optional GUID provider for deterministic IDs. /// Optional time provider for deterministic timestamps. public static FeedEpochAdvancedEvent Create( string feedId, string previousEpoch, string newEpoch, DateTimeOffset effectiveAt, int? advisoriesAdded = null, int? advisoriesModified = null, int? advisoriesWithdrawn = null, string? tenantId = null, string? correlationId = null, Guid? eventId = null, DateTimeOffset? timestamp = null, IGuidProvider? guidProvider = null, TimeProvider? timeProvider = null) { var guidSource = guidProvider ?? SystemGuidProvider.Instance; var timeSource = timeProvider ?? TimeProvider.System; return new FeedEpochAdvancedEvent { EventId = eventId ?? guidSource.NewGuid(), Timestamp = timestamp ?? timeSource.GetUtcNow(), FeedId = feedId, PreviousEpoch = previousEpoch, NewEpoch = newEpoch, EffectiveAt = effectiveAt, AdvisoriesAdded = advisoriesAdded, AdvisoriesModified = advisoriesModified, AdvisoriesWithdrawn = advisoriesWithdrawn, TenantId = tenantId, CorrelationId = correlationId }; } }