# Requires — named preconditions, and the live checklist

> Named conditions that must hold before something may happen, declared on a state or on a slot — and readable as a live checklist so a screen can show what is left instead of refusing the button afterwards. Where you declare it decides what it gates: on a slot it gates the deposit into that wait; on a state it IS the state's completion condition.

<!-- id: workflow-requires · area: workflow · stability: stable · html: https://osysharp.com/reference/workflow/requires/ -->

## Summary        {#summary}
`Requires` names the conditions standing between an item and progress, and the platform both **enforces** them and
**reports** them. The reporting half is the point: a rule the engine will refuse is a rule a screen should be able to
show before anybody presses anything.

## Signature      {#signature}
```osy title="declaring a named condition and what to tell a human" syntax
Requires {
  <Name> {
    Must    = <predicate over this.Item>;
    Message = "what to tell a human when it does not hold";
  }
  …
}
```

Read the live checklist back:

```osy title="reading the live checklist back for a screen" syntax
<Wf>.For(item).Requirements            // List<RequirementStatus> — the state's AND its slots'
<Wf>.For(item).<Slot>.Requirements     // just that one wait's
```

## Description    {#description}

### Where you declare it decides what it gates    {#scope}
This is the distinction to hold, and the two are not variations of one rule:

| declared on | gates | means |
|---|---|---|
| a **slot** (`subscribe … { Requires { … } }`) | the **deposit** into that wait | *"you may not resolve without a root cause"* |
| a **state** (`state X { Requires { … } }`) | the state's **completion** | *"this state is done when all of these hold"* |

A slot's criteria are checked when somebody tries to fill it — an unmet one refuses the deposit and hands back which
criteria failed, with their messages. A state's criteria replace the default *"every armed slot is satisfied"*
completion test, which is how a quorum is expressed: three voters armed, done at two.

### The checklist returns BOTH, and each row names its slot    {#checklist}
`<Wf>.For(item).Requirements` returns the state's own criteria first, then each of its slots' in declaration order.
Every row carries `Slot` — the wait it gates, or **null** for a state criterion.

That member is not decoration. *"Record a root cause before you can resolve"* and *"triage it before this state is
done"* are different sentences about different acts, and on one flat list a screen cannot group them or say which
button each belongs to.

⚠ **The unscoped read used to return the state's criteria ALONE**, so a slot-scoped `Requires` — the commonest kind —
came back empty. The gate still refused correctly, which made it worse than a plain omission: the app rendered a
checklist saying there was nothing left to do and then refused the button. **An empty checklist and a satisfied one
are the same screen.**

### The rows are LIVE    {#live}
Every predicate is evaluated against `this.Item` at the moment of the read, and nothing is stored. Re-reading after a
change gives the new answer — so a form can re-check as fields are filled.

## Examples       {#examples}
A ticket that must be triaged before the state is done, and cannot be resolved without a root cause:

```osy title="a rule about the wait, and a rule about the state" test app=workflow-requires
enum Stage { Working, Done }

[Principal] entity Agent {
  [Required, MaxLength(80)] string Name;
  security { allow read when IsAuthenticated || IsAnonymous; }
}

entity Ticket {
  [Required, MaxLength(120)] string Subject;
  [MaxLength(200)] string? RootCause;
  bool Triaged;
  Stage State;
  security { allow read, create, update when IsAuthenticated || IsAnonymous; }
}

workflow TicketFlow {
  Tracks    = Ticket.State;
  Autostart = true;
  Initial   = Working;

  event Resolve();

  state Working {
    // About the STATE: it is not done until this holds.
    Requires {
      Triaged { Must = this.Item.Triaged; Message = "triage it first"; }
    }

    // About filling THIS WAIT: the deposit is refused until this holds.
    subscribe Resolve() as Resolver {
      Requires {
        RootCause { Must = this.Item.RootCause != null; Message = "record a root cause"; }
      }
    }

    on Resolver { goto Done; }
  }

  terminal success Done { }
}

// What is left to do — everything, grouped by what it blocks.
List<Osysharp.Workflow.RequirementStatus> Outstanding(Ticket ticket) {
  return TicketFlow.For(ticket).Requirements.Where(r => !r.Met).ToList();
}

// Just the wait's own gate — what to show beside the Resolve button.
List<Osysharp.Workflow.RequirementStatus> BeforeResolving(Ticket ticket) {
  return TicketFlow.For(ticket).Resolver.Requirements.ToList();
}
```

## Notes          {#notes}
**`Requires` is not authorization.** It gates the base fact, never the person: *"is the work complete"*, not *"may you
do this"*. Who may fill a wait is the slot's [`Candidates`](https://osysharp.com/reference/workflow/candidates/), checked first — a refusal there is
a `WorkflowAuthorizationException`, while an unmet criterion is a `RequirementsNotMet` carrying the failed criteria.
A UI tells them apart deliberately: one greys a button with a checklist, the other should not have offered it.

**A refused deposit is recorded.** The refusal writes a `Refused` row to the [trail](https://osysharp.com/reference/workflow/audit/), so "why did
this never get resolved" has an answer.

**`complete when` is the other way to say a state is done.** [`complete when (<predicate>)
goto <State>`](https://osysharp.com/reference/workflow/complete-when/) states one condition and where it goes; a state-level `Requires` states several NAMED ones with
messages, and is what you want when a human needs to be told which is missing.

## See also       {#see-also}
- [subscribe](https://osysharp.com/reference/workflow/subscribe/) — the slot a `Requires` is declared inside
- [Transitions — where this item may go next](https://osysharp.com/reference/workflow/transitions/) — where the item may go next, the read this checklist sits beside
- [Candidates (slot)](https://osysharp.com/reference/workflow/candidates/) — who may fill the wait, the gate checked before this one
- [Acting on an inbox row (deposit, claim, release)](https://osysharp.com/reference/workflow/inbox-act/) — depositing, which is what a slot's criteria gate
