Detector Runtime Contract
Detection modes, guarantees, fallback behavior, quality expectations, and how to verify the runtime configuration
Detection Modes
OGuardAI operates in one of three detection modes, configured in oguardai.yaml:
Mode: builtin (Deterministic)
detector:
mode: builtinGuarantees:
- Builtin detection in low single-digit ms (indicative, hardware-dependent)
- Builtin entity types: the named formats plus the always-on builtin_custom detectors, detected via the regex registry
- Zero external dependencies
- Deterministic: same input always produces same output
- Horizontally scalable, no shared state
Named builtin entity types: email, phone, ssn, iban, vat_id, credit_card, ip, url, order, customer_id, passport, health_id, date_of_birth, address
Always-on builtin_custom detectors:
money (ISO 4217 currency amounts), de_tax_id (German tax ID), de_sozialversicherung (German social security), quote_id (quote/offer IDs), case_ref (case references). These emit typed custom:<name> entities and run in every mode, including builtin. Source: crates/core/src/types.rs BUILTIN_CUSTOM_NAMES, registered in detector-builtins.
NOT available (requires NER): person, company, location
Mode: both (Full Coverage)
detector:
mode: both
advanced_url: http://localhost:9090Guarantees:
- The builtin entity types (named + builtin_custom) plus the NER-only types person, company, and location
- Person names, company names, locations detected via GLiNER/spaCy
- Graceful fallback: if NER sidecar is unreachable,
bothmode falls back to builtin-only - Fallback timeout: configurable (
detector.timeout_secs)
Additional entity types: person, company, location
Latency (indicative, not guaranteed):
- Builtin entities: ~1-2ms
- NER entities: ~80ms p50, up to several hundred ms p99, depending on hardware, text length, and model
Fallback behavior when NER is unavailable:
- Server logs:
ner_service_unavailable_falling_back_to_builtin - Detection continues with builtin regex only
- person/company/location will NOT be detected
- Health endpoint shows:
builtin_and_ner (full entity detection)but actual capability degrades - No crash, no hang: bounded by the configured NER timeout (
detector.timeout_secs)
Mode: advanced (NER Only)
detector:
mode: advanced
advanced_url: http://localhost:9090NER is mandatory in this mode. Builtin regex still contributes structured detection, but NER cannot be bypassed: requesting builtin_regex alone is rejected, and if the Python sidecar is unavailable the request FAILS CLOSED with GUARDAI_DETECTION_FAILED rather than downgrading to builtin-only. Graceful fallback to builtin is a both-mode behavior only.
The same fail-closed rule applies whenever a loaded policy marks an entity type required_for (via detection.ner_labels, or the opt-in healthcare-hipaa template): the runtime gates on whether NER actually ran, not on the configured mode, so a required_for type that NER did not produce rejects the request instead of silently passing the input through.
Detection Mode Decision Tree
How to Verify Runtime Mode
# Check current mode (requires admin scope)
curl -H "X-API-Key: $GUARDAI_API_KEY" http://localhost:3000/v1/diagnostics | jq .detector_mode
# Check available entity types
curl -H "X-API-Key: $GUARDAI_API_KEY" http://localhost:3000/v1/capabilities | jq '.entity_types[].name'
# Check per-request mode (in transform response)
curl -X POST http://localhost:3000/v1/transform \
-H "X-API-Key: $GUARDAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input":"test","input_type":"text"}' | jq .detector_modeQuality Expectations by Mode
| Entity Type | Builtin | + GLiNER | Notes |
|---|---|---|---|
| Precision >99% | Same | Regex + Unicode support | |
| Phone | Precision >95% | Same | International formats |
| SSN | Precision >99% | Same | Strict format matching |
| IBAN | Precision >99% | Same | Country code + structure |
| Credit Card | Precision >99% | Same | Luhn validation |
| Person Name | N/A | Precision ~85-95% | Language-dependent |
| Company Name | N/A | Precision ~80-90% | Context-dependent |
| Location | N/A | Precision ~80-90% | May overlap with Address |
Overlap Precedence
When a regex span and an NER span cover the same text, the merge applies a deterministic precedence so the entity type is stable regardless of NER over-tagging:
- Structured regex types always win over NER. email, phone, ssn, iban, ip, url, order, passport, health_id, customer_id, and critically
credit_cardanddate_of_birthare precise, deterministic, high-value PII. If NER tags an overlapping span (for example a date read as an event or a card number read as an ID), the structured regex type is kept, not downgraded to the NER label. - NER wins for name-shaped types (person, company, address) over non-structured regex overlaps.
- Otherwise the longer span wins, then the higher-confidence span, with ties resolved deterministically.
NER Precision Floor (False-Positive Suppression)
Zero-shot NER (GLiNER) over-tags common function and greeting words as person/company/location entities. OGuardAI applies a built-in precision floor after NER, additive over the raw model output:
- A universal acronym stoplist (~50 entries: PII, API, CEO, IBAN, SWIFT, HR, SSN, ...) drops NER spans that are just a known acronym.
- A per-language noise floor (shipped as data for German and Arabic today) suppresses NER spans whose tokens are all noise words, stopwords, or proclitics, including glued phrases the model tags as one entity.
- A minimum-confidence floor for NER-only types (built-in 0.65) drops low-confidence names.
This floor is a precision floor, not a ceiling: a deployment may add acronyms, un-suppress a specific built-in acronym so an acronym-shaped real organization name is detected, or raise the confidence floor (stricter only). It can never lower the floor or weaken detection below the built-in baseline, and invalid overrides are rejected at startup.
Recommendation
- For maximum speed + determinism: Use
builtinmode - For maximum coverage: Use
bothmode with healthy NER sidecar - For production safety: Configure health monitoring for NER sidecar availability
Token Protocol
The semantic token format, deterministic assignment, the per-token capability cap, and the three-stage repair that make restoration safe against a mutating LLM
Detector Capabilities
Entity detection capabilities by runtime mode, language support matrix, performance characteristics, and deployment modes