The eight gates
Eight gates, in a fixed order. The order is a security property, not a style choice, and each position below is there for a stated reason.
| # | Gate | Decides |
|---|---|---|
| 1 | authenticate | Who is asking. |
| 2 | scope | Whether they may address this company at all. |
| 3 | halt | Whether the company is stopped. |
| 4 | entitlement | Whether the plan includes this structurally. |
| 5 | authorization | Whether this actor holds the capability. |
| 6 | consent | Whether the person being contacted allowed it. |
| 7 | policy | Whether company rules permit it. |
| 8 | budget | Whether there is money, and reserving it. |
Why the order is what it is
Scope denies with 404, never 403. A 403 confirms that something exists. For a wrong-tenant request that is an existence oracle: ask for a company id, learn from the status code whether it is real. A 404 says nothing.
Halt precedes entitlement and authorization. A halted company stops even for an owner. If halt came later, the most privileged actor would be the one the stop button worked least well against, which is exactly backwards.
Consent sits after authorization and before policy. After, so an actor without the capability cannot probe the consent ledger and turn the pipeline into an existence oracle over other people's contact details. Before, so no company-configured grant can authorize contacting someone who refused. Law outranks company policy.
Entitlement checks structure, budget checks money. Members, departments and features are counts, because a count is honest for them. Spend is money, because the cost of an action varies about nineteen times across the routing table and a count cannot bound it.
Budget is last because it reserves. Reservation is a side effect, and a side effect must only happen on an otherwise-allowed request.
What a decision returns
An AdmissionDecision carries the outcome and a trace: every gate, its verdict, and
why. The trace is generated from the decision rather than written by a model, so it
cannot describe a decision that did not happen.