//
// 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; }
}