August 19, 2026 · Iris, Growth @ minia2a.uk
For most of this year our documentation told agents to append ?trial=1 to an endpoint to
get a free call. The parameter does nothing. Not "does something subtle" — nothing. On a bucket with
calls left, the response with it and the response without it are identical, and both decrement the same
counter. On an exhausted bucket, both return the same 402.
It appeared in 209 places across 29 files: curl examples, Python snippets, a JS click handler, button labels, and — worst — the success body of the registration endpoint itself, which is the one instruction an agent receives at the exact moment it is most willing to act.
Nothing was ever broken by it. That is precisely why it survived 209 copies.
A human skims ?trial=1, ignores it, and moves on. An agent does something else: it builds a
model in which the parameter is the mechanism. Two failure modes follow, and neither shows up in
any error log of ours.
In a product whose readers are machines, documentation is not marketing collateral sitting next to the interface. It is part of the interface. Wrong text is a contract violation with a delay.
Our free allowance is 15 calls per identity — one bucket per IP (and a second one per registered wallet), shared across the entire catalog. Spend all fifteen on a single service or one call each on fifteen different services; it is the same counter.
Twenty-eight surfaces said something different: "15 free trial calls per endpoint." With 1,661 services listed, that phrasing promises roughly 1,661 times what exists. It was on a landing page, in a dozen posts, in a discovery record that external indexers read — and in the skill manifest, which is the first sentence an agent sees after installing our tooling.
The design is deliberate and worth stating plainly, because "15 total" reads stingy until you see the alternative: per-endpoint trials would let anyone farm an entire catalog for free, forever, one endpoint at a time. A shared allowance is what keeps the trial honest — enough to evaluate, not enough to operate on. The failure wasn't the policy. It was that we described it wrong in twenty-eight places.
Our own free-tier landing page advertised 239 endpoints and 6,400+ trials served. Live, those figures are 468 and 21,641. The page had the markup for live values and had never loaded the component that fills them, so it had been frozen since the day someone typed it — understating the product by 3x while a different page overstated the catalog. Both directions, same root cause.
| Claim on the page | Reality, measured | Direction |
|---|---|---|
?trial=1 gives you a free call | No-op; trials are automatic | phantom mechanism |
| 15 free calls per endpoint | 15 per identity, whole catalog | 1,661x over |
| 239 endpoints, 6,400+ trials | 468 endpoints, 21,641 trials | 3x under |
Three mechanisms, in increasing order of how much they've saved us.
We run a check that treats each published document as a contract: required tokens must be present, retired ones must be absent, and the canonical payload from the docs is POSTed with a deliberately invalid signature — reaching "signature verification failed" proves every schema requirement in the docs is still satisfied, while creating nothing. Seventeen checks, run on a schedule. A doc that drifts back to a dead route now fails out loud instead of quietly costing somebody an afternoon.
Every count in prose is either bound to a live value or it is a lie with a timer on it. Ours are rewritten from the stats endpoint on page load, with the baked fallback refreshed by script so crawlers and no-JS readers see today's number too. The checker verifies those fallbacks — 82 of them at last run — against live within a tolerance, so a frozen one is a failure, not a stale detail nobody notices.
Cleaning up prose at scale means pattern-matching prose at scale, and patterns are confidently wrong. The rule we wrote to fix "11,200+ free trials" matched a different line — "15 free trials per IP" — and proposed to rewrite our allowance into our lifetime total. It was caught because the tool prints what it would do before it does it, and because somebody read the list. The regex now requires a thousands separator. Every string replacement in that sweep also asserted it matched exactly once, and every edited page was re-checked for tag balance and re-fetched from production afterward.
None of this was written by an adversary. We wrote all of it, in good faith, and each line was true on the day it was typed. Documentation drift isn't a discipline problem; it's what happens when a fast-moving system meets prose that has no test suite. The fix isn't "be more careful." It's to make the docs observable — and then to look.
Our current numbers, live as you read this: 1,661 services · 21,641 free trials served · 843K requests. The machine-readable specs are AGENTS.md and llms.txt; if you find a line in either that doesn't match what the gateway actually does, that's a bug and we want it.