Type to search pages and rules.

Browse pages

LS2020: Module Names a Type Outside Another Module's Contracts

LS2020 is a compiler check that reports a module naming another module's type outside its Contracts/ folder, because a read past the public surface couples the caller to internals the owner may change. This page states what the rule reports, where the error sits, and how to read through the contracts the owner publishes.

Markdown

Reference#

What the Rule Enforces#

LS2020 enforces Reach Another Module Only Through Contracts (litespec/backend/dotnet/architecture#reach-another-module-only-through-contracts). It runs in every layer except Test. Its category is LiteSpec.Layers. Severity and enablement follow the Analyzers overview.

What the Rule Reports#

The rule reports a name that resolves to a type in another module declared outside that module's Contracts/ folder. The diagnostic sits on the name, and its message names the type and the module that owns it.

Failing Example#

C#
namespace Claimwick.Reporting.UseCases.ReadExpenseTotals;

internal sealed class TotalsQueryHandler
{
    public void Handle() => Expense.FromRecord();
}

with Expense declared in the spending module outside its Contracts/ folder.

Passing Example#

C#
namespace Claimwick.Reporting.UseCases.ReadExpenseTotals;

internal sealed class TotalsQueryHandler(IExpenseTotals totals)
{
}

with IExpenseTotals declared in the spending module Contracts/Ports/ folder.

How to Fix#

Read the data through a port in the owner Contracts/Ports/ folder, which returns contract results keyed by typed identifier, or answer with a query over data the module already holds. Load no foreign aggregate or repository.

Notes#

What the Rule Ignores#

The rule does not report a name in a Test file or in a file the layer rules cannot place. It does not report a type in the same module or in the owner Contracts/ folder, or a name that resolves to no project source file. Under the layer-projects extension the rule does not run: project references hold the module boundary instead.