Raxol.Payments.PolicyGate (Raxol Payments v0.2.0)

Copy Markdown View Source

Single source of truth for non-budget policy checks.

Composes Raxol.Payments.SpendingPolicy.domain_approved?/2 and requires_confirmation?/2 into one decision used by every payment entry point. Budget caps (per-request, session window, lifetime) stay in Raxol.Payments.Ledger so spend recording remains atomic.

Trust model

  • domain MUST be the host the agent declared intent toward -- for HTTP flows that is the request URL host, not anything supplied by the server (challenge body, response headers).
  • amount is the server-claimed amount from the protocol challenge, so the per-request cap and confirmation threshold are evaluated against the server's claim.

Confirmation gate

When the amount exceeds policy.require_confirmation_above, the gate consults the caller-supplied :on_confirm callback. With no callback the gate denies, which is the safe default for non-interactive paths (e.g. HTTP 402 auto-pay). Callers that can surface a prompt synchronously -- agent Command hooks, interactive shells -- can pass a 2-arity function returning :approve or :deny.

Summary

Functions

Evaluate the non-budget policy gates for a payment attempt.

Types

confirm_fn()

@type confirm_fn() :: (Decimal.t(), String.t() -> :approve | :deny)

decision()

@type decision() :: :ok | {:deny, deny_reason()}

deny_reason()

@type deny_reason() ::
  {:domain_not_approved, String.t()}
  | {:requires_confirmation, Decimal.t(), String.t()}

opts()

@type opts() :: [{:on_confirm, confirm_fn() | nil}]

Functions

evaluate(policy, amount, domain, opts \\ [])

Evaluate the non-budget policy gates for a payment attempt.

Returns :ok if the payment may proceed, or {:deny, reason} if the domain is not approved or the amount requires confirmation that was not granted.