# Design retry, timeout, fallback, and compensation

## When to use

Use this task when a node calls a fallible dependency or performs a reversible effect. Do not add retry automatically: first decide whether repeating the operation is safe and whether the caller can distinguish real output from degraded output.

## Inspect first

- Identify whether the Operator is pure computation, a read, or an external write.
- Find existing idempotency keys, reconciliation, and compensation behavior.
- Read [Chapter 6](/en/v/0.9.8-RC1/06-resilience-by-design) and the [conformance fixture](/assets/v/0.9.8-RC1/chapters/06-resilience-by-design/assets/bloge/bloge-conformance/fixtures/snippets/basic/retry-fallback-output.bloge).

## Required inputs

Obtain the per-attempt deadline, maximum attempts, backoff strategy, acceptable degraded result, idempotency contract, and compensation owner. Stop when any external-write guarantee is unspecified.

## Implementation path

1. Bound each attempt with `timeout`.
2. Add retry only for errors and operations the business dependency allows to repeat.
3. Choose fixed, exponential, or jitter backoff from the dependency's load behavior.
4. Add fallback only when downstream nodes can safely consume an explicitly degraded value.
5. Add compensation for completed reversible effects; keep irreversible effects outside false rollback claims.
6. Test one success, one retry recovery, one exhausted path, and one timeout-after-effect ambiguity.

## MUST / SHOULD / MAY

- **MUST** treat retry as repeated invocation, not as rollback.
- **MUST** make effectful retries idempotent or reconciled.
- **MUST** keep fallback output schema-compatible and semantically distinguishable.
- **MUST** state that engine timeout only stops waiting; it does not prove the remote effect stopped.
- **SHOULD** use jitter or exponential backoff for overloaded shared services.
- **MAY** omit fallback and fail the graph when degradation would produce an invalid business result.

## Failure patterns

- Retry duplicates a charge: introduce an idempotency key and provider-side reconciliation before enabling it.
- Fallback looks like a successful business value: add explicit degraded status or remove fallback.
- Compensation is declared for an action that cannot be undone: replace the claim with a forward recovery or manual repair path.

## Validation

Use a controlled Operator double to make each attempt observable. Assert attempt count, per-attempt timeout, final node state, fallback value, and compensation order. A mock-only pass does not prove the real provider's idempotency or rollback semantics.

## Evidence

- [Resilience chapter](/en/v/0.9.8-RC1/06-resilience-by-design)
- [Operator design chapter](/en/v/0.9.8-RC1/07-designing-good-operators)
- [Pinned runtime source](https://github.com/xbdotl/bloge/tree/cc38fbe5bb79ccc603888e4307cfe566d4674ffc/bloge-core)
- [Retry/fallback fixture](/assets/v/0.9.8-RC1/chapters/06-resilience-by-design/assets/bloge/bloge-conformance/fixtures/snippets/basic/retry-fallback-output.bloge)
