# Build a durable workflow

This recipe follows the checked support-triage application, where a durable
workflow records policy lookup before an agent can propose ticket escalation.
The `.one` excerpt mirrors the current owning example; the smaller Rust result
handling excerpts are illustrative end-product syntax.

## 1. Separate workflow decisions from activities

```one
one 1

semantic example.support
    domain one.contracts@1
    workflow SupportTriageLifecycle@1
        accepts example.support#TriageRequest@1
        returns example.support#TriageResponse@1
        concurrency "support/request"
        retention 30d
        evidence support.request example.support#TriageRequest@1
        evidence support.policy example.support#TriageResponse@1

        activity lookup_policy
            operation example.support#Policy.Lookup@1
            effect replay safe
            maximum attempts 1
            owns cancellation true
            on accepted terminal
            on rejected terminal
            on unsupported terminal
            on unsatisfied terminal
            on cancelled terminal
            on pending approval terminal
            on defect terminal
            on outcome unknown terminal
```

The workflow declares durable coordination and exhaustively classifies every
activity outcome. The read-only policy lookup is replay-safe and attempted at
most once.

## 2. Write deterministic decisions

```rust,ignore
match lookup_policy(request).await {
    ActivityResult::Accepted(policy) => continue_with(policy),
    ActivityResult::Rejected(fault) => stop_rejected(fault),
    ActivityResult::PendingApproval(request) => suspend(request),
    ActivityResult::OutcomeUnknown(effect) => suspend_for_reconciliation(effect),
    ActivityResult::Cancelled => stop_cancelled(),
    other => stop_with_exact_disposition(other),
}
```

The workflow cannot read ambient time, randomness, network, filesystem, or
secrets. Timers, signals, human decisions, activity outcomes, and provider
observations arrive as retained events.

## 3. Reconcile an uncertain activity

```rust,ignore
match ctx.activity(escalate_ticket(request)).await {
    ActivityResult::Completed(ticket) => complete(ticket),
    ActivityResult::Rejected(reason) => return_to_operator(reason),
    ActivityResult::OutcomeUnknown(effect) => {
        ctx.suspend_for_reconciliation(effect).await?
    }
    ActivityResult::Cancelled => stop_without_redispatch(),
}
```

`OutcomeUnknown` is not converted to failure and is never automatically
redispatched. Reconciliation updates the same effect relationship with exact
observation and receipt evidence.

## 4. Prove replay and interruption

```console
cargo test -p support-triage-agent --all-targets --offline
one check --workspace systems/system-idl/examples/support-triage-agent --offline
```

Replay validates compatible decisions against retained history without
repeating external effects. An incompatible workflow revision reports the
exact history range it cannot serve.

## 5. Select the durable engine later

Planning selects inference, encrypted durable session, Authority, History,
Build, and local-release providers independently. Replacing the deterministic
inference provider with the admitted HTTP provider does not revise the workflow
or agent declaration.

## Executable evidence

The checked-in
[support-triage project](https://github.com/muijf/one/tree/main/systems/system-idl/examples/support-triage-agent)
owns the exact source and lock, Rust `one::agent` parity test, deterministic
provider execution, bounded tool/effect trace, complete public lifecycle, and
idempotent resume evidence.

See [durable work](/one/guides/durable-work) and
[recovery and continuity](/one/lifecycle/recovery).
