Skip to content
Tracon

IAuditLog

Namespace Tracon · Assembly Tracon.Abstractions.dll

The audit trail log.

public interface IAuditLog

Writing happens in the store decorators, not in the endpoint layer: writing in the endpoint layer would miss a change made to the same store from another code path. The decorator is the single gate.

A write failure does not stop the operation. When IAuditLog.WriteAsync fails the caller logs it and the operation continues — the same rule: observability does not break behaviour.

There is a read endpoint only; there is no delete or edit endpoint, and there will not be one.

DI lifetime. Registered as a singleton with TryAdd; a consumer’s own registration wins. An implementation must be safe under concurrent calls and must not capture or depend on a scoped service.

Tenant behavior — EXPECTED tenant, with an AMBIENT fallback. IAuditLog.WriteAsync is scoped by the entry’s own AuditEntry.TenantId field — an explicit, EXPECTED tenant that is never inferred. IAuditLog.QueryAsync and IAuditLog.VerifyChainAsync accept an explicit TenantId override (AuditQuery.TenantId, AuditChainQuery.TenantId) and fall back to the AMBIENT ITenantContext.TenantId ONLY when that override is null or empty. A null TenantId is a contract, not a convenience: it MUST resolve to the single ambient tenant, never to “every tenant”. An implementation that treats a missing filter as “no filter” returns every tenant’s records to whoever leaves the field unset — this is exactly the shape AuditLogContract’s ambient-fallback scenarios (BL-046) guard against; the built-in InMemoryAuditLog and SqlAuditLog both resolve the fallback through an injected ITenantContext, the same pattern IRunStore’s AMBIENT methods use.

QueryAsync(AuditQuery, CancellationToken)

Section titled “ QueryAsync(AuditQuery, CancellationToken)”

Reads the records through a filter.

ValueTask<IReadOnlyList<AuditEntry>> QueryAsync(AuditQuery query, CancellationToken cancellationToken = default)

query AuditQuery

The filter.

cancellationToken CancellationToken

The cancellation token.

ValueTask<IReadOnlyList<AuditEntry>>

The records, newest first.

VerifyChainAsync(AuditChainQuery, CancellationToken)

Section titled “ VerifyChainAsync(AuditChainQuery, CancellationToken)”

Walks a tenant’s hash chain and reports whether it is intact.

ValueTask<AuditChainVerification> VerifyChainAsync(AuditChainQuery query, CancellationToken cancellationToken = default)

query AuditChainQuery

The scope: tenant and, optionally, a date range.

cancellationToken CancellationToken

The cancellation token.

ValueTask<AuditChainVerification>

The verification result.

A date range narrows which entries are walked; it does not weaken the check within that range. Because the entry immediately before the range’s start is not read, a break at the range’s own boundary cannot be judged and is not reported — an unbounded query is the only way to check a tenant’s whole history.

WriteAsync(AuditEntry, CancellationToken)

Section titled “ WriteAsync(AuditEntry, CancellationToken)”

Writes an audit record.

ValueTask WriteAsync(AuditEntry entry, CancellationToken cancellationToken = default)

entry AuditEntry

The record to write.

cancellationToken CancellationToken

The cancellation token.

ValueTask