What a machine reads before it buys
· Jithox engineering
We shipped a product, put it live, linked it from the catalogue, and listed it in the sitemap. A person could find it in two clicks. An agent could not find it at all. Nothing was broken, no test was red, and the gap survived a release review — because every check we had asked whether the page worked, and none asked whether a machine could discover that the page was for sale. This is what we found when we went looking, and what we changed.
Two audiences, two indexes
A human buyer arrives through a search engine, a link, or a homepage. The artefacts that serve them are HTML, a sitemap and a nav bar, and we test those.
An agent arrives differently. It reads a small number of machine-readable documents and decides from them what exists, what it costs, and how to call it. For us those are /llms.txt (what exists and where the canonical pages are) and /api/commerce/v1/status (what is on sale right now, derived from the same catalogue the meter charges from).
Our EU trade preflight product — one preflight over a shipment and its counterparty, composed from an import server and a sanctions server we already bill for — was in neither. It was reachable from /mcp in one click and listed in sitemap.xml. For a person, findable. For the buyer we actually built it for, invisible.
That is a distribution defect, not a copy defect, and it is worth naming the difference: a copy defect makes a page read badly, a distribution defect makes a working page unreachable for the audience it was built for.
Publishing a composition without inventing a product
The obvious fix is the wrong one. /api/commerce/v1/status has a products[] array, one entry per MCP endpoint, each carrying its own price and tool list where it is on sale. Dropping trade preflight in there would have made it a sixth server — with an endpoint that does not exist and a price nobody charges.
It is not a server. It is a journey composed of three tool calls across two servers that are already listed, already priced, and already metered. So it is published as a separate composed_offerings entry that says exactly that:
offering_idistrade-preflightandkindiscomposed_journey.composesnames the two servers it calls:eu-import-preflightandeu-sanctions-preflight.routepoints at the page a human or an agent starts from.max_cost_centsis100, the sum ofscreen_sanctioned_nameat 50,validate_eoriat 25 andcheck_eu_import_measuresat 25.idempotentisfalse, with a note saying a retried call is a new billable call.
An agent reading that learns three things it could not learn from the product list: that the route exists, that the ceiling is the sum of three per-tool prices it can verify independently, and that a retried call is a new billable call.
The number nobody writes down
max_cost_cents: 100 is not stored anywhere. It is summed at request time from the same catalogue the meter charges from, over the same check list the page runs. That matters more than it sounds.
The failure mode we were avoiding is specific. A published price that is restated rather than derived is correct on the day someone types it and silently wrong the first time the underlying price moves. Nothing fails loudly; the document simply starts describing a system that no longer exists, and the reader who trusted it budgets against a number the meter no longer honours.
Writing 100 into this new document by hand would have recreated exactly that, one level up from where prices live.
A reviewer then showed that summing from the catalogue was still not enough. It protects the price but not the set: add a fourth check to the product and the page offers and bills four while the document still publishes a three-check ceiling. An agent budgets one euro and is charged one twenty-five. So the check list is derived from the same table the page runs, and a test pins the published set against that table rather than merely iterating whatever gets emitted.
Availability is per check, not per product
The first version answered "is this buyable" with a single boolean over all three checks. The product page does not work that way — it filters per check, so with one server's pilot flag off it still sells the remaining checks with a real ceiling.
An all-or-nothing flag would therefore have told an agent that a route a human can buy from is dead. Now each check carries offerable, an unpriced check carries currency: null rather than "EUR" so it cannot read as sellable, and the ceiling covers only what is actually buyable today.
What we would tell another team
Three things we would have wanted written down before we started.
Test discoverability separately from function. Our suite proved the page rendered, the prices were right and the links resolved. Not one check asked whether the machine-readable index mentioned the page. Those are different properties and the second one has no natural place to fail.
Derive, never restate. Any number or list that appears in two places will disagree eventually. The question to ask of a published document is not "is this correct" but "what happens to this when the underlying thing changes". If the answer is "someone has to remember", it is already wrong.
A gate that has never failed has not been tested. Fourteen new checks passed and all fourteen failed against the previous commit, which felt like proof. It was not: a reviewer deleted a check from the published set and all fourteen stayed green, then replaced the computed total with a hardcoded 100 and all fourteen stayed green again — the anti-hardcoding check matched a code shape the file never used, and 100 happened to equal that day's sum. Running a suite against the old code proves it notices the change. It does not prove it would notice a regression. Those need separate evidence.
Verify any of this
Every claim above about the published documents is readable without an account. The claims about our own review process — which gates passed, which mutations survived — are not externally verifiable, and we would rather say so than imply otherwise.
curl https://jithox.com/llms.txtcurl https://jithox.com/api/commerce/v1/statuscurl https://jithox.com/api/pricing/v1
The worked sample at /trade-preflight runs synthetically with no signup, and shows the per-check prices and the ceiling before anything executes. If a number on this page and a number in those documents ever disagree, the documents describe what the system will actually do to your budget and this page is stale. Trust the documents.
Run this check on your own fleet
From nothing to a verified MCP call with a signed receipt — no card, no approval.