Skip to content

Commit f3358c3

Browse files
committed
feat: Add Fiduciary Circuit Breaker (FCB) risk extension
This PR implements structured risk types for AP2 Section 7.4 (Risk Signals), which was "intentionally left open-ended" in the v0.1 specification. The Fiduciary Circuit Breaker (FCB) pattern provides runtime governance for autonomous agent transactions through: - Trip conditions that evaluate agent behavior against predefined thresholds (VALUE_THRESHOLD, CUMULATIVE_THRESHOLD, VELOCITY, ANOMALY, etc.) - A state machine for governance (CLOSED → OPEN → HALF_OPEN → TERMINATED) - Human escalation protocol for exceptional cases - Structured risk signals for network/issuer visibility Changes: - Add src/ap2/types/risk.py with Python type definitions - Add samples/go/pkg/ap2/types/risk.go with Go type definitions - Add docs/topics/fiduciary-circuit-breaker.md with documentation - Update src/ap2/types/__init__.py to export new types - Update mkdocs.yml to include FCB in navigation This addresses the gap identified in Section 7.4 where temporal gaps, user asynchronicity, and agent identity verification require runtime governance beyond what mandate-based authorization provides.> Add comprehensive unit tests for the Fiduciary Circuit Breaker (FCB) risk extension types: Go tests (samples/go/pkg/ap2/types/risk_test.go): - 11 tests covering type constants, helper methods, JSON serialization - Tests for NewHumanEscalation, NewFCBEvaluation, AddTripResult - Complete integration scenario test Python tests (tests/test_risk.py): - 22 tests covering all enum types and Pydantic models - JSON round-trip serialization tests - B2B quote negotiation integration scenario Also includes minor formatting fix to risk.go (whitespace alignment).
1 parent 0b3379b commit f3358c3

9 files changed

Lines changed: 1724 additions & 0 deletions

File tree

.cspell/custom-words.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ multistep
109109
Mysten
110110
nexi
111111
nosetests
112+
Nygard
112113
Nuvei
113114
objx
114115
octicons
@@ -147,6 +148,7 @@ ropeproject
147148
RPCURL
148149
Rulebook
149150
screenreaders
151+
sess
150152
setlocal
151153
sharedpref
152154
Shopcider
@@ -165,6 +167,7 @@ stretchr
165167
superfences
166168
Truelayer
167169
Trulioo
170+
txns
168171
udpa
169172
unmarshal
170173
viewmodel

.gitleaks.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Gitleaks configuration
2+
# https://github.com/gitleaks/gitleaks
3+
4+
title = "AP2 Gitleaks Configuration"
5+
6+
[extend]
7+
useDefault = true
8+
9+
# Allowlist for false positives
10+
[allowlist]
11+
description = "Allowlist for AP2 data key constants"
12+
13+
# AP2 data key patterns (namespace identifiers, not secrets)
14+
regexTarget = "match"
15+
regexes = [
16+
'''ap2\.(risk|mandates|types)\.[A-Za-z]+''',
17+
]
18+
19+
# Specific paths with data key constants
20+
paths = [
21+
'''samples/go/pkg/ap2/types/.*\.go''',
22+
'''src/ap2/types/.*\.py''',
23+
'''tests/test_.*\.py''',
24+
]
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
# Fiduciary Circuit Breaker (FCB) Extension
2+
3+
!!! info
4+
5+
This extension provides structured risk types for AP2 Section 7.4 (Risk Signals).
6+
7+
`v0.1-alpha` (see [roadmap](../roadmap.md))
8+
9+
## Overview
10+
11+
The **Fiduciary Circuit Breaker (FCB)** is a runtime governance pattern that complements AP2's mandate-based authorization. While mandates prove that an agent has authority to act, FCB monitors *how* the agent exercises that authority in real-time.
12+
13+
### Why FCB?
14+
15+
AP2 mandates validate authority at signing time:
16+
17+
- ✅ "Agent has a valid IntentMandate with $50,000 budget"
18+
- ✅ "This transaction is within the mandate constraints"
19+
20+
But mandates don't address runtime behaviors:
21+
22+
- ❌ "Agent already spent $30,000 today across 10 transactions"
23+
- ❌ "Agent is making purchases 3x faster than normal"
24+
- ❌ "Agent is buying from an unfamiliar vendor in a high-risk region"
25+
26+
FCB fills this gap by providing **cross-transaction behavioral monitoring** that can trip and require human intervention when something looks wrong.
27+
28+
## Conceptual Model
29+
30+
```text
31+
┌─────────────────────────────────────────────────────────────────────────────┐
32+
│ AGENT GOVERNANCE STACK │
33+
├─────────────────────────────────────────────────────────────────────────────┤
34+
│ │
35+
│ Layer 3: RUNTIME GOVERNANCE (FCB) │
36+
│ ───────────────────────────────── │
37+
│ Question: "Should this action proceed RIGHT NOW?" │
38+
│ Evaluates: Cumulative risk, velocity, anomalies, thresholds │
39+
│ Output: ALLOW / TRIP (escalate to human) │
40+
│ │
41+
│ Layer 2: PAYMENT AUTHORIZATION (AP2 Mandates) │
42+
│ ───────────────────────────────────────────── │
43+
│ Question: "Does agent have cryptographic proof of authority?" │
44+
│ Evaluates: User-signed mandates, intent constraints │
45+
│ Output: Valid credential / Reject │
46+
│ │
47+
│ Layer 1: AGENT IDENTITY & DISCOVERY │
48+
│ ──────────────────────────────────── │
49+
│ Question: "Is this agent authentic?" │
50+
│ Evaluates: Agent cards, trust registries │
51+
│ Output: Verified identity / Untrusted │
52+
│ │
53+
└─────────────────────────────────────────────────────────────────────────────┘
54+
```
55+
56+
## FCB States
57+
58+
The FCB operates as a state machine:
59+
60+
| State | Behavior | Entry Condition |
61+
| ----- | -------- | --------------- |
62+
| **CLOSED** | Normal operation. Agent acts autonomously. | Initial state; human approves from OPEN; or conditions met from HALF_OPEN |
63+
| **OPEN** | All actions blocked. Requires human review. | Any trip condition fails from CLOSED; or conditions violated from HALF_OPEN |
64+
| **HALF_OPEN** | Limited operations with enhanced monitoring. | Human approves with conditions from OPEN |
65+
| **TERMINATED** | Permanently halted. No recovery. | Human rejects from OPEN; or timeout |
66+
67+
### State Transitions
68+
69+
```text
70+
CLOSED ──[trip condition fails]──► OPEN
71+
▲ │
72+
│ ┌─────────────┼─────────────┐
73+
│ │ │ │
74+
│ [approve] [approve w/conditions] [reject]
75+
│ │ │ │
76+
│ │ ▼ ▼
77+
└────────────────────┘ HALF_OPEN TERMINATED
78+
79+
┌─────────┴─────────┐
80+
│ │
81+
[conditions met] [conditions violated]
82+
│ │
83+
▼ ▼
84+
CLOSED OPEN
85+
```
86+
87+
## Trip Conditions
88+
89+
Trip conditions are predicate functions that evaluate agent behavior:
90+
91+
| Type | Description | Example |
92+
| ---- | ----------- | ------- |
93+
| `VALUE_THRESHOLD` | Single transaction exceeds limit | Order > $100,000 |
94+
| `CUMULATIVE_THRESHOLD` | Running total exceeds threshold | Daily spend > $500,000 |
95+
| `VELOCITY` | Too many actions too quickly | > 10 transactions/minute |
96+
| `AUTHORITY_SCOPE` | Action outside delegated domain | Modifying payment account |
97+
| `ANOMALY` | ML model detects unusual pattern | Behavior inconsistent with baseline |
98+
| `TIME_BASED` | Action during restricted period | Trade outside market hours |
99+
| `DEVIATION` | Significant departure from baseline | Price 30% below historical average |
100+
| `VENDOR_TRUST` | Untrusted counterparty | New vendor in high-risk region |
101+
102+
## Usage in AP2 Messages
103+
104+
### Including RiskPayload in Messages
105+
106+
The `RiskPayload` can be attached to any AP2 message via the `risk_data` DataPart:
107+
108+
```json
109+
{
110+
"messageId": "msg_123",
111+
"parts": [
112+
{
113+
"kind": "data",
114+
"data": {
115+
"ap2.mandates.PaymentMandate": { ... },
116+
"ap2.risk.RiskPayload": {
117+
"fcb_evaluation": {
118+
"fcb_state": "CLOSED",
119+
"trips_evaluated": 8,
120+
"trips_triggered": 0,
121+
"trip_results": [
122+
{
123+
"condition_type": "VALUE_THRESHOLD",
124+
"status": "PASS",
125+
"threshold": 100000,
126+
"actual_value": 45000
127+
},
128+
{
129+
"condition_type": "CUMULATIVE_THRESHOLD",
130+
"status": "PASS",
131+
"threshold": 500000,
132+
"actual_value": 125000
133+
}
134+
],
135+
"risk_score": 0.15,
136+
"evaluated_at": "2026-02-03T14:30:00Z"
137+
},
138+
"agent_modality": "HUMAN_NOT_PRESENT",
139+
"agent_id": "agent_xyz",
140+
"agent_type": "B2B_BUYER",
141+
"session_id": "session_abc123",
142+
"cumulative_session_value": 125000,
143+
"transaction_count_today": 3
144+
}
145+
}
146+
}
147+
]
148+
}
149+
```
150+
151+
### FCB Trip with Human Escalation
152+
153+
When FCB trips, the `human_escalation` field captures the escalation flow:
154+
155+
```json
156+
{
157+
"ap2.risk.RiskPayload": {
158+
"fcb_evaluation": {
159+
"fcb_state": "HALF_OPEN",
160+
"previous_state": "OPEN",
161+
"trips_evaluated": 8,
162+
"trips_triggered": 2,
163+
"trip_results": [
164+
{
165+
"condition_type": "CUMULATIVE_THRESHOLD",
166+
"status": "FAIL",
167+
"threshold": 500000,
168+
"actual_value": 525000,
169+
"message": "Daily cumulative spend exceeds $500,000 limit"
170+
},
171+
{
172+
"condition_type": "VENDOR_TRUST",
173+
"status": "WARNING",
174+
"message": "New vendor not in approved registry"
175+
}
176+
],
177+
"risk_score": 0.72,
178+
"human_escalation": {
179+
"escalation_id": "esc_789",
180+
"triggered_at": "2026-02-03T14:30:00Z",
181+
"approver_id": "user_john_smith",
182+
"decision": "APPROVE_WITH_CONDITIONS",
183+
"decided_at": "2026-02-03T14:45:00Z",
184+
"conditions": [
185+
"Add vendor to approved registry",
186+
"Enhanced monitoring for 7 days"
187+
],
188+
"notes": "Approved given strong counterparty history"
189+
},
190+
"evaluated_at": "2026-02-03T14:30:00Z"
191+
},
192+
"agent_modality": "HUMAN_NOT_PRESENT"
193+
}
194+
}
195+
```
196+
197+
## Python Types
198+
199+
```python
200+
from ap2.types.risk import (
201+
RiskPayload,
202+
FCBEvaluation,
203+
FCBState,
204+
TripConditionResult,
205+
TripConditionType,
206+
TripConditionStatus,
207+
AgentModality,
208+
)
209+
210+
# Create an FCB evaluation
211+
evaluation = FCBEvaluation(
212+
fcb_state=FCBState.CLOSED,
213+
trips_evaluated=3,
214+
trips_triggered=0,
215+
trip_results=[
216+
TripConditionResult(
217+
condition_type=TripConditionType.VALUE_THRESHOLD,
218+
status=TripConditionStatus.PASS,
219+
threshold=100000,
220+
actual_value=45000,
221+
)
222+
],
223+
risk_score=0.15,
224+
)
225+
226+
# Create risk payload
227+
risk_payload = RiskPayload(
228+
fcb_evaluation=evaluation,
229+
agent_modality=AgentModality.HUMAN_NOT_PRESENT,
230+
agent_id="agent_xyz",
231+
session_id="session_abc123",
232+
)
233+
```
234+
235+
## Go Types
236+
237+
```go
238+
import "github.com/google-agentic-commerce/ap2/samples/go/pkg/ap2/types"
239+
240+
// Create an FCB evaluation
241+
evaluation := types.NewFCBEvaluation(types.FCBStateClosed)
242+
threshold := 100000.0
243+
actualValue := 45000.0
244+
riskScore := 0.15
245+
evaluation.AddTripResult(types.TripConditionResult{
246+
ConditionType: types.TripConditionValueThreshold,
247+
Status: types.TripConditionStatusPass,
248+
Threshold: &threshold,
249+
ActualValue: &actualValue,
250+
})
251+
evaluation.RiskScore = &riskScore
252+
253+
// Create risk payload
254+
riskPayload := types.NewRiskPayload(types.AgentModalityHumanNotPresent)
255+
riskPayload.FCBEvaluation = evaluation
256+
agentID := "agent_xyz"
257+
riskPayload.AgentID = &agentID
258+
```
259+
260+
## Benefits for Payment Ecosystem
261+
262+
### For Merchants
263+
264+
- Real-time visibility into agent behavior before accepting transaction
265+
- Ability to require higher security for risky transactions
266+
267+
### For Payment Networks
268+
269+
- Standardized risk signals for authorization decisions
270+
- Clear audit trail of FCB state and human approvals
271+
272+
### For Issuers
273+
274+
- Additional data points for fraud detection
275+
- Visibility into agent vs. human-initiated transactions
276+
277+
### For Users
278+
279+
- Confidence that agents operate within guardrails
280+
- Human oversight for exceptional cases
281+
282+
## References
283+
284+
- [AP2 Specification Section 7.4: Risk Signals](../specification.md#74-risk-signals)
285+
- [Circuit Breaker Pattern - Michael Nygard, Release It! (2007)](https://pragprog.com/titles/mnee2/release-it-second-edition/)

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ nav:
2424
- AP2 and x402: topics/ap2-and-x402.md
2525
- Privacy and Security: topics/privacy-and-security.md
2626
- Life of a Transaction: topics/life-of-a-transaction.md
27+
- Fiduciary Circuit Breaker: topics/fiduciary-circuit-breaker.md
2728
- AP2 specification: specification.md
2829
- A2A extension for AP2: a2a-extension.md
2930
- Glossary: glossary.md
@@ -143,6 +144,7 @@ plugins:
143144
- topics/ap2-and-x402.md
144145
- topics/privacy-and-security.md
145146
- topics/life-of-a-transaction.md
147+
- topics/fiduciary-circuit-breaker.md
146148
"Specification":
147149
- specification.md
148150
- a2a-extension.md

0 commit comments

Comments
 (0)