ADR 0108 closed the policy set at four and priced a fifth: earned by a dependent that exists. The registry's public door is one. A registry takes layers in single requests of gigabytes, the predecessor served that name with a body-size middleware, and without one the proxy refuses the push at its own default before the registry sees it — so a public name that cannot state its limit is a public name nothing can be pushed to. Rejects the cheap merge deliberately: the implementation waiting on feat/registry-public-route could carry the limit beside certificate verification as a transport detail, but a body limit refuses requests, and a closed set with an exception written next to it is not a closed set.
4.2 KiB
topic, status, date, deciders, reconstructed, extends
| topic | status | date | deciders | reconstructed | extends |
|---|---|---|---|---|---|
| the tiers | proposed | 2026-09-26 | jochen | false | 02-DECISIONS/0108-a-route-carries-the-policy-applied-to-a-request.md |
115. A route may state the largest request body it carries, which is the fifth policy
Context
ADR 0108 closed the set of route policies at four — authentication, refusal scoped to a path, path-scoped routing with priority, redirect — and said what a fifth would cost: "A fifth is an amendment to this record, deliberately — each addition should be earned by a dependent that exists."
The dependent exists, and it is the registry's public door. The artifact store is reached by two names: one inside the private network, and one the world can push to. A registry takes image layers in single requests of gigabytes. The predecessor served the registry's public name with exactly a body-size middleware in front of it, because without one the proxy refuses the push at its own default long before the registry sees it. So a public name for the registry that cannot state its limit is a public name nothing can be pushed to — the route would be written, reported as served, and fail on first use.
Nothing in the four covers it. Refusal scoped to a path refuses by where a request arrives, not by how large it is, and the two are not substitutes: the registry's push path is the path that must work.
An implementation of this exists, written before the policy set was closed, on a branch in the
controller and the catalogue (feat/registry-public-route). It cannot merge as written — it predates
0108 and builds on the routing table 0108 replaced — and it is what this record would let be ported.
Decision
A route contribution may state the largest request body it carries, in bytes. It is the fifth policy, and the set is closed at five.
Absent means no limit, which is what every route gets today: the mesh's own proxy has never limited a body, and a default arriving with the field would change every route that never asked for one.
A value that is not a whole positive number of bytes is refused when the contribution is read — named, with the module and the route, like a port that is not a port. It is not rounded, and it is not dropped.
A limit the proxy cannot express is a route that is not written. Writing the route without its limit would carry exactly what the module said not to carry, and report success; that is the failure mode 0108 exists to prevent, arriving one field later.
The limit is enforced in front of the workload, so an oversized request is refused by the proxy with the proxy's own answer, and the workload never sees it.
Options rejected
A single limit configured on the proxy. One number for every route: large enough for the registry means large enough for every admin surface behind the same proxy, and small enough for those means the registry cannot be pushed to. The value belongs to the route, which is the thing that knows.
Carrying it outside the policy set, as a transport detail beside certificate verification. This works, and it is how the existing implementation would most cheaply be merged. It is rejected because a body limit refuses requests, and 0108 exists to put every request-refusing behaviour in the record that says where such behaviours live. A closed set with an exception written next to it is not a closed set, and the next reader has no way to know the exception is there.
Leaving the registry's public name on the adopted ingress. It defers the problem at the cost of keeping the predecessor's proxy alive for exactly one route, which is the standing exception 0108 was written to end.
Consequences
The set is closed at five, and the same terms apply to a sixth. This record's own precedent is that an addition needs a dependent that already exists, not one that might.
Every provider of route must understand one more key, which is the cost 0108 already named for
the four and accepts again here.
The contribution's vocabulary becomes checkable in one more place, which is worth stating because a limit that is silently ignored is worse than no limit: the push fails at the proxy, and the module's manifest says it should not have.