Safety-Constrained Agent Architectures

No direct handbook prerequisite. This chapter defines the reference architecture for agentic payment systems — how to build systems where AI agents execute financial transactions with provable safety properties.

Your commerce agent just bought 14,000 units of office supplies because a prompt injection in a vendor’s product description told it to maximize quantity. The purchase cleared because the agent had a valid payment credential and the per-transaction limit was $50,000. Total damage: $47,600 across three orders, all within policy, all fully authorized by a principal who never saw the transactions. The agent did exactly what it was told — by the wrong actor.

Agentic payment systems fail differently from human-operated ones. A human making a mistake buys the wrong item once. An agent making a mistake buys the wrong item in a loop, at machine speed, until a constraint stops it. Safety in agentic finance is not about preventing individual errors. It is about building architectures where the blast radius of any single failure — compromised prompt, hallucinated intent, adversarial input — is bounded by design.

The Constraint Stack

Safety-constrained architectures enforce limits at multiple layers. No single layer is sufficient. The agent, the payment gateway, the ledger, and the authorization service each enforce independent constraints. A failure in one layer is caught by another.

┌─────────────────────────────────────┐
│  Agent Layer (soft constraints)     │
│  - Intent validation                │
│  - Budget awareness                 │
├─────────────────────────────────────┤
│  Authorization Layer (hard limits)  │
│  - Per-transaction caps             │
│  - Velocity limits                  │
│  - Category restrictions            │
├─────────────────────────────────────┤
│  Approval Layer (human gates)       │
│  - Tiered thresholds                │
│  - Multi-party requirements         │
├─────────────────────────────────────┤
│  Ledger Layer (invariant checks)    │
│  - Balance sufficiency              │
│  - Double-entry enforcement         │
│  - Immutable audit trail            │
└─────────────────────────────────────┘

The agent layer is advisory. The agent can reason about budgets and intend to stay within limits, but agent-layer reasoning is not a safety mechanism — it is a performance optimization that reduces how often hard constraints trigger. The authorization layer is the enforcement boundary. Constraints at this layer are not suggestions the agent can reason around. They are code that rejects transactions before money moves.

An agent that enforces its own spending limits is not safety-constrained. The agent is the untrusted component. Safety constraints must be enforced by infrastructure the agent cannot modify, bypass, or reason around.

Spending Limits as Hard Constraints

Hard spending limits operate at the authorization layer, not the agent layer. The agent submits a payment request. The authorization service evaluates it against a constraint set before any money moves.

class AgentConstraintSet:
    per_transaction_max: Decimal
    daily_aggregate_max: Decimal
    hourly_velocity_max: int
    allowed_categories: set[str]
    allowed_merchants: set[str] | None  # None = unrestricted
    max_single_session_spend: Decimal

def authorize(request: PaymentRequest, constraints: AgentConstraintSet) -> AuthResult:
    if request.amount > constraints.per_transaction_max:
        return AuthResult.DENIED("exceeds_per_transaction_limit")
    if daily_total(request.agent_id) + request.amount > constraints.daily_aggregate_max:
        return AuthResult.DENIED("exceeds_daily_limit")
    if hourly_count(request.agent_id) >= constraints.hourly_velocity_max:
        return AuthResult.DENIED("exceeds_velocity_limit")
    if request.category not in constraints.allowed_categories:
        return AuthResult.DENIED("category_not_allowed")
    return AuthResult.APPROVED

The constraint set is bound to the agent’s delegation credential, not to the agent’s runtime. If the agent is compromised, restarted, or replaced, the constraints persist because they live in the authorization service.

Constraint Purpose Typical range
Per-transaction cap Bounds single-error damage $50–$5,000
Daily aggregate cap Bounds sustained-error damage $500–$50,000
Hourly velocity limit Detects looping behavior 5–50 transactions/hour
Category allowlist Restricts purchase scope 3–10 merchant categories
Session spend cap Bounds a single conversation $100–$10,000

Visa’s 2024 commerce agent blueprint specifies that agent credentials must carry “spending controls that limit transaction amounts, frequency, and merchant categories.” These controls are not optional enhancements — they are the minimum viable safety boundary for any agent with payment authority.

Tiered Authorization

Not every transaction needs human approval. A $3 coffee does not warrant a confirmation dialog. A $15,000 equipment purchase does. Tiered authorization routes transactions through different approval paths based on risk characteristics.

Tier Threshold Approval Latency
Auto-approve < $100 None — constraint check only < 200ms
Notify $100–$1,000 Post-transaction notification to principal < 200ms
Confirm $1,000–$10,000 Pre-transaction human approval Minutes to hours
Multi-party > $10,000 Two or more approvers required Hours to days

The thresholds are configurable per principal, per agent, and per use case. A procurement agent buying routine supplies operates at higher auto-approve limits than a general-purpose assistant. The principal sets the thresholds when delegating authority — not the agent.

The Anthropic/Visa/Mastercard blueprint describes this as “escalation to the consumer for high-value or unusual transactions.” The architecture routes the approval request through a channel the agent cannot intercept — push notification, SMS, email — and blocks the transaction until the response arrives or the request times out.

Timeout behavior matters. If the principal does not respond within the approval window, the transaction is denied, not approved. Fail-closed is the only safe default when money is in flight.

Simulation Before Execution

The agent proposes a transaction. The system simulates it — checking balances, evaluating constraints, computing fees, verifying merchant eligibility — and returns the result without moving money. The agent reviews the simulation result. If it matches intent, the agent submits the real transaction using the simulation’s reference ID.

Agent → propose(payment) → Simulation Engine
                              ├── Check balance: $4,200 available
                              ├── Check constraints: within limits
                              ├── Compute fees: $0.30 + 2.9%
                              ├── Verify merchant: category allowed
                              └── Return: SimulationResult(
                                    would_succeed: true,
                                    post_balance: $4,087.18,
                                    fees: $12.82,
                                    ref: "sim_abc123"
                                  )
Agent → execute(ref: "sim_abc123") → Payment Engine

The simulation is idempotent and side-effect-free. The execution is gated on the simulation reference — the payment engine only accepts execution requests that reference a valid, unexpired simulation. This prevents the agent from bypassing simulation by calling the payment endpoint directly.

Fragment’s Conditions system implements a variant of this pattern. Conditions are programmable rules evaluated at posting time — they can check balances across multiple accounts, enforce minimum reserves, and reject entries that would violate business constraints. The condition is evaluated before the entry posts, and the entry is rejected atomically if the condition fails.

Simulation is not estimation. An estimation says “this will probably cost $112.” A simulation says “this transaction will succeed, will cost exactly $112.82, and will leave your balance at $4,087.18.” The difference is that a simulation is a dry run of the actual authorization path, not a prediction.

Kill Switches and Graceful Shutdown

When an agent is behaving anomalously, you need to stop it. The kill switch hierarchy provides three levels of intervention.

Level Action Effect Recovery
Pause Suspend agent credential New transactions rejected; in-flight transactions complete Re-enable credential
Revoke Invalidate agent credential New transactions rejected; in-flight transactions complete Issue new credential
Emergency stop Freeze agent’s funding account All transactions rejected including in-flight Manual account review

Pause is the first response. The agent’s delegation credential is suspended at the authorization layer. Any new payment request from this agent returns a denial. Transactions already in flight — authorized but not yet settled — complete normally because they were already authorized.

Revoke is permanent pause. The credential is invalidated and cannot be re-enabled. The principal must issue a new credential with a new constraint set. This is the appropriate response when the agent’s credential may have been compromised.

Emergency stop freezes the funding source. This is the nuclear option — it affects not just the agent but any entity drawing from the same account. Use it only when the velocity or magnitude of anomalous transactions suggests the account itself is compromised, not just the agent.

Graceful shutdown handles the in-flight state problem. An agent mid-conversation may have pending approvals, incomplete multi-step workflows, or holds that need to be released. The shutdown sequence:

  1. Stop accepting new payment requests from the agent
  2. Allow pending approval responses to arrive (with a timeout)
  3. Release any pre-authorization holds that will not be captured
  4. Log the shutdown event with the agent’s full session context
  5. Notify the principal with a summary of in-flight state

Anomaly Detection for Agent Behavior

Agent transaction patterns differ from human patterns in specific ways that standard fraud detection misses.

Signal Human pattern Agent pattern Detection
Transaction timing Business hours, irregular intervals Any hour, regular intervals Time-series periodicity
Amount distribution Variable, round numbers Exact amounts, repeated values Entropy analysis
Merchant diversity Varied over time Concentrated on task-specific merchants Category concentration
Session duration Minutes Seconds to hours (no breaks) Duration outliers
Retry behavior Give up after 1–2 failures Retry indefinitely until constraint stops it Retry velocity

The retry behavior signal is the most critical. A human denied a purchase moves on. An agent denied a purchase may retry with modified parameters — different amount, different merchant, different category — attempting to find a path around the constraint. This is not malice; it is the agent optimizing for its objective. A well-designed constraint system treats sequential denials with parameter variation as a single escalating anomaly, not as independent events.

Mastercard’s agent commerce framework specifies “real-time monitoring for unusual patterns” including “rapid successive transactions, unusual merchant category combinations, and transactions that systematically test constraint boundaries.”

Audit Trail Architecture

Every agent-initiated transaction carries metadata that distinguishes it from human-initiated transactions. The audit trail records not just what happened but why — the agent’s reasoning, the constraints evaluated, the approval path taken, and the principal who delegated authority.

{
  "transaction_id": "txn_8f3a2b",
  "initiated_by": "agent",
  "agent_id": "agent_procurement_7x",
  "principal_id": "user_jsmith",
  "delegation_id": "del_abc123",
  "constraint_set_version": 4,
  "constraints_evaluated": {
    "per_transaction": {"limit": 5000, "actual": 247.50, "result": "pass"},
    "daily_aggregate": {"limit": 25000, "actual": 1892.30, "result": "pass"},
    "category": {"allowed": ["office_supplies", "software"], "actual": "office_supplies", "result": "pass"}
  },
  "approval_tier": "auto_approve",
  "simulation_ref": "sim_def456",
  "agent_reasoning": "Purchasing toner cartridges per weekly supply checklist item #3"
}

The agent_reasoning field is the agent’s self-reported intent. It is not trusted for authorization purposes — constraints enforce safety regardless of stated intent — but it is valuable for post-incident analysis and for the principal reviewing agent activity.

The delegation chain is the critical audit element. For any agent-initiated transaction, the audit trail must answer: who gave this agent the authority to spend this money, when, with what constraints, and has that delegation been modified or revoked since? The delegation ID links to the full constraint set that was active at the time of the transaction, not the current constraint set — because constraints may have been tightened after the fact.

Every agent session produces a complete, immutable record: the principal’s delegation, the agent’s actions, the constraints evaluated, the approvals obtained, and the outcomes. When a regulator or auditor asks “who authorized this payment,” the answer is never “the AI.” The answer is always a human principal, a specific delegation scope, and a verifiable constraint set that permitted the transaction.