# LS5002: Mark Names No Usable Record

## Intent

LS5002 is a compiler check that reports a mark naming no record, a record of a type its code element does not take, or a mark on a type or method that takes no mark, because a mark pointing nowhere leaves the element unlinked. This page states what the rule reports, where the error sits, and how to name a record the element takes.

## Reference

### What the Rule Enforces

LS5002 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, on every marked code element and test. Its category is `LiteSpec.Traceability`.

### What the Rule Reports

The rule reports a mark whose identifier matches no record, or matches a record of a type its code element does not take, such as a handler marking a rule. The marks table on the [model page](https://litespec.dev/4.0.0/core/model.md#marks) states which record type each kind takes. A test proves the lowest record it verifies: a scenario, a rule, a quality requirement, a technical decision, an external system, an integration event, or a provision of the carried release, read from the provision ids the package embeds. A proves mark naming a functional or policy requirement, a product decision, or any other kind a test does not take reports, as does one naming an unknown provision. The rule also reports a mark on a type or method that takes no mark: a reading method, a private helper, or an unrecognized class carrying a mark, or a proves mark on a method with no test attribute. A method that only reads or computes performs no act and carries no mark, following [Give Each Use Case Its Own Act](https://litespec.dev/4.0.0/backend/domain.md#give-each-use-case-its-own-act). On a technical class an `implements` mark names a Behavior record it serves, and a `follows` mark names a provision of the carried release, read from the provision ids the package embeds, or a decision or exception. A `follows` mark on any element is checked and never stray. The diagnostic sits on the mark.

### Failing Example

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

A mark on a method that takes no mark reports as well:

```csharp
public sealed class ExpenseCalculator
{
    /// <implements>use-case/spending.submit-expense</implements>
    public int ApprovedCount() => 0;
}
```

An `implements` mark naming a non-Behavior record on a technical class reports as well:

```csharp
/// <implements>decision/0002-store-expenses-as-documents</implements>
internal sealed class SubmitExpenseValidator
{
    public Task ValidateAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
```

A `follows` mark naming no decision reports as well:

```csharp
/// <follows>decision/0002-store-expences-as-documents</follows>
internal sealed class ExpenseRepository
{
    public Task StoreAsync(object expense, CancellationToken cancellationToken) => Task.CompletedTask;
}
```

A proves mark naming a functional requirement reports as well:

```csharp
public sealed class ExpenseTests
{
    /// <proves>requirement/approval-reminders.receipt-threshold</proves>
    [Fact]
    public void Submitting_without_a_receipt_fails()
    {
    }
}
```

### 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 method with no mark passes:

```csharp
public sealed class ExpenseCalculator
{
    public int ApprovedCount() => 0;
}
```

The same validator with a use case it serves passes:

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

The same repository with a decision that exists passes:

```csharp
/// <follows>decision/0002-store-expenses-as-documents</follows>
internal sealed class ExpenseRepository
{
    public Task StoreAsync(object expense, CancellationToken cancellationToken) => Task.CompletedTask;
}
```

The same test proving a quality requirement passes:

```csharp
public sealed class ExpenseTests
{
    /// <proves>requirement/expense-submission.month-end-submissions</proves>
    [Fact]
    public void Month_end_submissions_stay_fast()
    {
    }
}
```

### How to Fix

Name a record of the type the element takes, spelled as the record states it. A test names the lowest record it verifies: a quality requirement rather than a functional or policy one, and a technical decision rather than a product one. A code fix corrects a mistyped id, offering the three nearest records of the expected type by edit distance, one action each, with no Fix All. Remove the mark from a type or method that takes no mark, or add the test attribute the proves mark needs. A `follows` mark names a provision of the carried release, or a decision or exception.

## Notes

### What the Rule Ignores

The rule does not report an element with no mark; LS5001 owns that finding. It does not report a mark naming a record of the type its element takes, or an unmarked method that takes no mark. It does not report whether a provision's page applies to the project; `litespec model check` owns that finding. 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 rule reports an error, whether the mark names a record or not. A finding that a live exception covers stays silent. An `.editorconfig` entry for the rule id overrides the computed severity.
