This content reflects minia2a as of its publication date and is kept for the record. Current model: x402 pay-per-call in USDC on Base only, 5 free trial calls per signed wallet, no credits and no top-up rail.
The Discovery Manifest Pays for Its Routes Twice
2026-10-17 · by minia2a
A discovery document is the first thing an agent fetches and the last thing anyone measures. It is small enough that the size never shows up in a budget, and the fields are plausible enough that nobody asks which ones are normative. We measured ours three ways and found that the same 75 routes are published twice.
The document
Our /.well-known/x402 manifest, generated 2026-10-16T05:19:01Z, is a single JSON object with 75 monetized routes. Two arrays describe those routes:
- resources[] — 75 entries of {url, method, description}, the x402-shaped enumeration.
- endpoints[] — 75 entries of {id, name, description, price, category, url}, a catalog projection for non-x402 consumers.
Same route set, two projections. The document also carries root metadata (name, description, stats, register, probe, openapi, and so on) and a pointer to the full catalog. The two arrays are what scale with N.
The measurement
Method: fetch the served bytes, parse, re-serialise with json.dumps(d, indent=2) plus one trailing newline, and compress with gzip.compress(..., 9). That serialisation reproduces the served document exactly (35,315 B), so the rows below describe one document, not four variants.
| portion | raw | gzip -9 | ratio |
|---|---|---|---|
| whole document | 35,315 B | 5,741 B | 6.15x |
| resources | 11,188 B | 3,043 B | 3.68x |
| endpoints | 15,990 B | 4,077 B | 3.92x |
| single enumeration (drop endpoints[]) | 15,150 B | 3,739 B | 4.05x |
−57.1% raw · −34.9% compressed
35,315 → 15,150 B raw; 5,741 → 3,739 B gzip -9, by removing the duplicate route enumeration and keeping the pointer to the full catalog. Nothing else changed.
Two numbers decide how this should be read.
The per-array ratio is what the spec should use. The whole document compresses at 6.15x, but most of that comes from the shared root metadata: it is one copy of a handful of long strings. The parts that scale with N get 3.68–3.92x, because a route's URL and description are unique high-entropy strings that gzip cannot fold into a previous route. A budget derived from the 6.15x figure will be wrong at every larger N.
The duplicate is 77% of the raw document. 11,188 + 15,990 = 27,178 B, against 35,315 B total. Removing the second projection does not save 15,990 compressed bytes — the two arrays share dictionary material, so the actual compressed saving is 2,002 B. That is still a third of the wire weight, and it is the difference between O(2N) and O(N) for any host that publishes both shapes.
Two costs that a raw-byte budget hides
Pretty-printing is almost free on the wire. The compact form is 28,200 B and 5,582 B gzip; the indented form is 35,315 B and 5,741 B. So 7,115 raw bytes cost 159 compressed bytes. If the budget is stated in raw bytes, a host pays a 25% penalty for whitespace that does not exist in transit.
The encoding name matters too. We measured the same body at the edge with different Accept-Encoding headers:
| request | bytes on the wire |
|---|---|
| Accept-Encoding: gzip | 5,714 B |
| Accept-Encoding: br | 6,035 B |
Brotli is larger than gzip here. That is not an argument against brotli; it is an argument against writing a budget as ≤ 64KB under gzip / br and treating the two as interchangeable. A host passes under one encoding and fails under the other, and the only number that exists for a given agent is the one its client received.
What this changes in practice
- Name one normative enumeration. If resources[] is normative, a second full projection is a cache of it. Derived or served at its own URI is fine; repeated inside the same document is double-billing every reader.
- Budget compressed bytes, per encoding. The transport cost is the encoded body. State which encoding the ceiling is measured under, or measure the one delivered.
- Derive per-entry constants from the array, not the document. The whole-document ratio flatters the number at small N and misleads at large N.
- Keep a pointer. Dropping the duplicate does not drop the capability: the document already carried endpointsUrl and endpointsCount. A consumer that wants the richer projection fetches it once and caches it.
We have not deployed the single-enumeration form yet. The manifest is written by a daily sync script rather than served straight from the gateway, but two guards assert that resources[] and endpoints[] agree url-for-url, so the change is a writer plus those guards — not a one-line deletion. The measurement above is the served bytes with endpoints[] removed and nothing else touched, which is what isolates the effect.
If you publish a discovery document, the check is one command and it does not need our endpoint: serialise the document, compress it at level 9, then remove each array in turn and compress again. The arrays that scale with N will tell you their own price. If the same set appears twice, you are paying for it twice.
Method note: every size above is a measurement on 2026-10-17 of the document served at https://minia2a.uk/.well-known/x402 (generated 2026-10-16T05:19:01Z). Raw sizes are UTF-8 bytes; compressed sizes are Python's gzip.compress(data, 9). Wire sizes are curl's size_download for the same URL with Accept-Encoding: gzip and br. Percentages are computed against the served document, not against a compact re-serialisation.
Originally published at minia2a.uk.
Top comments (0)