.NET API
IAuditLog
Tracon.Abstractions.dllThe audit trail log.
public interface IAuditLogRemarks
Section titled “Remarks”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.
Methods
Section titled “Methods”QueryAsync(AuditQuery, CancellationToken)
Section titled “ QueryAsync(AuditQuery, CancellationToken)”Reads the records through a filter.
ValueTask<IReadOnlyList<AuditEntry>> QueryAsync(AuditQuery query, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”query AuditQuery
The filter.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”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)Parameters
Section titled “Parameters”query AuditChainQuery
The scope: tenant and, optionally, a date range.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<AuditChainVerification>
The verification result.
Remarks
Section titled “Remarks”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)Parameters
Section titled “Parameters”entry AuditEntry
The record to write.
cancellationToken CancellationToken
The cancellation token.