# LS5001: Code Element Carries No Mark

## Intent

LS5001 is a compiler check that reports a code element of a recognized kind that carries no mark naming the record it serves, because without the mark no tool can tell which record the element implements. This page states what the rule reports, where the error sits, and how to add the missing mark.

## Reference

### What the Rule Enforces

LS5001 enforces [Point Code and Tests up to Records](https://litespec.dev/4.0.0/core/system.md#point-code-and-tests-up-to-records) (`litespec/core/system#point-code-and-tests-up-to-records`) and [Point Every Technical Class up to Its Record or Choice](https://litespec.dev/4.0.0/core/system.md#point-every-technical-class-up-to-its-record-or-choice) (`litespec/core/system#point-every-technical-class-up-to-its-record-or-choice`). It runs in every layer, checking the kinds that layer holds: Domain checks aggregate roots, state-changing methods, domain events, rule exceptions, and domain services; Application checks command and query handlers, event handlers, jobs, ports, and technical classes; Infrastructure checks adapters, jobs, and technical classes; WebApi checks endpoints and technical classes; Worker checks jobs and technical classes; and test projects check tests. Its category is `LiteSpec.Traceability`.

### What the Rule Reports

The rule reports a code element of a recognized kind that carries no mark. Kinds are recognized from the code: a handler implements an interface named `ICommandHandler` or `IQueryHandler`; an event handler implements an interface named `IEventHandler` or `IDomainEventReaction`; a job derives from a class named `BackgroundService` or implements an interface named `IHostedService` and is named `*Job` or `*Worker`; an aggregate root derives from a class named `AggregateRoot` with one type argument; an aggregate method is a public instance or static method on an aggregate root that raises a domain event; a domain event implements an interface named `IDomainEvent`; a rule exception derives from a class named `DomainException` and is not abstract; an endpoint implements an interface named `IEndpoint` or is named `*Endpoint` in WebApi; an adapter implements a marked port; a technical class is a top-level class in Application, Infrastructure, or WebApi that takes no other kind and declares an ordinary method; and a test method carries a test attribute. The marks table on the [model page](https://litespec.dev/4.0.0/core/model.md#marks) states which record each kind names. A technical class carries an `implements` mark naming a Behavior record it serves, or a `follows` mark naming the provision, decision, or exception that shapes it. The diagnostic sits on the type or method name.

### Failing Example

```csharp
internal sealed class SubmitExpenseCommandHandler(...)
    : ICommandHandler<SubmitExpenseCommand, SubmitExpenseCommandResult>
{
    // Loads the expense, submits it, stages it, and returns the result.
}
```

A technical class with no mark reports as well:

```csharp
internal sealed class SubmitExpenseValidator
{
    public Task ValidateAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
```

### Passing Example

```csharp
/// <implements>use-case/spending.submit-expense</implements>
internal sealed class SubmitExpenseCommandHandler(...)
    : ICommandHandler<SubmitExpenseCommand, SubmitExpenseCommandResult>
{
    // Loads the expense, submits it, stages it, and returns the result.
}
```

The same validator with its `implements` mark passes:

```csharp
/// <implements>use-case/spending.submit-expense</implements>
internal sealed class SubmitExpenseValidator
{
    public Task ValidateAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
```

A technical class with a `follows` mark passes as well:

```csharp
/// <follows>litespec/backend/persistence#commit-each-command-pipeline-once</follows>
internal sealed class CommitStep
{
    public Task CommitAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
```

### How to Fix

Add the mark naming the record the element serves, in the style the project declares. A code fix adds the missing mark, with one action per candidate record titled with the record title, and no Fix All. For a technical class the fix offers the use-case records that handlers in the same folder mark. When no sibling handler marks a use case, name the Behavior record it serves or the provision, decision, or exception that shapes it.

## Notes

### What the Rule Ignores

The rule does not report a port or a domain service, which are recognized only by their mark; an unmarked port is found from the top, through its external system. It does not report a state-changing method that raises no event, which is recognized only once it carries a mark. It does not report a minimal-API route with no endpoint type. A record, interface, nested type, generated class, migration, or class with no ordinary method is never a technical class. Types in test projects are never domain events, jobs, or endpoints. The rule reads C# only; frontend `litespec` constants are checked by `litespec model check`. The rule stays silent when no `.litespec/project.json` is in reach, or when the docs root it names cannot be resolved; the CLI owns that configuration error.

### Severity

The finding names no record, so it reports as an error. A finding that a live exception covers stays silent. An `.editorconfig` entry for the rule id overrides the computed severity.
