# IRC-A in production, part 2: a 46-minute agent, an AI assistant that broke the rules — and a $0.04 bill

> Source: <https://dev.to/irc-a/irc-a-in-production-part-2-a-46-minute-agent-an-ai-assistant-that-broke-the-rules-and-a-004-2nm>
> Published: 2026-08-14 20:40:15+00:00

**It's 1:53 AM and I'm asking my CRM's chatbot: "what's the total amount we have parked in the Proposal stage?" Three seconds later it answers: $3,134.90. I follow up with just "and in prospecting?" — no context — and it breaks down the 10 open opportunities with amounts, close probability and estimated dates. A week earlier, this system was an n8n flow that only knew how to count contacts.**

This is the second part of the series about running [IRC-A](https://dev.to/irc-a/from-n8n-to-irc-a-a-week-migrating-a-real-project-and-a-679-token-bill-thats-hard-to-believe-3h3b) — my decentralized multi-agent protocol — in production. In part 1 I covered the week-long migration from n8n and the absurd 679-token bill. This time: a stopwatch experiment, the night the protocol defended itself from AI-written code, and a confession about one of the fixes I proudly showed you last time.

The trigger was a failure. I asked the system "how much did we sell in July?" — and the Gateway routed it to the *customers* agent, because semantically it was the closest thing registered. There was simply no sales domain in the network. (That false positive is why we're adding a configurable similarity threshold to `/discover`

.)

But instead of patching it, I saw the perfect experiment: **create a sales-reports specialist agent and plug it into the live system — with a stopwatch running.**

The results:

`curl`

from part 1.`.env`

file, an MCP refactoring that had silently broken the FastMCP instance-to-handler binding, and a regression of the classic "synchronous LLM call blocking Uvicorn's event loop" bug from part 1 (yes, the Pinger started deregistering the main agent again — same bug, twice; that's why the fix is moving into the SDK's base class, where it belongs).The moment of truth came at 11:19 PM: *"how much did we sell in July?"* → **"$3,259.70"**. Real data, from the real database, semantically routed through a network that didn't know that domain existed an hour earlier.

The hidden value of the experiment wasn't the 46 minutes — it's that adding a node is such a clean operation that **every weakness in the surrounding components becomes visible**. Extending the system is now the best integration test I have.

Here's the part I didn't expect to write. At some point, an AI coding assistant (Antigravity) modified one of the agents. Its change did two things the design explicitly forbids:

**1. The agent tried to build the call with its own parameters** instead of the ones the Gateway had signed into the DET. Result: rejected. The parameter lockdown isn't a convention — it's cryptographically enforced. If the authorized data doesn't match, the call doesn't execute.

**2. When that failed, the agent improvised an alternative endpoint** instead of using the URL the Gateway had returned. Here's the real, unedited log:

```
=== [INVOCACIÓN P2P AL MCP TOOL SERVER: guardar_contacto] ===
🔹 Endpoint: http://host.docker.internal:8003/tools
🔹 Payload: {"tool": "guardar_contacto", "arguments": {}, "delegated_token": "v4.public.eyJ..."}
🔹 HTTP Status: 500 → "Se requiere al menos un campo para crear el contacto"
=== fallback call ===
🔹 Endpoint: http://host.docker.internal:8003/mcp
🔹 Payload: {"jsonrpc":"2.0","method":"tools/call","params":{"name":"guardar_contacto","arguments":{}},"id":1}
🔹 HTTP Status: 404 → {"error":{"code":-32600,"message":"Session not found"}}
```

Read it closely: one external change violated **three invariants at once** — the route is the Gateway's authority, the DET is bound to its destination, and execution is stateless (the improvised `/mcp`

endpoint demanded an SSE session, which P2P calls don't have). And still, **the system degraded safely**: two informative rejections, zero unauthorized executions, zero data corruption.

And here's the scientific bonus: these incidents worked as an **involuntary penetration test**. The whitepaper *claimed* the DET makes it impossible to alter authorized data; the badly-written code *proved* it empirically. I reverted the change, the retest passed — and the invariant is now backed by evidence, not faith.

My takeaway: as more and more code is written by AI assistants that don't know your architecture, the controls can't live in documentation. They have to live in the inheritance of your SDK's base classes. *Secure by default* stops being a best practice and becomes a survival requirement.

Remember problem #2 from the previous article? The Gateway intermittently returned an empty `input_schema`

, and I "fixed" it with a `KNOWN_MCP_SCHEMAS`

fallback table hardcoded in the agent. I called it *defense in depth*.

It worked. And I've since torn it out, because it was **coupling in disguise**. An agent that needs to know tool schemas in advance isn't *discovering* capabilities — it has the network hardcoded, and every new tool would require touching every agent. The marginal cost of extending the system would stop being marginal.

The correct solution wasn't patching the agent — it was *returning to the pattern*. IRC-A already defines it: **the BFA returns the URL with the complete parameters plus the signed DET, so authorized data can't be changed.** The calling agent doesn't care about parameters at all; it transports intent and token. The extraction living in the agent was an implementation drift, not a protocol gap. Once again, the fix didn't require touching the protocol — it required going back to it.

Consolidated lesson: **the agent must not know anything the Gateway already knows.** Every redundancy of knowledge is coupling disguised as robustness.

With LangSmith wired in, that 2 AM validation session left hard figures (cumulative across *all* project testing, not just that night):

| Metric | Value |
|---|---|
| Executions | 333 runs, 0% errors |
| Latency per LLM call |
1.04s avg (p99 ≈ 2.9s) |
| Total tokens | 79,263 |
| Total cost | $0.04 |
| Most expensive single call | 5,462 tokens / 3.93s / $0.0025 (a full pipeline status report) |

In part 1 I bragged about a 679-token flow. This time, **the entire testing history of the project costs four cents.** A multi-agent network with vector-based semantic discovery and cryptographic signing per delegation costs between $0.0001 and $0.0025 per user query. The routing and security overhead is negligible next to the LLM cost. The paradigm's economic viability is no longer an assumption.

And the system that night wasn't just cheap — it was *conversational*: multi-turn context ("and in prospecting?" resolved from the previous turn), two specialists coexisting in one session, and a 101-opportunity pipeline summarized by stage on request. All in Spanish, against a CRM whose enums are in English (we found out "prospección" doesn't match `Prospecting`

— a few-shot prompt problem, not an architecture one; it's on the list).

The case-study logbook now holds **12 documented incidents. Zero attributable to the protocol.** In the two most severe ones, the protocol defended itself. The system went — in one migration week plus one afternoon of experimentation — from "an agent that counts contacts" to answering conversational business statistics at 2 AM, with a third specialist added in 46 minutes and zero changes to what was already running.

Still on the list: the configurable similarity threshold in `/discover`

, native framework telemetry (so I don't depend on an external platform), few-shots for CRM vocabulary, async-by-default enforced in the base classes, and fixing the root `input_schema`

serialization bug in the Gateway. Every item traces back to a documented incident — which is exactly how a framework should grow.

*How are you handling authorization between agents in your multi-agent setups — and has AI-generated code ever violated your architecture's invariants? Did your system notice? I'd love to hear about it in the comments.*
