EngineeringJune 30, 20265 min read

We Don't Put a Classifier in the Decision Path

The best injection detectors are machine-learned models scoring above 97% F1. We use deterministic rules that score lower. That is a deliberate trade, and the reason is what an auditor can do with the answer.

The strongest prompt-injection detectors on the market are machine-learned classifiers, and the good ones are genuinely good. Published evaluations put the leaders above 97% F1 across public benchmark suites. That is a real number produced by real work, and a rules-based scanner will not match it.

obsvr's decision path contains no classifier at all. Thirteen deterministic rule types, regular expressions normalized for lookalike characters, allowlists, and threshold lookups. No second model sits between your call and the provider deciding whether the first model should be allowed to run.

That is a trade, and it is worth being precise about what is on each side of it, because the version where we pretend we win on every axis is not useful to anyone.

What we give up

Recall on novel phrasings. A classifier trained on tens of thousands of injection attempts generalizes to attacks it has never seen, because it learned a representation rather than a list. A regex catches what it was written to catch. Someone who rewrites a known payload in an unusual register may get past a pattern set and would not get past a well-trained model.

We say this in the SDK's own documentation rather than in a footnote: obsvr's prompt_injection rule is pattern-based, a useful signal and defense in depth, and it is not proof of prevention. If adversarial prompt detection is the only control you have, a dedicated detection product will do it better than we will.

What we get

Three things, and each one only exists because the decision is deterministic.

The decision is reproducible. Every enforcement event carries a hash of the exact ruleset that produced it. Hand that event to someone eight months later, give them the rules at that hash, and they get the same verdict on the same input, every time. A classifier's verdict is a function of weights that may have been retrained twice since. Asking "would this call be blocked today" and "was this call blocked correctly then" are different questions, and only one of those systems can answer the second one.

The decision is explainable in the way a regulator means it. EU AI Act Article 12 wants logs that allow traceability of a system's operation. In practice an auditor asks why one specific call was blocked. "Rule pii_ssn matched at offset 1,204, here is the rule, here is its hash, here is the version of the policy in force at that moment" is an answer. "The classifier scored it 0.87 against a threshold of 0.85" is a description of a number, and the follow-up question, why 0.87, has no answer anyone can produce. Not because the vendor is hiding it, but because the model does not contain one.

The decision is fast enough to be everywhere. A model in the decision path is either a network hop or a local inference pass, and both cost milliseconds. Deterministic rules cost microseconds. obsvr's full pipeline, rules and PII scan and quota and hooks and multi-turn injection and shadow rules, adds 45.1 microseconds at the median in TypeScript. That is the difference between a control you can afford on every single call and one you ration to the calls you already suspect.

These compose, and that is the actual answer

The framing where you pick a detector or a governance layer is wrong. They sit at different points and answer different questions.

Run a dedicated ML detector if adversarial input is your primary threat. It will out-detect us and we will say so. What it will not do is tell you which policy was in force when a decision was made, produce a record an auditor can verify without trusting the vendor, or reconstruct the exact model and ruleset behind a decision from eight months ago. Those are the questions obsvr exists to answer, and answering them requires the decision to be a thing you can re-run rather than a score you have to accept.

A detector tells you something is probably an attack. A governance layer tells you what your system did about it, under which rules, and proves the answer. Both are worth having. Only one of them can be audited.

The failure mode we were actually designing against

There is a second reason for determinism that has nothing to do with auditors, and it comes from watching how detection systems drift.

A scoring model has a threshold. The threshold is a number someone chose, and the score distribution it sits in moves whenever the model is retrained, whenever the input distribution shifts, and whenever a new class of payload appears. None of that movement is visible from the outside. The system keeps returning verdicts, the verdicts keep looking reasonable, and the relationship between "flagged" and "actually dangerous" quietly changes underneath.

The version of this failure that bites hardest is not even in the model. It is in the plumbing around it. It is common to find a validation library whose constructor defaults to raising on failure while some other code path assumes a silent no-op, so the effective posture depends on which route you took to get there. It is equally common to find a scanner with no error channel at all, where an exception simply propagates and becomes an unintentional fail-closed nobody chose. Neither is a bad detector. Both are cases where semantics drifted between layers and nobody noticed, because there was no single place where the behavior was declared.

That is the failure we designed against. Every detector class in obsvr declares its behavior explicitly, in one table per language, pinned by a shared cross-language fixture. A detector that ships without a declared failure disposition turns a test red rather than inheriting whatever the surrounding code happens to do. The point is not that our rules are cleverer. It is that there is exactly one place where the behavior is written down, and it cannot silently disagree with itself.

When we would tell you to use something else

If adversarial prompt detection is your primary threat and audit is secondary, buy a detector. Run it in front of us or beside us. Our pattern set is defense in depth and we describe it that way in our own documentation rather than in the small print.

If the question keeping you up is some version of "what did our AI actually do, under which rules, and can I prove it to someone who does not trust me," a detection score does not answer it and cannot be made to. That is the line, and it is not a marketing line: it falls out of the fact that one system produces a number and the other produces a reproducible decision.