AWS Marketplace·Enterprise deployment — listing in progress.Contact sales·View pricing

INTERTRACE — RUNTIME AI SECURITY • GATEWAY PROTECTION • RUNTIME VERIFICATION • BEHAVIORAL INTELLIGENCE • PROMPT INJECTION DEFENSE • PII REDACTION • SUB-50MS CLASSIFICATION • COMPLIANCE REPORTING • MANAGED AGENTS • OWASP LLM TOP 10 • INTERTRACE — RUNTIME AI SECURITY • GATEWAY PROTECTION • RUNTIME VERIFICATION • BEHAVIORAL INTELLIGENCE • PROMPT INJECTION DEFENSE • PII REDACTION • SUB-50MS CLASSIFICATION • COMPLIANCE REPORTING • MANAGED AGENTS • OWASP LLM TOP 10 • INTERTRACE — RUNTIME AI SECURITY • GATEWAY PROTECTION • RUNTIME VERIFICATION • BEHAVIORAL INTELLIGENCE • PROMPT INJECTION DEFENSE • PII REDACTION • SUB-50MS CLASSIFICATION • COMPLIANCE REPORTING • MANAGED AGENTS • OWASP LLM TOP 10 •
← Back

ADR 0004: AI-first detection and the regex freeze

Research note · August 11, 2026 · 13 min readBy Samuel OyanEngineer
researchADR 0004classifierintent router

Research note: why Intertrace refuses to grow classifier regex and riskgate pattern counts, and how protected assets, intent routing, and tenant OPA absorb new misses instead.

Abstract

Pattern-count growth is a tempting incident response: a missed prompt becomes a regular expression, CI goes green, the next paraphrase misses again. ADR 0004 (accepted 2026-07-17) freezes MustCompile counts in gateway-go/internal/classifier/regex.go and gateway-go/internal/riskgate/gate.go. CI enforces the freeze in gateway-go/scripts/check-regex-freeze.sh. Detection quality is required to move through evaluated classifiers, optional intent-router prototypes, tenant OPA / policy packs, and ForceAI on protected assets. Benign skip of AI classification is opt-in via INTERTRACE_INTENT_ROUTER_ALLOW_SKIP and defaults off. This note records the technical rationale, the operational alternatives, the interaction with later decision fusion (ADR 0009), and the failure modes of treating string libraries as a product.

Force AI on protected assets
PromptIntent routerprototypeprotectedbenign*Force AISkip (opt-in)Classifier* INTERTRACE_INTENT_ROUTER_ALLOW_SKIP default off · regex freeze (ADR 0004)

The interesting miss is not that we lacked a string. It is that the model and policy did not agree with the attacker’s paraphrase. That is an eval problem. Protected assets never take the skip path. INTERTRACE_INTENT_ROUTER_ALLOW_SKIP defaults off.

1. Introduction

Deterministic regex and fast-gate patterns are a useful hard floor. Literal secrets, obvious command substitution, and a small set of CRITICAL exploit shapes should not wait on a remote judge. That floor is not a strategy for first customers whose agents speak insurance English, HR English, support English, and red-team English in the same afternoon. Growing the library for every Support Agent paraphrase overfits our own drills, drifts per tenant, and becomes the product’s maintenance tax. Live probes during the ADR window showed AI-on-LOW catching on the order of 98% of regex-blind attacks that the pattern library would have allowed. The remaining work is not the 2%. It is refusing to spend the next year chasing the 2% with MustCompile.

Security organizations already know this pattern from WAF signatures, antivirus, and DLP dictionaries. Each generation begins with high-precision strings and ends with a committee that is afraid to delete them. LLM traffic makes the failure faster: attackers optimize wording, not bytes, and internal users generate false positives by discussing the very controls we encode. A freeze is a process control on that loop. It is not a claim that regex is unused.

1.1 Claims and non-claims

  • Claim: new misses must not land as additional MustCompile in the frozen files without an explicit freeze-budget review.
  • Claim: protected assets always receive AI judgment (ForceAI / tier override). LOW_REGEX pass-through never applies when assetProtected is true.
  • Claim: benign AI-skip is opt-in and default off. ClassifyOpts.ForceAI (asset policy) is distinct from IntentRoute.RequireAI (hostile match).
  • Non-claim: the classifier is omniscient. Fusion, twin corpora, and analyst feedback exist because it is not.
  • Non-claim: 50ms inspect is free. AI-first increases latency on LOW when AI is configured; skip is how some operators will want to buy it back, which is why skip is dangerous.

2. Why freeze

Regex encodes yesterday’s wording. Attackers optimize for everything except yesterday’s wording. Each added pattern also adds false positives that train operators to ignore the gateway. The social loop is worse than the technical one: a miss produces a Slack message that begins just add a pattern. The diff looks like security. A frozen file looks like neglect. It is the opposite. CI freeze makes the cheap path unavailable so the expensive path—eval sets, feedback, OPA, prompt calibration—is the only path.

Two files are frozen, not one. regex.go is the classifier’s lexical library. riskgate/gate.go is the fast-gate. Splitting them did not save us from double growth; both receive the same incident-driven patches unless a script counts MustCompile and fails the build. The baselines at freeze were 49 and 116 respectively. ADR 0009 later notes the freeze unchanged at those counts while fusion work landed elsewhere. The numbers are not sacred. Raising them is a review, not a drive-by.

A freeze is also a statement about where generalization lives. A regular expression that matches ignore previous instructions in three encodings does not match a polite paraphrase in French that still attempts to dump tokens through an allowed claims tool. An embedding-style intent prototype can escalate that paraphrase to AI without adding a language-specific pattern. Tenant OPA can deny a tool for one org without polluting the global kernel. Those mechanisms have their own failure modes. They fail in ways we can evaluate. Regex fails in ways we only notice after the next miss.

2.1 What the freeze is not

The freeze is not a ban on deterministic enforcement. CRITICAL fast-gate still fails closed. Timeouts on catastrophic classes still fail closed. Literal secret shapes still belong on the floor. The freeze is a ban on using those files as the product’s memory. If a miss is truly a missing literal—an API key format we do not detect—the review can raise the budget. If a miss is a paraphrase, the PR that adds a phrase is the wrong artifact even when it would turn a unit test green.

3. Mechanics of the freeze

check-regex-freeze.sh counts MustCompile( in the two files, preferring ripgrep and falling back to grep. If regex.go exceeds 49 or riskgate/gate.go exceeds 116, the script prints the policy and exits non-zero: add intent-router prototypes, classifier eval cases, or tenant OPA instead. The script is the ADR in executable form. A markdown decision that CI does not run is a blog post.

ClassifyOpts in classify_opts.go is the request-scoped control plane for the judge. ForceAI overrides LOW_REGEX and REGEX so protected assets always get AI judgment. AllowAISkip permits the intent router to skip AI on clearly benign traffic and is ignored when ForceAI is true. PurposeCategory selects a domain language pack so colliding job English is scored as benign-ops rather than a jailbreak lab. Options travel on context. Defaults are AI-first: AllowAISkip false unless the process opted in.

Parity resolution (resolveClassifyTier / related helpers) applies protected-asset ForceAI and hostile RequireAI on top of lexical tiering. LOW_REGEX remains regex-only unless those bits are set. Skip is allowed only when AllowAISkip is true, ForceAI is false, and the route says AllowSkipAI. That triple is the entire safety argument for skip. Two out of three is not enough.

4. Where new misses go

  1. Intent-router prototypes: local token prototypes that escalate hostile paraphrases to AI, including overriding LOW_REGEX, without expanding regex. Remote embeddings stay out until there is a real call site. Domain language packs for benign-ops live here, keyed by purpose_category—not as new MustCompile in frozen files.
  2. Classifier evaluation and feedback: labeled transcripts, analyst false_positive / false_negative on findings, nightly mining into allow-path clusters, pinned cases that cannot drop from the corpus. A miss becomes a row, not a pattern.
  3. Tenant OPA and policy packs: organization-specific deny and allow that do not pollute the global kernel. Global string lists are not the product.

This ordering is not a waterfall. A protected asset miss that the judge allowed is a fusion and eval problem (ADR 0009), not an invitation to skip. A tenant-specific tool that should never run in that org is OPA even if the classifier would have allowed it. A clearly hostile paraphrase that regex missed is an intent-router prototype plus a judge, not a third encoding of ignore previous instructions.

4.1 Protected assets always ForceAI

Pass-through LOW_REGEX never applies when assetProtected is true. Headers and agent context both have to be able to set ForceAI; promptGuard policy context treats X-Intertrace-Asset-Protected and agent IsProtected as sufficient. Authorize paths pass ForceAI into ClassifyOpts. Compact-classifier environment overrides must not quietly disable protected-asset ForceAI on the promptGuard path. The invariant is simple enough to test and easy to break with a latency flag. Tests should fail when a protected asset would have taken LOW_REGEX.

Protected is a policy statement about blast radius, not a sentiment about the prompt. A greetings-class utterance on a payroll agent is still in the ForceAI set. That is the latency cost we accepted in the ADR consequences: LOW gets more expensive when AI is configured. The offset is later, opt-in skip plus possible remote embeddings—not a silent exception for protected assets that happen to look friendly.

4.2 Skip is a loaded gun

Skipping AI on obviously benign traffic recovers latency. It also creates an attacker-shaped hole: look like benign. INTERTRACE_INTENT_ROUTER_ALLOW_SKIP maps onto ClassifyOpts.AllowAISkip (legacy BASTION_INTENT_ROUTER_ALLOW_SKIP still parsed, default false). The flag is off unless an operator accepts the trade. Protected assets never take it. Industry latency-tier comments in config that send remote AI only on RequireAI / ForceAI / MEDIUM|HIGH when skip is on are exactly the trade: you are betting the router’s benign class against an adversary who has read this paragraph.

We still prototype skip because inspect budgets are real. A 50ms conversation for gateway-added time cannot absorb an unbounded judge on every ping and every empty heartbeat. The correct response is a measured allow-skip on non-protected assets with eval coverage of the skip set, not a regex of salutations. If skip cannot be evaluated, it stays off. Default off is the ADR. Default off is the code.

5. Decision fusion and the twin corpus

ADR 0004 stopped regex growth. It did not specify how the judge, the router, and the fast-gate should combine. ADR 0009 (accepted 2026-08-13) does. The context was concrete: protected-asset ForceAI still 403’d customer job English after a threat-matrix allow-reason fix, because the judge said allow and the intent router plus a pre_provider FLAG→BLOCK vetoed it on phrases like no full SSN and using the allowed claims.get tool. Growing regex.go to carve those out would have violated the freeze and encoded more job English as a negative lookahead. Fusion was the alternative.

The fusion rule (SSOT: gateway-go/internal/classifier/fusion.go) is deliberately small. Floor (fast-gate critical / hard hostile intent) may BLOCK alone. Judge allow or monitor with no typed threat: PASS, and the intent router must not 403. Judge allow plus typed threat at or above threshold: BLOCK, because the judge can miss attacks. Judge block plus intent or fast-gate agreement: BLOCK. Disagreement: FLAG / monitor, not a silent 403. Do not globally demote a threat class; demote only when intent is benign-ops or an allowlisted-tool job. That last sentence is how you keep fusion from becoming a second regex.

Twin corpus is a merge blocker: lib/qa/allow-path-corpus.ts, Go mirrors, npm run gate:allow-path-corpus. Enforcer deploys also run live AI runtime protect end-to-end. Must-allow regressions do not merge. Analyst false positives persist to classifier_eval_feedback. A nightly cron mines 14-day 403-plus-benign clusters. Pinned cases cannot drop. Shadow-before-enforce defaults soft hostile elevate to observe. None of that is possible if the response to a 403 is a new MustCompile that makes the unit test pass and the corpus rot.

6. Evaluation design

A freeze without eval is just a smaller signature set. The interesting measurements are: regex-blind recall of the judge on a held-out paraphrase set; false-positive rate on must-allow job English; skip-path leak rate if AllowAISkip is enabled in a lab; protected-asset ForceAI coverage (did any protected request take LOW_REGEX); fusion disagreement rate (FLAG vs silent 403). Precision/recall reported only on last month’s red-team wording will overstate the freeze’s wisdom.

We treat findings marked false_positive as training input, not as a reason to delete the finding. Deleting the finding deletes the audit line and the eval row. Status changes go through withFindingChangeSource(); they are not a side channel into regex.go. If an analyst label cannot block a merge, the loop is theater. ADR 0009 made corpus membership a merge blocker for that reason.

  • Must-allow: job English, negations, allowlisted tools. Target: 0 403s on the corpus.
  • Must-block: typed attacks on protected agents. Target: 0 misses on that suite.
  • Regex freeze: 49 / 116 unless a freeze-budget review says otherwise.
  • Skip: measured only in configurations that set the opt-in flag; never inferred from production defaults.

7. Operational consequences

Latency on LOW increases when AI is configured. Operators will ask for skip. The answer is the flag name, the default, and the protected-asset invariant—not a custom build that hard-codes skip on. Fail-closed on CRITICAL and on timeouts remains. A judge timeout is not a pass-through. Fusion’s FLAG path is not a pass-through either; it is an explicit weaker enforcement that still records evidence.

Tenant OPA becomes the release valve for org-specific strings we will not globalize. That shifts load onto policy authoring quality. Packs are inputs, not certificates. A pack that reimplements a banned regex in CEL is still a string list; it is at least a string list one tenant owns. Review it as such.

The Go enforcer on Fly (https://intertrace.fly.dev, pin v1.3.1) is where this code runs for product traffic. Railway gateway-v2 and Node proxies are not the place to prototype a new MustCompile because they are not the product path. A detection improvement that exists only on a legacy proxy is not an improvement we can evaluate in production metrics.

8. Failure modes

  • Freeze exception without review: a one-line regex to get a customer unblocked. The next paraphrase is free.
  • Skip default flipped in a deploy overlay and not in docs. Protected assets might still be safe; everything else is a hole shaped like hello.
  • ForceAI implemented only on one header and not on agent context, or the reverse. Inventory drift then silently drops protection.
  • Fusion used as a dump for special cases until it is an untestable maze. The rule list in ADR 0009 is the budget.
  • Eval corpora that contain only attacks. Must-allow is half the product. Job English 403s destroy trust faster than a missed jailbreak in a lab.
  • Storing classifier labels in Convex or in Clerk metadata. Eval and evidence belong with gateway_events and findings under RLS.

Mature detection vendors fuse cheap and expensive signals, keep golden corpora in CI, feed analyst decisions into eval, and observe before they enforce. Cloudflare WAF, Google Model Armor, AWS Bedrock Guardrails, and similar systems differ in UI and in model choice. They agree that signature sprawl is not the scaling axis. ADR 0004 is Intertrace’s version of that agreement, specialized to an OpenAI-compatible and MCP gateway with key-derived tenancy and a fail-closed Go enforcer.

Academic prompt-injection literature emphasizes attack success rates against a model. Our unit of analysis is a gateway decision under a latency budget, with evidence that must survive a review. A 98% catch rate on regex-blind probes is a point-in-time lab number, not a residual-risk certificate. We publish it here because it was the empirical reason to freeze, not because it is a forever SLO.

10. Limitations

The freeze cannot see patterns added under a different API than MustCompile. A clever helper that compiles elsewhere would dodge the script. Code review still matters. Local token prototypes can overfit as badly as regex if we grow them without eval. Tenant OPA can encode discriminatory or brittle rules that the global kernel would have refused. AI judges drift when vendors change models; fusion and corpora are how we notice, not how we prevent vendor change.

We also cannot freeze the human urge to look busy after a miss. The ADR exists to give reviewers a script to point at. If leadership treats a frozen count as neglect, the freeze will be lifted in the worst way: a batch of phrases from the last incident. The remedy is visible eval, not a higher MAX_REGEX_GO.

10.1 What we measured, and what we did not

The 98% AI-on-LOW figure was a live-probe observation on regex-blind attacks the pattern library would have allowed. It is not a production residual-risk number, not a p95, and not a claim about skip-enabled configurations. We do not have a right to quote it as an SLO. We have a right to use it as the reason we stopped adding phrases. Subsequent quality work is corpus-gated: must-allow job English at zero 403s on the twin corpus, must-block typed attacks at zero misses on the protected-agent suite, freeze counts unchanged unless reviewed. If those gates are green and a customer still sees a miss, the miss becomes an eval row. If those gates are green and a PR still adds MustCompile, the PR is the incident.

11. Conclusion

AI-first detection is not a slogan. It is a constraint on the repository. If a PR grows the frozen pattern tables, it is not a detection improvement—it is a process failure. New misses go to intent-router prototypes, classifier eval and feedback, or tenant OPA. Protected assets always ForceAI. INTERTRACE_INTENT_ROUTER_ALLOW_SKIP defaults off and never applies to those assets. Fast-gate remains a hard floor for CRITICAL and for timeouts. Everything else is judged, fused, and measured. The cheap path is unavailable on purpose.

References (selected)

  • ADR 0004: AI-first detection — stop growing the regex library (accepted 2026-07-17).
  • ADR 0009: Decision fusion, twin corpus, and shadow-before-enforce (accepted 2026-08-13).
  • gateway-go/scripts/check-regex-freeze.sh — MAX_REGEX_GO=49, MAX_RISKGATE_GO=116.
  • ClassifyOpts in gateway-go/internal/classifier/classify_opts.go; fusion.go as fusion SSOT.
  • INTERTRACE_INTENT_ROUTER_ALLOW_SKIP / ClassifyOpts.AllowAISkip, default false.
  • Industry notes on WAF/guardrail shipping: cheap+expensive fusion, golden corpora as CI, observe-then-enforce.

Continue reading

← Back to blog