Skip to main content
Delivery

Layered guardrails across voice, web chat and messaging

A policy that holds on web chat and quietly softens on voice is not a policy. The layers, the order they run in, and what the assistant does when one of them fires.

Delivery
First-party capability build, operated by Humint Labs and answering real inbound enquiries across voice, web chat and messaging. Deployed in-region on AWS.
System proof points

Measured system behaviour

3Channels

Reference design scope across voice, web chat and messaging.

OrderedControl layers

Reference design target: policy checks run in an explicit sequence.

SeparatedFailure classes

Reference design target: blocking, redirecting and escalation are distinct.

RepeatableRegression path

Reference design target: guardrail changes are tested before release.

The Challenge

The operating challenge

One assistant answers real inbound enquiries on voice, web chat and messaging. It has one policy and three delivery paths, and the ordinary failure is the reverse: three implementations of the policy that drift apart, until a refusal on web chat is a hedge on voice and nobody notices until someone reads a transcript.

Guardrails are usually assembled one at a time, each in answer to something that already went wrong, and each configured wherever it was cheapest to configure at the time. What results is a set of controls that nobody can describe in order, whose interactions are undocumented, and whose combined behaviour has never been stated as a testable claim. The controls are real. What is missing is a definition of correct that a change can be measured against.

Channel differences are real, and almost all of them belong to delivery rather than to policy. Voice arrives as transcription output, not as text a person wrote, so a pattern-based check tuned against typed input weakens exactly where confirming a value with the person is slowest. The order the layers ran in was carrying weight nobody had assigned, with an expensive grounding check sometimes running on turns a scope check would have ended for nothing. Blocking and redirecting were both being reported as the guardrail firing, hiding the fact that most interventions should not end the conversation. And nothing had a test: configuration was tuned against a handful of remembered examples, so a regression could only be found by a person meeting it in production.

What we found

  • Channel differences are real, and almost all of them belong to delivery rather than to policy. What a caller hears is shorter than what a chat user reads, and a messaging reply may arrive an hour later. Whether the answer is allowed is not a channel question, and every place it had been treated as one was a defect waiting to be found.
  • Voice arrives as transcription output, not as text a person wrote. There is no punctuation to anchor a pattern, numbers are spelled as words, and names come through approximated. A pattern-based check tuned against typed input weakens exactly where confirming a value with the person is slowest.
  • The order the layers ran in was carrying weight that nobody had assigned. Layers had been added in the order incidents happened, which meant an expensive grounding check ran on turns that a scope check would have ended for nothing.
  • Blocking and redirecting were both being reported as the guardrail firing, and the single label hid the important fact underneath: most interventions should not end the conversation. A control that only knows how to stop is a control that gets loosened until it stops working.
  • Nothing had a test. Configuration was tuned against a handful of remembered examples, so a change could be argued about but not demonstrated, and a regression could only be found by a person meeting it in production.

Where the bottleneck sat

The constraint was never detection quality. It was that guardrail behaviour lived as configuration, tuned by hand, with no written definition of correct behind it.

Without that definition no change could be shown to be an improvement, and no channel could be shown to behave the same as the others. Everything built afterwards follows from writing the definition down first.

Design rationale

Part of the answer was not code. Before any layer was moved, the policy was written once as a channel-independent statement, with the deliberate channel exceptions listed beneath it, each carrying the reason it exists and the name of the person who agreed it.

That exercise resolved more than the reordering did. Two behaviours that had been logged as bugs were correct and are now recorded as intended, and one that everybody had assumed was intended had no owner and no rationale, so it was removed.

Build

Our Solution

The constraint was never detection quality. It was that guardrail behaviour lived as configuration, tuned by hand, with no written definition of correct behind it. Without that definition no change could be shown to be an improvement, and no channel could be shown to behave the same as the others.

Part of the answer was not code. Before any layer was moved, the policy was written once as a channel-independent statement, with the deliberate channel exceptions listed beneath it, each carrying the reason it exists and the name of the person who agreed it. That exercise resolved more than the reordering did: two behaviours that had been logged as bugs were correct and are now recorded as intended, and one that everybody had assumed was intended had no owner and no rationale, so it was removed.

What we built is five policy layers on the request path in a fixed order: topic and scope, content safety and personal information handling before generation, then a grounding check and output validation after it. The layers are defined once, in one shared policy core, and every channel resolves the same decision from it. Topic and scope runs first because it is the broadest and cheapest, and it redirects rather than blocks, naming what the assistant covers and offering it. Content safety is the only layer permitted to end a turn outright, refusing once and offering a route to a person rather than explaining its reasoning. Personal information is matched before anything is written to a store, redacted in place so the turn continues and the unredacted value never reaches storage. The grounding check runs after generation and requires every claim to trace to a retrieved passage; a draft that fails is withheld rather than softened. Output validation checks shape, length and channel rules, and regenerates once before handing over rather than retrying until something passes. A small channel override register records the deliberate exceptions, each with an owner and a review date, and an override that changes an allow or deny decision is rejected at review. A lightweight routing model sits in front of the generation model so classification and generation scale independently.

The hardest part was recognising that guardrails tuned tight enough to be safe are tuned tight enough to be useless, and that failure is far harder to see than the one everybody guards against: an unsafe answer produces a complaint, but an assistant that has quietly stopped answering half of what it could answer produces silence, and the silence reads as adoption that never arrived. The remedy is a second test set with the opposite polarity, a false-refusal set of ordinary, legitimate enquiries the assistant must answer, run alongside the adversarial set. A change that raises the adversarial pass rate whilst dropping the false-refusal pass rate fails the pack, and neither number is reported without the other.

A policy decision is now made once and rendered three ways, rather than implemented three times and reconciled after a transcript review. The layers run in a stated order for a stated reason. A guardrail firing is recorded as what it did, redirect, block, redact or withhold, rather than a single count that hides the shape of the intervention. Guardrail configuration moves through the same review and release path as application code, and is versioned with it.

Scroll diagram horizontally

The order the guardrail layers run in, and what each one does when it firesVoice, web chat and messaging enter one ordered policy path before generation and delivery. Topic, safety, personal information, grounding and output checks take distinct redirect, block, redact, withhold or retry paths.Three channelsVoiceTranscribed turnWeb chatTyped turnMessagingTyped turn, asyncOne policy setThe decision is identical on every channel. Only the delivery differs.The request path, in orderWhat happens when it fires1. Topic and scopeIs this something theassistant answers at allredirectsNames what is in scope, offers itThe turn continues. The person is toldthere is a boundary, not that they erred2. Content safetyHarm classes, checked onthe way in and the way outblocksOne refusal, then a route to a personThe turn ends. A reason code is loggedagainst the conversation, not the wording3. Personal informationPattern and context matchbefore anything is storedredactsRedacted in place, turn continuesThe person is not interrupted. Theunredacted value never reaches the storeGenerationGrounded in the versionedknowledge layer4. Grounding checkEvery claim traceable to aretrieved passagewithholdsDraft withheld, handover offeredThe draft is withheld rather thanhedged. Nothing ungrounded is sent5. Output validationShape, length and the rulesof the channel it is bound forretriesOne regeneration, then handoverA second failure is a system fault,not a prompt to try harderDeliveryRendered for the channel:spoken, typed or asyncBroadest and cheapest first, so an expensive check never runs on a turn a cheap one would have ended
Ordered policy path and its exception outcomes.

The order the guardrail layers run in, and what each one does when it fires

Read the description

Voice, web chat and messaging enter one ordered policy path before generation and delivery. Topic, safety, personal information, grounding and output checks take distinct redirect, block, redact, withhold or retry paths.

Shared policy core

One definition of scope, harm classes and personal information handling, resolved by every channel from the same source. A channel adapter can change how a decision is rendered, in length, in phrasing, in whether a disclosure is spoken or linked. It cannot change what the decision was.

Topic and scope, layer one

Runs first because it is the broadest and the cheapest, and because a turn that is out of scope needs none of the checks below it. It redirects rather than blocks: it names what the assistant does cover and offers it, which is the difference between a boundary and a wall.

Content safety, layer two

Harm classes, evaluated on the inbound turn and again on the outbound answer, because the two directions fail differently. This is the only layer permitted to end a turn outright. When it does, the assistant refuses once and offers a route to a person, rather than explaining its reasoning, which is both an unhelpful reply and a description of the control to anyone probing it.

Personal information, layer three

Pattern and context matching, applied before anything is written to a store or a trace. It redacts in place and lets the turn continue, because a person who has just typed an account number has not done anything wrong. The unredacted value never reaches storage, which is what stops the trace store becoming a second uncontrolled copy of the conversation.

Grounding check, layer four

Runs after generation because it needs a draft to inspect. Every claim in the answer must be traceable to a passage the retriever actually returned from the versioned knowledge layer. A draft that fails is withheld rather than softened, because a hedged ungrounded answer is still an ungrounded answer and reads as more trustworthy than it is.

Output validation, layer five

Shape, length, formatting and the rules of the channel the answer is bound for. A spoken answer cannot carry a bulleted list or a link, and a messaging reply has a length the platform will truncate. This layer regenerates once. A second failure is treated as a system fault and handed over, not retried until something passes.

Channel override register

The small set of places where a channel's conventions justify a deliberately different behaviour, each recorded with the reason, the owner and a review date. The register exists so an intended difference cannot be read later as a bug, and so a bug cannot survive by looking like an intended difference. Overrides govern delivery. An override that changes an allow or deny decision is rejected at review.

Acceptance suite and regression pack

Every layer has its own suite, with an adversarial set and a false-refusal set for each, plus a channel matrix that runs the same policy cases through transcription output as well as typed input. The pack runs on every change to configuration or code, not once before go-live, because a guardrail with no test is a hope with a version number.

Guardrails tuned tight enough to be safe are tuned tight enough to be useless, and that failure is far harder to see than the one everybody guards against. An unsafe answer produces a complaint. An assistant that has quietly stopped answering half of what it could answer produces silence, and the silence reads as adoption that never arrived. The remedy is a second test set with the opposite polarity: alongside the adversarial cases sits a false-refusal set of ordinary, entirely legitimate enquiries that the assistant must answer, and a change that raises adversarial pass rate whilst dropping false-refusal pass rate fails the pack. Neither number is allowed to be reported without the other. That is also the only honest way to argue about a threshold, because a threshold argued without both numbers is settled by whoever is most worried in the room.

Outcome

What changed

  • A policy decision is made once and rendered three ways, rather than implemented three times and reconciled after a transcript review.
  • The layers run in a stated order for a stated reason, so adding a sixth layer is a decision about where it belongs rather than an append.
  • A guardrail firing is recorded as what it did, redirect, block, redact or withhold, so the shape of intervention is visible instead of a single count that hides it.
  • A channel exception has an owner, a rationale and a review date, so a deliberate difference cannot be mistaken for a defect a year later, and a defect cannot hide as a deliberate difference.
  • Guardrail configuration moves through the same review and release path as application code, and is versioned with it, so a policy change is as inspectable afterwards as a code change.
  • A tightening is now argued with two numbers rather than one, which is what stopped the slow drift towards an assistant that is safe because it answers nothing.
AI agentsGuardrailsMulti-channelVoiceTesting

Ready to shipEnterprise AI?

Get the Executive Guide