# on — a route and its arms

> An `on` route is what a state does when an event arrives: a flat body, or guarded `when` arms tried top to bottom with a `default`. Inside an arm, a nested `when (…) { …; goto X; }` is a branch out of the state.

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

## Summary        {#summary}
`on <Event> { … }` inside a state says what happens when that event arrives there. Its body is either one flat body
or a list of ARMS: `when (guard) { … }` arms, tried top to bottom, and an optional `default { … }`. An arm usually ends
in `goto <State>;`. Inside an arm, a `when (…) { …; goto X; }` may NEST — a branch out of the state.

## Signature      {#signature}
```osy title="the shapes of a route" syntax
on Event { …; goto Next; }                         // a flat body: one implicit default arm

on Event(Decision d) {
  when (d == Decision.Reject) { goto Rejected; }   // arms are tried top to bottom
  default {
    when (this.Item.Urgent) { Page(); goto Urgent; }   // a NESTED when must end in goto
    goto Approved;
  }
}
```

## Description    {#description}

### Arms   {#arms}
The arms of a route are its top level. The first `when` whose guard holds runs; if none does, `default` runs; if
there is no `default`, the event changes nothing. An arm's `goto` is where the run goes next — an arm without one
stays in the state, which is how a route records something and keeps waiting.

### A `when` nested inside an arm   {#nested-when}
Inside an arm, `when (guard) { …; goto X; }` is a branch OUT of the state: if the guard holds, its body runs and the
run goes to `X`; otherwise the arm carries on. It is exactly `if (guard) { …; goto X; }`, and that is how an exported
app spells it.

It must end in `goto`. A nested `when` that stays in the state would read as one more arm to pick from, and it is
not one — the rest of the enclosing arm runs after it — so it is refused, and the message names both ways to write
what you meant:

- a branch that leaves the state: end it with `goto <State>;`;
- a step that stays: write `if (…) { … }`.

A `when` outside any `on` route (in an `enter { }`, in a function) is not an arm at all; write `if`.

### Why nest at all   {#why}
Without it, "urgent work goes to the urgent state, everything else to the queue — but both are accepted first" has to
be two top-level arms that repeat the shared part:

```osy title="the flattened form nesting replaces" syntax
on Accept {
  when (this.Item.Urgent) { Stamp(); goto Urgent; }
  default { Stamp(); goto Queued; }
}
```

## Examples       {#examples}
A whole app, compiled: an urgent job leaves for `Urgent` from inside the `default` arm, every other one for `Done`.

```osy title="a nested when that leaves the state" test app=workflow-route-nested-when
using Osysharp.Workflow;

enum JobStage { Open, Urgent, Done }

entity Job {
  [Required, MaxLength(100)] string Title;
  bool Urgent;
  [MaxLength(100)] string Note = "";
  JobStage Stage;
  security { allow read, create, update when IsAuthenticated || IsAnonymous; }
}

workflow JobFlow {
  Tracks    = Job.Stage;
  Autostart = true;
  Initial   = Open;

  event Go();

  state Open {
    on Go {
      default {
        when (this.Item.Urgent) { this.Item.Note = "paged"; goto Urgent; }
        goto Done;
      }
    }
  }
  state Urgent {
    on Go { goto Done; }   // paged — the next Go closes it
  }
  terminal success Done { }
}

void Start(Job j) { JobFlow.RaiseGo(j); }
```

## See also       {#see-also}
- [Raising a workflow event](https://osysharp.com/reference/workflow/raise/) — how an event reaches a run
- [subscribe](https://osysharp.com/reference/workflow/subscribe/) — a state's wait for an event, and its promises
- [Transitions — where this item may go next](https://osysharp.com/reference/workflow/transitions/) — the moves a run can make from where it is
- [enter and exit (a state's arrival and departure hooks)](https://osysharp.com/reference/workflow/enter-exit/) — what runs on entering and leaving a state
