3 days until MiCA enforcement. You deployed 5 agents. Discovery worked. You added 5 more. Discovery crashed the network.
This is the 10-node ceiling. Every team building multi-agent systems hits it. The A2A protocol provides a discovery mechanism (agent cards at /.well-known/agent-card.json), but it assumes agents poll peers independently. At 5 nodes, that is 20 discovery requests per cycle. At 10, it is 90. At 50, it is 2,450. The traffic grows quadratically while the useful work stays linear.
CockroachLabs documented this as the "thundering herd problem in agentic AI" in June 2026. Tianpan.co reported a 27% agent fatality rate when 11 agents started simultaneously and fought over shared resources. The arxiv paper on decentralized agentic discovery confirms: peer-to-peer discovery saturates bandwidth at scale, consuming up to 80% of network capacity in dense deployments.
The Discovery Storm Pattern
When agents use peer-to-peer discovery without coordination, they create a discovery storm:
# What happens when 20 agents use naive A2A peer discovery
import asyncio
import time
class NaiveA2ADiscovery:
"""Default A2A discovery: each agent polls every known peer."""
def __init__(self, agent_id: str, known_peers: list):
self.agent_id = agent_id
self.known_peers = known_peers
self.discovery_interval = 30 # seconds
async def discover_loop(self):
while True:
# Each agent fetches EVERY peer's agent card
for peer_url in self.known_peers:
await self.fetch_agent_card(peer_url)
await asyncio.sleep(self.discovery_interval)
async def fetch_agent_card(self, peer_url):
# GET /.well-known/agent-card.json for each peer
# At 20 agents: 20 * 19 = 380 requests per 30-second cycle
# At 50 agents: 50 * 49 = 2,450 requests per 30-second cycle
# At 100 agents: 100 * 99 = 9,900 requests per 30-second cycle
pass
# The math that kills your network:
def discovery_requests_per_cycle(n_agents: int) -> int:
return n_agents * (n_agents - 1) # O(n^2)
for n in [5, 10, 20, 50, 100]:
reqs = discovery_requests_per_cycle(n)
per_second = reqs / 30
print(f"{n:3d} agents: {reqs:,} requests/cycle, {per_second:.0f} req/s sustained")
# Output:
# 5 agents: 20 requests/cycle, 1 req/s sustained <- works fine
# 10 agents: 90 requests/cycle, 3 req/s sustained <- still OK
# 20 agents: 380 requests/cycle, 13 req/s sustained <- latency spikes
# 50 agents: 2,450 requests/cycle, 82 req/s sustained <- network saturation
# 100 agents: 9,900 requests/cycle, 330 req/s sustained <- system collapse
# And this is JUST discovery traffic.
# Actual task messages are on top of this.
# Under MiCA: every failed discovery = broken audit trail.
Why the 10-Node Ceiling Matters for MiCA
When discovery fails, agents cannot verify peer identity. Under MiCA Article 67, every cross-agent transaction requires verified counterparty identification. If Agent A cannot discover Agent B's current capabilities and identity attestation, the transaction either proceeds without verification (non-compliant) or halts (lost revenue).
The 10-node ceiling creates a regulatory cliff: your system works in staging (8 agents) and fails in production (15 agents). The failure mode is not a crash. It is degraded discovery that produces incomplete audit records.
Hub-Spoke with Federation: The Topology That Scales
The solution is not bigger pipes. It is a different topology. Instead of every agent discovering every peer, agents register with a managed routing layer that handles discovery centrally and pushes updates:
// MANAGED DISCOVERY: Hub-spoke with federation via rosud-call
import { RosudCall, RoutingRegistry } from 'rosud-call';
// Each agent registers ONCE with the routing registry
const agent = new RosudCall({
agentId: 'analytics-agent-eu-west',
network: 'base-mainnet',
discovery: {
// No peer polling. Registry pushes updates.
mode: 'managed',
registry: 'wss://registry.rosud.com/v1',
// Agent declares its capabilities (like an agent card, but push-based)
capabilities: ['financial-analysis', 'eurc-liquidity', 'mica-reporting'],
// Regions for federated routing (MiCA jurisdiction awareness)
regions: ['eu-west', 'eu-central'],
// Payment requirements (x402 v2 compatible)
pricing: { creditsPerRequest: 3, paymentType: 'fixed' }
}
});
// Discovery is now O(1) per agent, not O(n)
// Agent asks registry: "Who can do financial-analysis in eu-west?"
const peers = await agent.discoverByCapability({
capability: 'financial-analysis',
region: 'eu-west',
minTrustLevel: 'verified' // MiCA: counterparty must be identified
});
// Registry response is instant (cached, push-updated)
// No polling storm. No quadratic traffic. No 10-node ceiling.
console.log(`Found ${peers.length} verified peers`); // Works at 10, 100, or 1000
// When a peer goes offline or updates capabilities:
agent.on('peer-update', (event) => {
// Push notification, not poll discovery
// Audit record automatically includes peer status changes
console.log(`${event.peerId} status: ${event.status}`);
});
// Federated routing for cross-region MiCA compliance:
const crossBorderPeer = await agent.discoverByCapability({
capability: 'mica-reporting',
region: 'eu-central', // Different jurisdiction
requireMiCAAuth: true // Must have MiCA authorization
});
// Registry verifies MiCA status before returning peer
// Non-authorized peers never appear in discovery results
Dead-Letter Queues: When Messages Cannot Be Delivered
Discovery storms do not just cause latency. They cause message loss. When Agent A sends a task to Agent B but B is overwhelmed by discovery traffic, the message times out. In a naive implementation, that message is gone. The task silently fails.
Production messaging infrastructure needs dead-letter queues for undeliverable messages:
// Message delivery with dead-letter queue via rosud-call
const channel = new RosudCall({
agentId: 'orchestrator-prod',
network: 'base-mainnet',
messaging: {
delivery: {
maxRetries: 3,
retryBackoff: 'exponential', // 1s, 2s, 4s (not thundering herd)
jitter: true, // Prevents synchronized retries
timeout: 5000 // 5s per attempt
},
deadLetter: {
enabled: true,
retention: '72h',
alertAfter: 3, // Alert if 3+ messages dead-lettered
replayable: true // Can retry dead-lettered messages later
}
}
});
// Send a paid task to a peer
const result = await channel.sendTask({
to: 'analytics-agent-eu-west',
message: { parts: [{ kind: 'text', text: 'Generate MiCA D-3 compliance snapshot' }] },
payment: { amount: '0.50', token: 'USDC' }
});
// If delivery fails after retries:
// 1. Message moves to dead-letter queue (not lost)
// 2. Payment is NOT settled (funds safe)
// 3. Alert fires to orchestrator
// 4. Audit record shows: attempted, failed, queued, reason
// 5. MiCA compliance: complete lifecycle even for failed transactions
channel.on('dead-letter', (msg) => {
console.log(`Message ${msg.id} dead-lettered: ${msg.reason}`);
// reason: 'peer_unreachable' | 'timeout' | 'peer_rejected' | 'payment_failed'
// All reasons are machine-readable for MiCA Article 67 reporting
});
The Topology Comparison
| Metric | Peer-to-Peer (A2A default) | Hub-Spoke Managed (rosud-call) |
|---|---|---|
| Discovery traffic | O(n^2) | O(n) |
| 10-node ceiling | Yes | No |
| Thundering herd risk | High | Eliminated (jitter + push) |
| Message loss on overload | Silent | Dead-letter queue + replay |
| MiCA audit completeness | Gaps during storms | Complete (even for failures) |
| Cross-region routing | Manual | Federated with jurisdiction |
The Bottom Line
The A2A protocol is a discovery specification. It is not a discovery infrastructure. The specification says "fetch /.well-known/agent-card.json." It does not say how to do that at scale without creating a quadratic traffic storm that kills your network at 10 agents.
rosud-call replaces peer-to-peer polling with managed push-based routing. Discovery is O(n), not O(n^2). Messages that cannot be delivered go to a dead-letter queue, not into the void. And every state transition, successful or failed, produces a MiCA-compliant audit record.
3 days until MiCA enforcement. Your staging environment has 8 agents and discovery works. Your production target is 30. Do the math: 30 * 29 = 870 discovery requests per cycle. Your network will not survive it.
Scale agent messaging beyond 10 nodes: rosud.com/rosud-call
Top comments (0)