Shared adapter execution for sync and Oban worker dispatch paths.
Classification contract
classify/1 now returns a 3-tuple {outcome, error_class, detail} so
:temporary | :permanent | :bounced classification is preserved end-to-end:
adapter.deliver -> classify -> Deliveries.record_attempt(error_class:)
-> attempt row .error_class column
-> trace explanation
-> Oban worker {:ok | {:error, _}} returnrun_delivery/1 passes error_class into Deliveries.record_attempt/2. The
return shape for sync consumers is {:ok, %{delivery, attempt}} |
{:error, step, reason, changes} | {:error, term()}. The Oban worker reads
the recorded attempt's outcome + error_class to decide its
Oban return value (retry vs terminal vs success).
Summary
Functions
@spec run_delivery(Chimeway.Delivery.t()) :: {:ok, %{delivery: Chimeway.Delivery.t(), attempt: Chimeway.DeliveryAttempt.t()}} | {:error, atom(), term(), map()} | {:error, term()}
@spec run_target(Chimeway.Delivery.t(), keyword()) :: {:ok, %{ delivery: Chimeway.Delivery.t(), target: Chimeway.DeliveryTarget.t(), attempt: Chimeway.DeliveryTargetAttempt.t() }} | {:noop, term()} | {:error, term()}