# Success criteria and failure handling

Time travel with the Warp API is thrilling, but it's not all smooth jumps and perfect landings. In Arazzo, `successCriteria` let you define what "success" means and what to do when the timeline goes sideways. Whether it's a paradox, a timeout, or an unauthorized hop, these tools keep your workflows on track. Let's explore how to set them up, with Warp examples to guide us through the chaos of time manipulation.

## Defining `successCriteria`

The `successCriteria` field in a step is your checkpoint—it tells Arazzo how to confirm a step worked as expected. It's a list of conditions, typically runtime expressions, that must all pass for the step to succeed. Think of it as your time-travel log: "Did we land in 1889? Is the timeline stable?"

Here's a basic check for Warp's `timeTravel`:


```yaml
steps:
  - stepId: "jumpTo1889"
    operationId: "warpApi.timeTravel"
    requestBody:
      payload:
        destination: "tml_tesla_mission_1"
    successCriteria:
      - condition: "$statusCode == 200"
```

## How it works

- `$statusCode`: A runtime expression grabbing the HTTP response code.
- `== 200`: Ensures the jump returned a 200 OK—mission accomplished!


You can layer conditions for precision. Let's verify the arrival time too:


```yaml
successCriteria:
  - condition: "$statusCode == 200"
  - condition: "$response.body#/arrival_time == '1889-03-10T23:50:00Z'"
```

Both must be true—or the step fails, triggering `onFailure`. You can also use JSONPath for deeper checks:


```yaml
successCriteria:
  - condition: "$statusCode == 200"
  - condition: "$.items_transported.length > 0"
    context: "$response.body"
    type: "jsonpath"
```

This confirms we brought back Tesla's blueprint (items_transported isn't empty).

## Configuring `onFailure`

When a step fails—maybe Warp's servers are overloaded or your token expired—`onFailure` steps in.
It's an optional field that decides the next move.
Your options are:

- `end`: Abort the workflow immediately.
- `retry`: Try the step again, with limits.
- `goto`: Jump to another step or workflow as a backup plan.


## Configuring `onSuccess`

When a step passed—`onSuccess` steps in.
It's an optional field that decides the next move.
Your options are:

- `end`: Abort the workflow immediately.
- `goto`: Jump to another step or workflow as a backup plan.


### Exit on failure

For a must-succeed step like setting an anchor:


```yaml
- stepId: "setHomeAnchor"
  operationId: "warpApi.setAnchor"
  requestBody:
    payload:
      timestamp: "2025-02-19T12:00:00Z"
      description: "Home base"
  successCriteria:
    - condition: "$statusCode == 201"
  onFailure:
    - name: "exitOnFailure"
      type: "end"
```

If the anchor doesn't set (not a 201 Created), the workflow stops—because traveling without a return point is a bad idea.

### Retry on failure

For a flaky jump that might timeout (e.g., 503):


```yaml
- stepId: "jumpTo1889"
  operationId: "warpApi.timeTravel"
  requestBody:
    payload:
      destination: "tml_tesla_mission_1"
  successCriteria:
    - condition: "$statusCode == 200"
  onFailure:
    - name: "retryOnTimeout"
      type: "retry"
      retryLimit: 3
      retryAfter: 5
      criteria:
        - condition: "$statusCode == 503"
```

This retries up to 3 times, waiting 5 seconds between tries—perfect for temporary glitches in the time stream.

### Goto another step

For an unauthorized jump (401), go to a re-authentication step:


```yaml
- stepId: "jumpTo1889"
  operationId: "warpApi.timeTravel"
  requestBody:
    payload:
      destination: "tml_tesla_mission_1"
  successCriteria:
    - condition: "$statusCode == 200"
  onFailure:
    - name: "reAuthOn401"
      type: "goto"
      stepId: "reAuth"
      criteria:
        - condition: "$statusCode == 401"
- stepId: "reAuth"
  operationId: "warpApi.someAuthOperation"  # Hypothetical endpoint
  outputs:
    newToken: $response.body#/token
```

If the jump fails with a 401, it skips to reAuth to refresh the token, then you'd loop back manually or adjust the workflow.

## Practical examples

### Handling timeouts

Warp's `monitorTimeline` might timeout (503). Retry, then give up:


```yaml
- stepId: "monitorJump"
  operationId: "warpApi.monitorTimeline"
  parameters:
    - in: query
      name: timeline_id
      value: "tml_tesla_mission_1"
  successCriteria:
    - condition: "$statusCode == 200"
  onFailure:
    - name: "retryOnTimeout"
      type: "retry"
      retryLimit: 3
      retryAfter: 10
      criteria:
        - condition: "$statusCode == 503"
    - name: "exitOnMaxRetries"
      type: "end"
      criteria:
        - condition: "$retryCount >= 3"
```

After 3 failed attempts, it exits—better to abort than risk a corrupted timeline.

### Unauthorized responses

For a 401 on `checkParadox`:


```yaml
- stepId: "checkStability"
  operationId: "warpApi.checkParadox"
  requestBody:
    payload:
      timeline_id: "tml_tesla_mission_1"
      proposed_changes:
        - event: "Retrieve Tesla's blueprint"
          time: "1889-03-10T23:50:00Z"
  successCriteria:
    - condition: "$statusCode == 200"
    - condition: "$.adam_stable == true"
      context: "$response.body"
      type: "jsonpath"
  onFailure:
    - name: "logOn401"
      type: "goto"
      stepId: "logIssue"
      criteria:
        - condition: "$statusCode == 401"
- stepId: "logIssue"
  operationId: "warpApi.someLogOperation"  # Hypothetical logging endpoint
  requestBody:
    payload:
      message: "Unauthorized paradox check"
```

If authorization fails, it logs the issue—great for auditing time-travel mishaps.

## Tips for success

- **Start simple**: Use `$statusCode` checks first, then add response body conditions.
- **Match reality**: Test successCriteria against actual Warp API responses (e.g., does `adam_stable` exist?).
- **Plan B matters**: Add `onFailure` for critical steps—time travel's too wild to wing it.
- **Tune retries**: Set retryLimit and retryAfter based on your API's behavior (Warp's docs suggest timeouts are rare but possible).


## Why it matters

With the Warp API, a failed step could leave you stranded in 1889 or unravel reality itself. Success criteria ensures your jumps, checks, and anchors hit their marks, while `onFailure` offers a safety net for the unexpected. Together, they turn risky time-travel workflows into reliable missions.