Cairnloop.Workers.ToolExecutionWorker (cairnloop v0.1.0)

Copy Markdown View Source

The ONLY place run/3 is ever called in Cairnloop.

Consumes a :execution_pending ToolApproval lane, re-validates the proposal against current policy/scope, calls the tool's run/3 on success, and co-commits the outcome (:executed + :succeeded result state + append-only event).

Fail-closed on re-validation: policy/scope change since the resume worker ran causes :invalidated/:execution_failed with a humanized reason — nothing is written (T-16-02).

Idempotency layers (D16-05, T-16-01)

  1. Oban job uniquenessunique: [period: :infinity, keys: [:approval_id]] prevents double-enqueue (no two workers race for the same approval).
  2. Pre-execution terminal guard (LAYER-1) — any non-:execution_pending status is a true no-op (replayed/duplicate job, wrong-lane approval, already executed).
  3. LAYER-2 terminal guard — if ToolProposal.result_state == :succeeded, the approval has already been executed; another no-op (guards against TOCTOU between LAYER-1 check and commit, e.g. very fast replay).
  4. Run-level idempotency key — passed into run/3 context as :run_idempotency_key; the tool uses an indexed existence check to dedup its own host write (Stripe-style).

Retry semantics (D16-07)

  • Transient {:error, reason} from run/3 with attempt < max_attempts → return {:error, reason} so Oban's built-in backoff retries.
  • Permanent failure (re-validation fail, or attempt >= max_attempts) → record terminal :execution_failed and return {:cancel, reason} (Oban discards; never retries).

Telemetry (D16-10)

[:cairnloop, :governance, :action_executed] and [:cairnloop, :governance, :action_failed] are emitted AFTER a successful with pipeline via Governance.Telemetry — never inside the clause list and never instead of a ToolActionEvent (D-29).