// // Copyright (c) StellaOps. Licensed under BUSL-1.1. // using System.Collections.Immutable; namespace StellaOps.Facet; /// /// Persistent store for instances. /// /// /// /// Implementations provide storage and retrieval of facet seals for drift detection /// and quota enforcement. Seals are indexed by image digest and creation time. /// /// /// Sprint: SPRINT_20260105_002_003_FACET (QTA-012) /// /// public interface IFacetSealStore { /// /// Get the most recent seal for an image digest. /// /// The image digest (e.g., "sha256:{hex}"). /// Cancellation token. /// The latest seal, or null if no seal exists for this image. Task GetLatestSealAsync(string imageDigest, CancellationToken ct = default); /// /// Get a seal by its combined Merkle root (unique identifier). /// /// The seal's combined Merkle root. /// Cancellation token. /// The seal, or null if not found. Task GetByCombinedRootAsync(string combinedMerkleRoot, CancellationToken ct = default); /// /// Get seal history for an image digest. /// /// The image digest. /// Maximum number of seals to return. /// Cancellation token. /// Seals in descending order by creation time (most recent first). Task> GetHistoryAsync( string imageDigest, int limit = 10, CancellationToken ct = default); /// /// Save a seal to the store. /// /// The seal to save. /// Cancellation token. /// A task representing the async operation. /// If seal is null. /// If a seal with the same combined root exists. Task SaveAsync(FacetSeal seal, CancellationToken ct = default); /// /// Check if a seal exists for an image digest. /// /// The image digest. /// Cancellation token. /// True if at least one seal exists. Task ExistsAsync(string imageDigest, CancellationToken ct = default); /// /// Delete all seals for an image digest. /// /// The image digest. /// Cancellation token. /// Number of seals deleted. Task DeleteByImageAsync(string imageDigest, CancellationToken ct = default); /// /// Purge seals older than the specified retention period. /// /// Retention period from creation time. /// Minimum seals to keep per image digest. /// Cancellation token. /// Number of seals purged. Task PurgeOldSealsAsync( TimeSpan retentionPeriod, int keepAtLeast = 1, CancellationToken ct = default); } /// /// Exception thrown when attempting to save a duplicate seal. /// public sealed class SealAlreadyExistsException : Exception { /// /// Initializes a new instance of the class. /// /// The duplicate seal's combined root. public SealAlreadyExistsException(string combinedMerkleRoot) : base($"A seal with combined Merkle root '{combinedMerkleRoot}' already exists.") { CombinedMerkleRoot = combinedMerkleRoot; } /// /// Gets the duplicate seal's combined Merkle root. /// public string CombinedMerkleRoot { get; } }