Browse pages
LS2013: Audit Value Read from the Message in the Handler
LS2013 is a compiler check that reports a command handler, the type that runs the state change, adding an audit value that the message already carries, which the pipeline should have recorded before the handler ran. This page states what the rule reports, where the error sits, and how to declare the value beside the message.
Reference#
What the Rule Enforces#
LS2013 enforces Declare audit values beside the message (litespec/backend/application#declare-audit-values-beside-the-message). It runs in Application, Infrastructure, and Worker. Its category is LiteSpec.Layers. Severity and enablement follow the Analyzers overview.
What the Rule Reports#
The rule reports a call to WithTarget or WithReason on a receiver of type IAuditScope inside a command handler, which is a class whose name ends in CommandHandler or that implements ICommandHandler, when every argument reads only the handler message parameter, constants, and string formatting, and at least one argument reads the message. The diagnostic sits on the invoked member name, and its message names the handler and the call.
Failing Example#
internal sealed class RenewLoanCommandHandler
{
public void Handle(RenewLoanCommand command, IAuditScope audit)
{
audit.WithTarget(command.LoanId);
audit.WithReason($"Renewed by {command.ReaderName}");
}
}Passing Example#
internal sealed class RenewLoanCommandHandler(ILoanRepository loanRepository)
{
public void Handle(RenewLoanCommand command, IAuditScope audit)
{
var loan = loanRepository.GetById(command.LoanId);
var renewalId = Guid.NewGuid();
audit.WithTarget(loan.Id);
audit.WithTarget(renewalId);
}
}How to Fix#
Declare the target and reason beside the command, so the pipeline records them on every outcome, including a denial. Keep in the handler only a generated identity or a reason composed from loaded state.
Notes#
What the Rule Ignores#
The rule does not report an argument that reads a local, a loaded aggregate, or a generated value, an argument that reads only a constant, or a WithTarget or WithReason call on any other receiver type or outside a command handler. It does not run in Domain or WebApi.