A self-loop with a guard.

Audit loop

retry records another attempt and leaves the record on Waiting. The guard stops that loop once retry_count reaches 3. finish is the way out. A self-loop with no guard is fsm/unbounded-self-loop.

app audits "Audits" {}

entity Attempt {
  retry_count: number

  workflow {
    initial Waiting
    states Waiting, Done
    terminal Done

    retry:  Waiting -> Waiting when retry_count < 3
    finish: Waiting -> Done
  }
}