Every JSON door applies the same body gate, and reports its refusals
A caller should not have to learn which endpoint bounds its input. Every door that takes a JSON body applies the same limits and gives the same answer when they are exceeded.
The rule
- Every door that accepts a JSON request body applies the same body gate: the same size, depth and top-level shape limits, refused the same way.
- A refusal from that gate reaches the caller as the 400 it is; an implementation must not report it as a server error.
- Where a body is optional, its absence is mapped to an empty object ahead of the gate and everything else goes through the gate; optional never means unvalidated.
What it means
A door is any route that takes a JSON request body. The gate is the check every such door runs before it reads a single field: is the body present, is it within the size bound, does it nest no deeper than the depth bound, is it JSON at all, and is its top level a shape the door can work with. The rule does not fix the bounds; it fixes that there is one gate, that every door runs the same one, and that an implementation cannot make an exception for one route because that route "never gets big bodies".
Two consequences carry most of the weight.
A gate refusal is a 400, never a 500. The gate refuses because of what the caller sent, so the answer is the caller's to act on. An implementation that lets the refusal fall through a general failure handler and surface as a server error has told the caller the wrong thing, and made the two indistinguishable. API-7 says why that matters in general; this rule is the specific case where the door already knows the answer.
Optional is a statement about presence, not about checking. Where a door's
body is optional, an absent body is read as {} before the gate, and the gate
then runs on that. A body that is present goes through the gate whether or not
the door needed it. So a malformed body on an optional-body door is refused, not
quietly treated as absent.
Example
The same three bodies, sent to any JSON door, get the same three answers. The gate answers before any workflow-level meaning is read, so the door's own rules never see the first two.
POST /api/flowdrop/workflows
{"name":POST /api/flowdrop/workflows
"just a string"POST /api/flowdrop/workflows
{"name": "WF"}Whatever the door refuses from here on (STORE-2, say) is a workflow-level refusal, and the gate has nothing further to say.