Relay Compliance
Overview
Section titled “Overview”Relay Compliance scans every AI Warden request/response payload in-line against compliance templates (HIPAA, SOC2, GDPR, PCI, and M-26-14) for PHI, PII, PAN/PCI, credentials and secrets. It produces one of three deterministic verdicts:
- ALLOW — clean / sub-threshold.
- ALLOW + NOTIFY — findings present; the request passes through but a violation is recorded and notifications fire (the default for hygiene-class findings, so traffic is never broken).
- BLOCK — a fired rule’s action is block (critical leaks).
It reuses the same production-tuned engine that scans Logrite source code — LogLeakDetector / LEAK_PATTERNS — no new pattern library, no new AI vendor. It ships as one product surface with AI Warden (Sprint 1) and also bootstraps M-26-14 for relay use; the full M-26-14 framework is owned by M-26-14 Maturity.
| Setting | Value |
|---|---|
| Engine | LogLeakDetector.checkSingle / shared leakPatterns.ts (analyzer dev + vendored byte-identical into the relay) |
| Scan location | In-relay, in-process (logrite-ai-service/src/warden/complianceCheck.ts) — no synchronous hop on the hot path |
| Events index | relay-compliance-events-{tenant} (OpenSearch, redacted) |
| Binding | relay_compliance_binding — since 2026-10-15 read only to resolve a request’s workspace and project |
| UI | Frameworks are framework items on a business-rules policy, edited in the policy editor or turned on from Rules & Policies → Frameworks (/policies/frameworks); see Rules & Policies. Violations surface in AI Warden → Overview. |
Verdict composition (most-restrictive-wins)
Section titled “Verdict composition (most-restrictive-wins)”resolve(business, compliance) → (1) if either is block → BLOCK; (2) else if either is allow_notify → ALLOW_NOTIFY; (3) else ALLOW. Each event records businessDecision, complianceDecision, and finalDecision.
Template → rule-set mapping
Section titled “Template → rule-set mapping”| Template | Canonical rules |
|---|---|
| SOC2 | soc2_log_leak_credentials, soc2_log_leak_confidentiality |
| HIPAA | hipaa_log_leak_phi, hipaa_log_leak_phi_object |
| GDPR | gen_log_leak_pii |
| PCI (implicit) | gen_log_leak_payment |
| M-26-14 | m2614_pii_in_ai_prompt, m2614_sensitive_output (+ reused gen_log_leak_pii, soc2_log_leak_credentials) |
| GEN | gen_log_leak_request_body, gen_log_leak_query_params — only when GEN is explicitly selected (no always-on floor) |
UX Lifecycle — Configure → Connect → Test → Operate → Review
Section titled “UX Lifecycle — Configure → Connect → Test → Operate → Review”- Configure — frameworks are
frameworkitems on a business-rules policy with the AI traffic feature (any of the 30 library frameworks), each with an optional action override (Block / Flag / Record) and the policy’s scan-scope setting. Only selected frameworks gate — there is no always-on floor. In Monitor only status (evaluate) the backend caps a framework owned only by Monitor-only policies to notify viaevaluateFrameworks. - Connect — the relay resolves the effective
ai_trafficpolicies per relay key and request project, and caches the bundle (LRU + short TTL). The legacy per-project binding and compliance-profile fallback were removed on 2026-10-15. - Test — use the in-tab relay test (Connect & Keys Step 3, or Business Rules → Test your configuration) to send a message through the relay and verify the right rules fire. See the AI Warden in-browser relay test for the built-in sample payloads and expected verdicts.
- Operate — LLM-first: the judge seeded by the selected frameworks is the primary decider; for each message the relay also normalizes in-scope strings →
checkSingle(sub-ms regex pre-filter / fallback) → composes verdict most-restrictive → redacts → fans out theComplianceEventasynchronously (off the hot path). See AI Warden — LLM-first judging. - Review — the Violations view (
relay-compliance-events-*): ALLOWED-BUT-FLAGGED filter, BLOCKED filter, mark-false-positive. The requests table shows a per-framework compliance chip deep-linking to the violation. Outside the app, the same events are read throughGET /api/v1/warden/compliance-eventsand/compliance-events/stats(2026-10-14; session or API key — see AI Warden), which MCP’swarden_relay list_events/event_statsandcompliance_logsuse.
API — removed
Section titled “API — removed”/api/v1/relay/compliance/* (GET/PUT /binding, GET /effective-ruleset), RelayComplianceController,
RelayComplianceService and warden_compliance_profile were removed on 2026-10-15. Configure
frameworks through /api/v1/policies (including POST /api/v1/policies/frameworks/{libraryKey}/enable) — see
Rules & Policies.
Redaction & safety
Section titled “Redaction & safety”The ComplianceEvent is redacted inside the relay before any sink: leakedFields = token names only, redactedSnippet ≤ 200 chars with values masked, raw values never written. Default posture is fail-open (a detector error records + allows); fail_mode: closed is per-binding opt-in. Notification fan-out is async/fire-and-forget — never awaited on the hot path.
Event timestamps (2026-10-14). Every ComplianceEvent carries the same instant in timestamp and @timestamp; before, only timestamp existed, and a window on @timestamp matched nothing. Existing events are backfilled per estate, and new indices get the backend’s relay-compliance-events index template — details and the dev/prod mapping divergence on AI Warden.
Redaction kinds (2026-10-09)
Section titled “Redaction kinds (2026-10-09)”Three kinds joined the product redaction list. They are identical, in the same order, in the
backend’s RedactionPatterns and the AI service’s DEFAULT_REDACTION
(urlCredential, credentialPair, email, ssn, mrn, card, iban, phone, dob, secretKey, opaqueToken, longDigits),
and are used by the relay, ingest-time redaction and the demo seeder.
| Kind | Matches | Example → stored |
|---|---|---|
mrn | MRN or “medical record (number/no/id)”, then up to three separators, then an id of 4+ letters, digits or hyphens (case-insensitive) | MRN TEST-004417 → MRN *** |
phone | North-American numbers: optional +1, a 3-digit area code (with or without parentheses), then 3 and 4 digits; also the short +1 NNN-NNNN form | call +1 555-0142 → call *** |
dob | a date after a label — DOB, D.O.B., date of birth, birthdate, birth date, born, born on (case-insensitive) | DOB 1984-03-12 → DOB *** |
An unlabelled date (2026-10-08 12:31) is not masked. mrn also counts as a strong value for
compliance findings. For Cortex answers the same kinds are rendered as labels ([SSN], [MRN],
[DOB], [EMAIL], [PHONE], [CARD], [IBAN]) instead of ***.
Judge reasons mask any quoted span of 2–80 characters (up to six words) unless it is the name of a
judged policy, a framework key or a snake_case rule id — so a reason quoting
'Jane Testperson' or 'MRN TEST-004417' stores neither value, while under 'No clinical advice'
keeps the policy name.
Whether the relay masks at all, and which kinds, is a workspace choice since 2026-10-09 — see AI Warden → Redaction switches.
HIPAA framework 1.4.1 (2026-10-09)
Section titled “HIPAA framework 1.4.1 (2026-10-09)”hipaa_log_leak_identifiersno longer flags every barehttps?://URL (an educational answer citing a guideline page raised Notify). A URL counts only when labelled as a patient or member URL or portal:\b(patient|member)[_ ]?(url|portal)\b\s*[=:]\s*https?://.- Response-scope word-list hits are weak. On a model response, a value-pattern hit is strong
only when the matched text contains a digit, an
@, or a run of 16+ opaque characters (or a redaction-kind hit). So “Biometric identifiers such as fingerprints” in an answer is allowed, whilessn: 123-45-6789still notifies. - The starter HIPAA template’s No clinical advice policy now reads: “Block any request seeking a
medical diagnosis, a treatment plan, or medication or dosage advice for an identifiable patient or
for a person whose symptoms are described for that purpose. Questions about usual or guideline care
for a condition or a generic, de-identified case (e.g. ‘usual follow-up for type 2 diabetes’) are
general health education and are allowed.” Judge eval: a de-identified diabetes follow-up question
is allowed; dosing for “my patient” and diagnosis from symptoms are blocked (55/55 cases on
deepseek-v4.1-flash). Policies already saved keep their own text.
Demo data
Section titled “Demo data”When the events index is empty, opensearch/scripts/seed-demo-program.sh seeds sample violations into relay-compliance-events-{tenant} (allow_notify + block, cross-linked to the warden requests) so the Violations view renders; --clean removes them.
Scaling & throughput
Section titled “Scaling & throughput”The relay is the inline LLM-proxy hot path (/v1/:provider/*) and the surface that high-volume / agentic-coding traffic hits. Measured ceiling (single process, mock upstream, full pipeline, judge off): ~350 req/s at p95 ~500 ms / 150 concurrent (harness: perf-tests/run-warden-bench.sh, results in perf-tests/WARDEN-FINDINGS.md).
| Concern | Lever | Default |
|---|---|---|
| Overload backpressure | WARDEN_MAX_INFLIGHT — over the per-process cap → 429 over_capacity + Retry-After (no timeouts/5xx) | 500 |
| Global rate/token limits + shared caches | WARDEN_REDIS_URL / REDIS_URL — makes limits + binding/judge caches GLOBAL across cluster workers/replicas; fail-soft (unset/down ⇒ in-process, never errors; ~2% hot-path overhead) | unset (in-process) |
| Per-key request cap (DoS) | WARDEN_RATE_LIMIT_PER_MIN | 1200 |
| Per-tenant token budget (agentic TPM) | WARDEN_TPM_BUDGET_PER_TENANT — 0 disables | 0 |
| Multi-core | WARDEN_INSTANCES=max — node cluster inside the container; safe ONLY with Redis set (else per-fork caps multiply). The PM2 cluster this used to describe no longer exists | 1 (fork) |
| async_observe judge throughput | WARDEN_JUDGE_WORKERS — concurrent queue drainers; /health.judgeQueueEvicted surfaces drops | 4 |
| Groq judge resilience | invokeGroq retries 429/5xx/network with jittered backoff + Retry-After | — |
| Audit-write load-shed | WARDEN_CAPTURE_ENABLED=false drops per-request capture writes under extreme load | true |
/health exposes saturation signals: inFlight, maxInflight, judgeQueueDepth, judgeQueueEvicted, redis.
Recommended production sequence: provision Redis → set WARDEN_REDIS_URL → confirm /health shows redis: connected → set WARDEN_INSTANCES=max → (optionally) run N relay replicas behind Traefik. WARDEN_TEST_STATIC_BINDING is TEST-ONLY (isolated load tests) and MUST be empty in production.
Close-out fix wave 2 (2026-10-09)
Section titled “Close-out fix wave 2 (2026-10-09)”mrnneeds a digit. Anmrnmatch is masked only when the captured value contains at least one digit, so phrases like “MRN field” or “medical record number” with a plain word after them are left alone (backend 2e4517eb, ai-service 05bc0561).- Response-scope value matches. On
scope: response, a value-pattern hit is strong only when the matched text contains a digit, an@, or an opaque token of 16 or more characters; anything else is a weak word-list hit and does not raise a finding on its own.