126 lines
3.3 KiB
C#
126 lines
3.3 KiB
C#
// -----------------------------------------------------------------------------
|
|
// ChainVerificationResult.cs
|
|
// Sprint: SPRINT_20260105_002_002_SCHEDULER_hlc_queue_chain
|
|
// Task: SQC-015 - Implement chain verification
|
|
// -----------------------------------------------------------------------------
|
|
|
|
using StellaOps.Scheduler.Persistence.Postgres;
|
|
|
|
namespace StellaOps.Scheduler.Queue.Models;
|
|
|
|
/// <summary>
|
|
/// Result of chain verification.
|
|
/// </summary>
|
|
public sealed record ChainVerificationResult
|
|
{
|
|
/// <summary>
|
|
/// Whether the chain is valid (no issues found).
|
|
/// </summary>
|
|
public required bool IsValid { get; init; }
|
|
|
|
/// <summary>
|
|
/// Number of entries checked.
|
|
/// </summary>
|
|
public required int EntriesChecked { get; init; }
|
|
|
|
/// <summary>
|
|
/// List of issues found during verification.
|
|
/// </summary>
|
|
public required IReadOnlyList<ChainVerificationIssue> Issues { get; init; }
|
|
|
|
/// <summary>
|
|
/// First valid entry's HLC timestamp (null if no entries).
|
|
/// </summary>
|
|
public string? FirstHlc { get; init; }
|
|
|
|
/// <summary>
|
|
/// Last valid entry's HLC timestamp (null if no entries).
|
|
/// </summary>
|
|
public string? LastHlc { get; init; }
|
|
|
|
/// <summary>
|
|
/// Head link after verification (null if no entries).
|
|
/// </summary>
|
|
public byte[]? HeadLink { get; init; }
|
|
|
|
/// <summary>
|
|
/// Get a summary of the verification result.
|
|
/// </summary>
|
|
public string GetSummary()
|
|
{
|
|
if (IsValid)
|
|
{
|
|
return $"Chain valid: {EntriesChecked} entries verified, range [{FirstHlc}, {LastHlc}], head {SchedulerChainLinking.ToHexString(HeadLink)}";
|
|
}
|
|
|
|
return $"Chain INVALID: {Issues.Count} issue(s) found in {EntriesChecked} entries";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents a single issue found during chain verification.
|
|
/// </summary>
|
|
public sealed record ChainVerificationIssue
|
|
{
|
|
/// <summary>
|
|
/// Job ID where the issue was found.
|
|
/// </summary>
|
|
public required Guid JobId { get; init; }
|
|
|
|
/// <summary>
|
|
/// HLC timestamp of the problematic entry.
|
|
/// </summary>
|
|
public required string THlc { get; init; }
|
|
|
|
/// <summary>
|
|
/// Type of issue found.
|
|
/// </summary>
|
|
public required ChainVerificationIssueType IssueType { get; init; }
|
|
|
|
/// <summary>
|
|
/// Human-readable description of the issue.
|
|
/// </summary>
|
|
public required string Description { get; init; }
|
|
|
|
/// <summary>
|
|
/// Expected value (for comparison issues).
|
|
/// </summary>
|
|
public string? Expected { get; init; }
|
|
|
|
/// <summary>
|
|
/// Actual value found (for comparison issues).
|
|
/// </summary>
|
|
public string? Actual { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Types of chain verification issues.
|
|
/// </summary>
|
|
public enum ChainVerificationIssueType
|
|
{
|
|
/// <summary>
|
|
/// The prev_link doesn't match the previous entry's link.
|
|
/// </summary>
|
|
PrevLinkMismatch,
|
|
|
|
/// <summary>
|
|
/// The stored link doesn't match the computed link.
|
|
/// </summary>
|
|
LinkMismatch,
|
|
|
|
/// <summary>
|
|
/// The HLC timestamp is out of order.
|
|
/// </summary>
|
|
HlcOrderViolation,
|
|
|
|
/// <summary>
|
|
/// The payload hash has invalid length.
|
|
/// </summary>
|
|
InvalidPayloadHash,
|
|
|
|
/// <summary>
|
|
/// The link has invalid length.
|
|
/// </summary>
|
|
InvalidLinkLength
|
|
}
|