# `SquidMesh.Runtime.Compensation`
[🔗](https://github.com/ccarvalho-eng/squid_mesh/blob/main/lib/squid_mesh/runtime/compensation.ex#L1)

Executes durable saga compensation for completed workflow steps.

Compensation is intentionally separate from normal failure routing. Forward
retries and `:error` transitions decide whether the workflow can continue.
Only after a run reaches terminal failure does the runtime dispatch a
compensation job, which walks completed reversible steps in reverse completion
order and records each callback result in the original step's recovery
metadata.

# `compensation_error`

```elixir
@type compensation_error() :: {:compensation_failed, [map()]}
```

# `compensate_completed_steps`

```elixir
@spec compensate_completed_steps(
  SquidMesh.Config.t(),
  SquidMesh.Workflow.Definition.t(),
  SquidMesh.Run.t(),
  map()
) :: :ok | {:error, compensation_error() | term()}
```

Runs all pending compensation callbacks for a failed run.

Completed steps are evaluated in reverse completion order. A successful
callback stores `:completed` plus its output under `recovery.compensation`;
a failed callback stores `:failed` plus the normalized error and returns a
structured `{:compensation_failed, failures}` error after all eligible
callbacks have been attempted.

# `compensation_available?`

```elixir
@spec compensation_available?(
  module(),
  SquidMesh.Workflow.Definition.t(),
  Ecto.UUID.t()
) :: boolean()
```

Returns whether a failed run has any completed step with compensation pending.

The runtime uses this before enqueuing a compensation job so workflows without
reversible completed work keep their historical worker-count and dispatch
behavior.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
