# LS2013: Audit Value Read from the Message in the Handler

## Intent

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](https://litespec.dev/4.0.0/backend/application.md#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](https://litespec.dev/4.0.0/analyzers/README.md).

### 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

```csharp
internal sealed class RenewLoanCommandHandler
{
    public void Handle(RenewLoanCommand command, IAuditScope audit)
    {
        audit.WithTarget(command.LoanId);
        audit.WithReason($"Renewed by {command.ReaderName}");
    }
}
```

### Passing Example

```csharp
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.
