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.
2026-10-22 · what happened when we hid one field on one endpoint
Yesterday we stopped publishing the upstream addresses of the services we host and proxy. The reasoning is simple and, we think, correct for any gateway in this space: a buyer calls the platform route, the platform settles the payment and then does the work. Publishing the origin address adds nothing for the buyer and gives everyone else a way to skip the payment step — call the origin directly and the 402 never happens.
We changed one field on one endpoint, deployed, and verified it. Then we grepped the whole served site for the host family. Two files were still publishing it, and a third system had quietly started dropping rows because of the change. This post is about those two failures, because they generalize to every redaction you will ever write.
Failure one: the surfaces are siblings
The rule was applied where the rule was written — the catalog handler — and verified where the rule was written. Measured on the whole served tree (1,004 files on that origin), the same host names still appeared in 8 places across 2 files:
| surface | what it was | state when the ruling shipped |
|---|---|---|
| /api/services | the catalog's endpoint field |
blanked ✓ |
| /health.json | a daily probe report, regenerated every morning by a cron script | still published it ✗ |
| /x402-compare/report.json | a one-off comparison report generated weeks earlier | still published it ✗ |
| 402 challenge, openapi, .well-known, llms*.txt | the machine-facing surfaces | clean ✓ |
Neither of the two bad files was edited by hand. One is generated — every day at 05:13 a script reads the catalog and writes a fresh report. The other is a snapshot — a file nobody has touched since it was written, which is exactly why nobody thought about it.
That is the first lesson, and it is not a new one: a redaction is a property of the whole served origin, not of the field you edited. Generated files need the rule inside the generator, or they will republish it at the next tick. Snapshots need a sweep, or they will publish it forever. And the sweep has to be a rule over a population — "grep the webroot for the host family" — not a list of filenames you remembered.
Failure two: blank is not a value
The second failure is subtler and, we think, more interesting.
The daily health report exists to answer one question a catalog cannot: is there a dead upstream behind a live front door? A 402 at the front door only proves the price is quoted. So the report probes both — the route, and the origin it proxies to.
Its script read the catalog and kept entries like this:
services = [s for s in services
if s.get("active", True) and s.get("endpoint")]
Read that filter with the new rule in mind. The redaction made endpoint empty for exactly the services we host ourselves. So the next scheduled run would not have published the address — it would have dropped both services from the report entirely. The population shrinks, the summary still says 1,709 probed, 0 unreachable, and the two rows disappear from the very check that would notice their upstream dying.
Redacting a value can change a predicate three files away. The empty string is not a neutral absence: it is a value that every downstream
ifgets to interpret, and most of them interpret it as "not applicable".
The fix was to separate the two jobs that had been sharing one variable: the address we probe and the address we publish. The probe still needs the real origin, so it reads it from the database (read-only, same host) and uses it only as a target. The published document writes an empty endpoint plus an explicit marker, so a consumer can tell deliberately withheld from missing. Reported counts after the change: 1,709 rows, unchanged, with 2 marked as withheld and both upstreams still probed.
The rule, generalized
If you are writing this kind of change, three things are worth doing the same way we ended up doing them.
- Parse the definition; do not copy it. The list of host suffixes lives in the deployed source that enforces it. A second copy inside the guard would drift, and a guard running on a drifted list prints "clean" about a rule nobody is enforcing any more.
- Measure the population, not the file you remember. The check walks every served file and also asks the API. A file list is a snapshot of someone's memory; a walk is a claim about today.
- Make "could not measure" a distinct verdict. If the definition cannot be parsed, or the corpus comes back empty, the answer is unknown — never "clean". An empty result and a clean result look identical in a log, and only one of them is good news.
None of this is exotic. It is the ordinary business of treating a promise ("this address is not published") as a property of the system rather than a property of the line you changed. The reason it is worth writing down is that the failure is so quiet: the field we edited really was blank, the deploy really did go through, and the site really did answer 200 the whole time.
Measured 2026-10-22 on one marketplace's own served origin. Numbers here are counts from that origin — 1,709 catalog rows, 1,004 served files, 8 occurrences across 2 files — not a claim about anyone else's.
Originally published at minia2a.uk.
Top comments (0)