Type to search pages and rules.

Browse pages

LS5001: Code Element Carries No Mark

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.

Markdown

Reference#

What the Rule Enforces#

LS5001 enforces 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 (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 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#

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

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

Passing Example#

C#
/// <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:

C#
/// <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:

C#
/// <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.