Engineering · 2026-06-05
Why our gateway rejects unclassified prompts
A gateway that guesses what kind of data it is handling turns compliance into model behavior. We prefer the stricter contract: the caller classifies the prompt, the gateway enforces the policy, and unclassified calls fail early.
The most tempting product requirement for a compliance-aware gateway is also one of the first we removed from Hermes: if the caller forgets to classify a prompt, infer the classification automatically and keep the request moving.
It sounds kind. The application team gets a forgiving interface. The end user does not see a failed request. The gateway feels helpful. The problem is that the system has quietly changed the question from is this request allowed to take this route? to did a probabilistic component guess the request's route-limiting facts correctly? That is not a trade we want in the middle of a jurisdictional decision.
Our rule is narrower. A prompt entering the gateway must arrive with an explicit classification. If it does not, the gateway rejects it before provider selection. The rejection is not an incident; it is an integration defect, and the calling application has enough local context to fix it.
There are three reasons for being this strict.
The caller knows the data flow. The gateway sees text and metadata. The application sees the workflow that produced them. It knows whether the prompt came from a customer-support transcript, an internal analyst note, a public documentation page, or a generated planning step. It knows whether the user is acting in a tenant-bound context, whether the data came from a regulated system, and whether the action is part of an approval chain. A classifier at the gateway boundary can see signals. The caller can know facts.
Classification is an audit claim. When a routing decision is questioned later, the useful answer is not the gateway thought this looked low-risk. The useful answer is this application emitted this classification under this schema version; this policy revision allowed these providers; this request went to this provider. The classification is part of the evidence chain. If the gateway invented it, the evidence chain now depends on a component whose behavior changes with prompts, examples, models, and thresholds.
Failure is safer than a default. The worst version of this system is a permissive fallback: if classification is absent, treat the prompt as ordinary traffic and route by quality or cost. A less obviously bad version is the opposite: if classification is absent, treat it as maximally sensitive. That preserves safety, but it hides broken integrations and produces mysterious cost or latency regressions. We want the brokenness to be visible at the boundary where it can be fixed.
In practice the request envelope carries a small classification block: schema version, origin, sensitivity, jurisdiction bucket, and handling constraints. The exact vocabulary is product documentation, not a blog post, but the behavior matters more than the names. The gateway validates that the block exists, that the schema version is supported, that the values are known, and that the combination is meaningful. Only then does it evaluate eligibility and optimize among eligible providers.
When validation fails, Hermes returns a typed error and records a minimal event: tenant, application, route name, schema version if present, and the reason the classification failed. It does not need to log the prompt body to diagnose a missing classification. The application team can graph those errors, add tests around them, and fix the caller. The compliance team can see that the gateway did not silently route an unclassified prompt.
This costs something. Application teams have to model their data flows. SDKs need types. Product flows that were previously "just send text to the model" need to carry a little more structure. During integration, requests fail for reasons that feel bureaucratic until the first audit review, when the same structure becomes the thing everyone is relieved to have.
We try to lower that cost without moving the decision back into the gateway. Typed SDKs make unclassified calls hard to construct. Local fixtures let application teams test classification without calling a model. A policy preview tool shows which providers a given tag set would allow. None of those tools guess the classification for production traffic.
The analogy we use internally is an authorization scope. A service may not call another service without a token that says what it is allowed to do. We do not ask the callee to infer the missing scope from the request body. We fail the call, fix the caller, and keep the boundary honest.
Prompt classification deserves the same treatment. A gateway can enforce policy, optimize routing, record evidence, and explain the decision it made. It should not pretend to know what the calling application forgot to say.

