From 81bdf8df568fde6d5122ed472b86407d89c29564 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 26 Sep 2026 15:10:26 +0200 Subject: [PATCH] ADR 0115 (proposed): a route may state the largest request body it carries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- ...5-a-route-may-limit-the-body-it-carries.md | 81 +++++++++++++++++++ 02-DECISIONS/README.md | 1 + 2 files changed, 82 insertions(+) create mode 100644 02-DECISIONS/0115-a-route-may-limit-the-body-it-carries.md diff --git a/02-DECISIONS/0115-a-route-may-limit-the-body-it-carries.md b/02-DECISIONS/0115-a-route-may-limit-the-body-it-carries.md new file mode 100644 index 0000000..53f1763 --- /dev/null +++ b/02-DECISIONS/0115-a-route-may-limit-the-body-it-carries.md @@ -0,0 +1,81 @@ +--- +topic: the tiers +status: proposed +date: 2026-09-26 +deciders: jochen +reconstructed: false +extends: 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](0108-a-route-carries-the-policy-applied-to-a-request.md) 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. diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index 6b46026..505932f 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -125,6 +125,7 @@ python3 00-META/checks/index.py fail if stale - **0098** — [A fact a provider makes at first start is fetched from it, not carried in its manifest](0098-a-fact-a-provider-makes-at-first-start-is-fetched-from-it.md) - **0108** — [A route carries the policy applied to a request, and names a secret rather than holding one](0108-a-route-carries-the-policy-applied-to-a-request.md) - **0109** — [A package registry seat is one per ecosystem, not one for all of them](0109-a-package-registry-seat-is-one-per-ecosystem.md) +- **0115** — [A route may state the largest request body it carries, which is the fifth policy](0115-a-route-may-limit-the-body-it-carries.md) *(proposed)* ### What runs on them, and how it gets there -- 2.54.0