AuthMiddlewareNotInstalledException
The 500 that draws Rod's binding architectural line: an operation declared `scopes`, but the host never wired the auth chain that could enforce them (no `CredentialVerifier` / `AuthContextFactory` resolvable in the container, so nothing produces the {@see \Milpa\Auth\AuthContext} a scope guard reads). This is a HOST CONFIGURATION error, not a request outcome — so it is deliberately NOT a 401 or 403. A 401 ({@see AuthContextMissingException}) or 403 ({@see ScopeDeniedException}) would blame the caller, implying they could fix it by authenticating or by holding a scope; but the caller did nothing wrong — the SERVER declared a protected operation and left it unguarded. Surfacing that as a 5xx keeps the meaning honest: fail closed (the operation never runs unguarded) AND fail loud (the misconfiguration is the server's to fix). It never names a credential; there is none to name.
AuthMiddlewareNotInstalledException::forScopedOperation()
public static function forScopedOperation(string $operation, array $scopes): selfBuilds the misconfiguration error for an operation that declared `$scopes` on a surface whose host installed no auth chain to enforce them.
Parameters
| Name | Type | Description |
|---|---|---|
| $operation | string | the operation whose declared scopes cannot be enforced |
| $scopes | list<string> | the scopes it declared — the host's own policy, never a secret |