Skip to content

AuditChainWalker

Namespace AgentPrism · Assembly AgentPrism.Core.dll

Walks an ordered list of audit entries and reports the chain status. Shared by InMemoryAuditLog and the SQL providers so the two verify algorithms can never drift apart.

public static class AuditChainWalker

objectAuditChainWalker

object.GetType(), object.MemberwiseClone(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()

Verifies an ordered (oldest first) list of entries belonging to one tenant.

public static AuditChainVerification Verify(IReadOnlyList<AuditEntry> entries, bool hasLowerBound = false)

entries IReadOnlyList<AuditEntry>

The entries, ordered oldest to newest (created_at, then id).

hasLowerBound bool

true when the query that produced entries had a lower date bound (AuditChainQuery.After was set) — meaning an entry may exist before entries[0] that this call cannot see, so nothing can be concluded about the very first entry’s AuditEntry.PreviousHash. false (the default) means the query covered the tenant’s whole history, so entries[0] IS the tenant’s genesis entry and its AuditEntry.PreviousHash must be null.

AuditChainVerification

The verification result.

Three checks, in this order:

  • Self-consistency. Each entry’s stored AuditEntry.Hash is recomputed from its own content and its own stored AuditEntry.PreviousHash. A mismatch means the row was altered (any field, including PreviousHash itself) after it was written — AuditChainStatus.Broken. This pass runs first and wins over the next two: an altered row also breaks the link to its neighbor, but “the row was altered” is the more specific and more useful diagnosis.
  • Genesis check. Only when hasLowerBound is false: entries[0] must have a null AuditEntry.PreviousHash. A non-null value here means the tenant’s true first entry (or entries right after it) were deleted — also AuditChainStatus.Gap. Without this check, deleting a chain’s oldest row is invisible: every SURVIVING row is still internally self-consistent and still correctly linked to its own surviving neighbor.
  • Link consistency. Only once every entry is self-consistent: entry i’s AuditEntry.PreviousHash must equal entry i-1’s AuditEntry.Hash. A mismatch means a row between them is missing — AuditChainStatus.Gap.