The classifier will sometimes not know. Somebody sends something that fits no concept, or fits three equally, or is four words long. The system has to do something, and there are two obvious answers.
Fail closed. Refuse what you cannot categorise. Safe, defensible, and it means a typo in a prompt becomes an outage for whoever sent it.
Fail open. Route it somewhere sensible and carry on.
We fail open. CON-fail-open-on-classification says an unclassifiable request
goes to the default concept and is logged for taxonomy review. That is the easy
half of the decision.
The word that does the damage
"Fail open" has two readings, and only one of them is right.
The first: unclassified. We do not know which concept this is, so treat it as the default one — with the default concept's constraints, capabilities and policy row, all of which apply exactly as they would to anything else.
The second: unconstrained. We do not know what this is, so let it through.
The second reading is how a fail-open policy turns into a hole. Nobody writes
if unknown: skip_filters(). What happens is subtler: the unclassified path
becomes a special case, the special case is written by someone thinking about
availability rather than about residency, and a request nobody could categorise
ends up reaching a model that a categorised request could not.
Which means "I could not tell what this was" becomes a way to get past the constraints — and an attacker does not need to guess that; they only need to send something ambiguous.
What holds it
general.assist is a concept like any other. It has a policy row, a candidate
list and an objective. Falling back to it is not falling out of the system, it
is landing in a normal part of it.
And the filters run afterwards, on that concept's constraints. If the request
also carried x-fife-critical, residency still pins to in_infra and the
vendor models are still eliminated — because criticality is a property of the
request, not of the classification, and it did not become less true when the
classifier shrugged.
The test is named for the distinction:
tests/router/test_router.py::TestFailOpen
::test_failing_open_does_not_mean_failing_unconstrained
It exists because the two meanings are one careless sentence apart, and the sentence is in the constraint document, which is exactly where somebody implementing this would read it and take the wrong half.
The record, and why it matters more than the routing
Every fall-through is logged for taxonomy review. Not as an error — nothing failed — but as the signal that a category is missing.
That log is the input to the only mechanism that fixes this properly. A steady trickle of unclassifiable requests that all look alike is a concept nobody has written yet, and the fix is a file with a description and four exemplars, not a better classifier.
Without the log you get a system that is quietly correct: it routes the ambiguous traffic somewhere reasonable, forever, and nobody ever discovers that 15% of requests were a category the taxonomy should have had.
The general shape
This is the same trade as a 404 that leaks whether a resource exists, or a retry that turns a transient failure into a duplicate charge. The behaviour everyone agrees on — do not error, degrade gracefully — has a second half that nobody states, and the second half is where the bug lives.
Degrade gracefully into what. If the answer is "into a path with fewer rules", the graceful degradation is a bypass with better manners.