# LS1004: State Case Is Not Sealed

## Intent

LS1004 is a compiler check that reports a lifecycle state case in Domain, the layer that holds business rules, left open for extension, which lets a later type add states the business never defined. This page states what the rule reports, where the error sits, and how to seal the case.

## Reference

### What the Rule Enforces

LS1004 enforces [Model every Aggregate lifecycle with state records](https://litespec.dev/4.0.0/backend/dotnet/domain.md#model-every-aggregate-lifecycle-with-state-records) (`litespec/backend/dotnet/domain#model-every-aggregate-lifecycle-with-state-records`). It runs in Domain only. Its category is `LiteSpec.Domain`. Severity and enablement follow the [Analyzers overview](https://litespec.dev/4.0.0/analyzers/README.md). It decides at the end of compilation, as the [Analyzers overview](https://litespec.dev/4.0.0/analyzers/README.md) describes.

### What the Rule Reports

The rule reports a non-abstract, non-sealed class that derives directly from a recognized state base. A state base is an abstract record whose name ends in `State` and either matches `{Aggregate}State` or is an aggregate `State` property type. The diagnostic sits on the case name.

### Failing Example

```csharp
public abstract record OrderState;

public record OrderDraftState : OrderState;
```

### Passing Example

```csharp
public abstract record OrderState;

public abstract record OrderOpenState : OrderState;

public sealed record OrderDraftState : OrderOpenState;
```

### How to Fix

Mark the case `sealed`, or mark it `abstract` when it is a genuine intermediate with its own sealed cases.

## Notes

### What the Rule Ignores

The rule does not report sealed cases or abstract intermediate cases. It does not run outside Domain.
