Skip to content

Feature 6: Success Criteria and Actions

← Structural Results | Next: Execution Model →


UWS defines a first-class vocabulary for deciding whether an operation succeeded, and for specifying what to do when it did or did not. Criteria and actions are declared inline on the operation — there is no shared registry. This guide describes current UWS 1.12 semantics unless it identifies an earlier version.

Criterion Object

A Criterion describes a condition to evaluate:

Field Required Description
condition REQUIRED For simple, a runtime expression or literal condition; otherwise a regex pattern, JSONPath query/pointer, or XPath 1.0 expression
type optional simple (default), regex, jsonpath, or xpath
context REQUIRED when type is regex, jsonpath, or xpath Value to apply the condition against

simple type (default) — uses the normative comparison grammar:

successCriteria:
  - condition: $response.statusCode == 200
  - condition: $response.body.success == true
  - condition: $response.body.count > 0

regex type — evaluates context first, converts its value to a string or UTF-8 byte sequence, then searches it using RE2-compatible semantics. condition is the pattern:

successCriteria:
  - condition: "^(200|201|204)$"
    type: regex
    context: $response.statusCode

jsonpath type — evaluates a JSONPath expression against a context value:

successCriteria:
  - condition: "$.items[?(@.status == 'active')]"
    type: jsonpath
    context: $response.body

xpath type — evaluates an XPath expression against an XML context:

successCriteria:
  - condition: "//order[@status='confirmed']"
    type: xpath
    context: $response.body

For jsonpath, context is a JSON value and condition is a JSONPath query whose selected values are tested for truthiness, or a direct JSON Pointer lookup. For xpath, context is XML text and condition is an XPath 1.0 expression. When any non-simple condition begins with the exact context expression, UWS removes that prefix before interpreting the remaining pattern or query. A missing pointer does not match; a present null value is found but false. See the UWS 1.12 execution contract.

Failure Actions

onFailure handles a leaf runtime error or a false successCriteria result:

Field Required Description
name REQUIRED Unique action name
type REQUIRED end, goto, or retry
workflowId REQUIRED for goto (exactly one of workflowId/stepId) Target workflow
stepId REQUIRED for goto (exactly one of workflowId/stepId) Target step
retryAfter optional Cancellable seconds to wait before retrying. MUST be ≥ 0
retryLimit REQUIRED for retry Number of retries after the initial attempt. MUST be ≥ 1
criteria optional Additional conditions that scope this action

When successCriteria is non-empty, every criterion must match; an empty list adds no success condition. Within either action list, actions are considered in declaration order and the first matching action is applied. All criteria on an action must match, while an empty action criteria list matches immediately. If criterion evaluation itself fails, the operation fails directly without an action. If no failure action matches, the operation failure propagates. A retry limit counts retries after the first attempt, so retryLimit: 3 permits four total attempts; every retry gets a fresh operation timeout. An exhausted retry does not fall through to a later action as a fallback.

Success Actions

onSuccess fires when the operation's successCriteria are all satisfied:

Field Required Description
name REQUIRED Unique action name
type REQUIRED end or goto
workflowId REQUIRED for goto (exactly one of workflowId/stepId) Target workflow
stepId REQUIRED for goto (exactly one of workflowId/stepId) Target step
criteria optional Additional conditions that scope this action

Example 1: Retry and Failure Routing

Retry server errors up to 3 additional times; end cleanly on client errors; route other matching failures to an error handler.

operationId: charge_payment
sourceDescription: stripe_api
openapiOperationId: createCharge
successCriteria:
  - condition: $response.statusCode == 200
  - condition: $response.body.status == "succeeded"
onFailure:
  - name: retry_on_5xx
    type: retry
    retryAfter: 2
    retryLimit: 3
    criteria:
      - condition: $response.statusCode >= 500

  - name: skip_on_4xx
    type: end
    criteria:
      - condition: $response.statusCode >= 400
      - condition: $response.statusCode < 500

  - name: escalate
    type: goto
    workflowId: payment_error_handler

retry_on_5xx only activates when status ≥ 500. The initial attempt plus three retries makes at most four attempts. If the retry limit is exhausted, that action returns the failure; skip_on_4xx and escalate are not fallback actions for the same 5xx failure. skip_on_4xx activates for 4xx. escalate catches failures that do not match either earlier action.

Example 2: goto to a Specific Step

On success, branch directly to a named step rather than a whole workflow:

operationId: check_eligibility
sourceDescription: rules_api
openapiOperationId: evaluateRules
successCriteria:
  - condition: $response.body.eligible == true
onSuccess:
  - name: fast_track
    type: goto
    stepId: approve_immediately
    criteria:
      - condition: $response.body.score >= 90

  - name: standard
    type: goto
    stepId: queue_for_review

fast_track sends high-scoring applicants to approval; otherwise the unconditional standard action sends the applicant to the review queue. In UWS 1.11, goto is a terminal transfer: it unwinds the entire active top-level run, including any sub-workflow, loop, or forEach item, invokes the target and its dependencies in root orchestration scope, and ends the run after the target completes. It does not resume at the caller or continue with later siblings. A root target already completed, skipped, or in flight fails explicitly instead of replaying or waiting. A same-named record inside a prior workflow call does not count as a completed root target.

Example 3: goto to a Workflow on Failure

Route persistent failures to a dedicated error-handling workflow:

operationId: sync_inventory
sourceDescription: warehouse_api
openapiOperationId: syncStock
successCriteria:
  - condition: $response.statusCode == 200
onFailure:
  - name: retry_briefly
    type: retry
    retryAfter: 5
    retryLimit: 2
    criteria:
      - condition: $response.statusCode >= 500

  - name: raise_incident
    type: goto
    workflowId: ops_incident_workflow

For a failure that matches retry_briefly, the retry action is selected first. If its two retries are exhausted, the operation failure propagates; raise_incident does not automatically run as a fallback. Use mutually exclusive action criteria or handle retry exhaustion in the runtime/profile when the incident workflow must run afterward.

Example 4: end on Partial Success

Stop early when there is nothing left to do, without calling it an error:

operationId: list_pending_orders
sourceDescription: orders_api
openapiOperationId: getPendingOrders
successCriteria:
  - condition: $response.statusCode == 200
onSuccess:
  - name: nothing_to_process
    type: end
    criteria:
      - condition: $response.body.total == 0

If the list is empty, execution ends cleanly. If items exist, the default behavior continues to the next step.

Example 5: Multi-Criterion successCriteria

All criteria in successCriteria must be satisfied for the operation to be considered successful:

operationId: create_session
sourceDescription: auth_api
openapiOperationId: initiateSession
successCriteria:
  - condition: $response.statusCode == 201
  - condition: $response.body.token != null
  - condition: "^[A-Za-z0-9_-]{32,}$"
    type: regex
    context: $response.body.token
onFailure:
  - name: auth_failure
    type: goto
    workflowId: handle_auth_error

All three criteria must pass. If the token is missing or malformed, auth_failure fires.

Inline Declaration

UWS does not provide a reusable component registry for criteria and actions. Each operation declares its own. This keeps the document self-describing and allows sibling operations to evolve independently without shared state.

From The Big Fixture

The large fixture combines simple and regex criteria with retry and goto failure actions:

onFailure "retry_run_llm_primary" {
  type       = "retry"
  retryAfter = 5
  retryLimit = 2
  criterion {
    condition = "$error.transient == true"
    type      = "simple"
  }
  criterion {
    condition = "timeout|rate limit"
    type      = "regex"
    context   = "$error.message"
  }
}

onFailure "review_run_llm_primary" {
  type       = "goto"
  workflowId = "wf_manual_review"
  criterion {
    condition = "$error.transient != true"
    type      = "simple"
  }
}

Full context: testdata/big/big.hcl.


← Structural Results | Next: Execution Model →