
Enterprise Agent Mesh · Engineering Guide 08 / 12
Build a Customer Support Agent around containment quality, not gross deflection: answer only when the customer’s account state and scoped evidence support the reply, route uncertain or consequential cases to a human quickly, and make the customer-facing send path stricter than the drafting path.
Source: Article 8 of The Enterprise Agent Mesh — Building Twelve Production AI Agents on Claude Code, September 2026, physical rendered pages 171–196. This web edition preserves the chapter’s twelve-section structure. Figures, thresholds, rates and failure observations from the handbook are reference-deployment guidance, not independently verified Infinity Technologies client results or universal benchmarks. Explicit Web-edition qualification notes separate current documentation checks and engineering hardening from the handbook. The cover is shared platform artwork, not a Customer Support product screenshot.
Routing a ticket to a human early is not a failure of the system. A confident wrong answer that prevents a human from seeing the ticket is.
The Support Agent sits between customer language, product state and the company’s public knowledge. Its job is not to maximize the count of tickets that never reach an employee. The handbook’s core claim is that deflection is an unsafe objective: a customer who gives up, silently accepts a wrong answer, or leaves after an exhausting bot loop can all be counted as “deflected.” The system therefore optimizes a stricter measure—containment quality—which asks whether an agent-resolved ticket stayed resolved and did not produce downstream harm.
The reference chapter covers triage and routing; grounded resolution drafting using the knowledge base plus account state; copilot and autonomous support as separate products; knowledge-gap detection; L2/engineering escalation packets; proactive outreach for incident blast radius; and QA scoring of human and agent replies against one rubric. Those operating figures frame the design, but they are not a claim about an Infinity customer.
| Workflow | Reference starting point | Ceiling / authority boundary |
|---|---|---|
| Triage and routing | L3 act-and-notify | Field updates and queue routing are reversible; wrong routes must be measurable and correctable. |
| Copilot drafting | L1 draft | Permanently a draft product; a human owns the send. |
| Autonomous how-to reply | L2 initially | May reach L4 only for a named intent allowlist after live evidence and zero commitment violations. |
| Autonomous troubleshooting | L1 | At most L2 in the handbook; uncertain diagnosis belongs with a human. |
| Escalation packet | L3 | Internal artifact only; no customer-facing text. |
| KB article drafting | L1 | Writer-reviewed publication path; no direct public publish. |
| Proactive incident outreach | L2 | Permanent human approval: Operations owns the approved incident statement. |
| QA scoring | L1 | Agent-reply analytics may automate further; autonomous scoring of human work remains a labor-relations decision. |
Some boundaries never move up the autonomy ladder. The agent must not promise refunds, credits, discounts, extensions, SLA outcomes, roadmap dates, delivery dates or legal positions. It must not publish its own interpretation of an active incident; the Operations Agent’s approved statement is authoritative. It does not change account plans, entitlements or feature flags, and it does not close a ticket because it thinks the customer is satisfied.
That distinction also separates copilot from autonomous support. A copilot draft can be wrong and cost a human a minute of editing. An autonomous send can be wrong with the company’s logo attached. They require different thresholds, guardrails, audit paths and evaluation sets. Turning off the human composer is not a feature flag on the same risk model.
In the handbook, a ticket counts as contained well only after a lag: the customer confirmed resolution or became silent for fourteen days, the ticket did not reopen within fourteen days, no related downstream escalation was created, and CSAT was not negative. The exact window is a reference policy choice, but the principle is general: measure the consequence after the conversation, not just whether a transfer happened during it.
Because this metric matures after the observation window, it should not become a live “green number” that teams optimize hourly. It is a release and trend metric. The live operational metric should instead be how quickly a non-answerable or high-risk ticket reaches the right human with useful context attached.
The architecture is intentionally asymmetric. A cheap classifier determines whether the ticket appears answerable. Only then does the system resolve the account state, perform a version- and entitlement-scoped retrieval, and ask a stronger worker to draft an answer. Any failed gate routes to a human rapidly. There is no retry lane that keeps the customer inside a bot loop.
helpdesk webhook → NATS event
|
v
intake-normaliser (Haiku)
thread flattening · quote/signature stripping · language · attachment text · PII tags
|
v
ticket-triage (Haiku, structured verdict)
intent · product area · severity · entitlement · p(answerable)
|
+-- S1/S2, interlock, low p(answerable) ------------------→ human queue
|
v
load_account_context (deterministic)
plan · version · entitlements · region · flags · open incidents
|
v
search_kb (SQL-scoped before vector/lexical ranking)
version · entitlement · visibility · locale
|
+-- evidence/grounding gate fails ------------------------→ human queue
|
v
resolution-drafter (Sonnet)
draft_reply(evidence_ids)
|
v
send guardrail chain
commitment · citation visibility · incident interlock · PII egress
|
+-- assist mode → human composer
`-- named autonomous intent → runner sends after controlsThe source assigns intake normalization and triage to a Haiku-class worker, resolution drafting and escalation packaging to a Sonnet-class worker, and QA scoring plus threshold recalibration to an Opus-class offline reviewer. That routing expresses role shape rather than a permanent model recommendation. Pin an approved model per role and re-run the relevant golden slice when the model changes.
The key ordering is account context before retrieval. A passage that is correct for product 4.2 can be wrong for a customer on 3.9. A workaround available to an enterprise plan can be unusable on starter. A general KB article can be unsafe during an open incident. The model should not retrieve broadly and then “remember” to apply these facts. The retrieval service receives them as filter predicates.
The handbook’s routing example uses three illustrative thresholds: answerability at 0.62, a groundedness gate at 0.70, and a higher 0.82 bar for autonomous send. Those are calibration artifacts from the reference deployment, not defaults. The engineering requirement is that the autonomous bar be stricter than the drafting bar, and that any threshold be versioned, observable and recalibrated on live outcomes.
Inter-agent work remains event-driven. A support ticket that resembles an incident publishes an event such as agent.support.incident.candidate; Operations processes it within its own credentials and evaluation boundary. The Support Agent does not invoke an Operations agent inside the same context window and inherit its incident-communication authority.
Web-edition qualification — “probability answerable” is not a model confidence score to trust raw. Calibrate it against labelled tickets, segment by intent/language/version, and inspect drift. A threshold is only useful if the score’s meaning is stable. High severity, active incidents and hard interlocks remain deterministic routing conditions even when the classifier reports high confidence.
support-agent/
.claude-plugin/plugin.json
.mcp.json
CLAUDE.md
agents/
intake-normaliser.md
ticket-triage.md
resolution-drafter.md
escalation-packager.md
qa-scorer.md
skills/
escalation-packet/{SKILL.md,reference.md}
kb-gap-draft/SKILL.md
hooks/
hooks.json
commitment_scan.py
citation_visibility.py
interlock.py
pii_egress.py
mcp/
kb/server.py
helpdesk/server.py
account/server.py
evals/
golden/tickets.jsonl
rubrics/groundedness.md
sql/
001_scoped_chunks.sql
010_containment_quality.sqlCLAUDE.md contains invariants that are short, stable and true on every turn. Product facts with dates, version matrices and feature availability do not belong there. They belong in account context or retrieval so they can change without a prompt release.
# Support Agent — operating invariants
## Version and entitlement
- "Latest" is never a customer version. Read the deployed version from account context.
- A feature the account is not entitled to use is not an answer.
- Name the version in instructions where version affects the procedure.
## Severity
- S1/S2 never receive an autonomous reply.
- Severity follows product impact, not customer tone.
## Commitments
Never promise: refund, credit, discount, contract extension, SLA outcome,
roadmap/ship date, legal characterisation, or blame of a third party.
Acknowledge the request and route it.
## Active incident
If account context intersects an open incident, do not improvise.
Only the approved Operations statement can be customer-facing.
## Evidence
- Customer-facing factual claims require public, account-applicable evidence.
- Internal runbooks, postmortems and past tickets are not customer citations.
- Machine-translated KB content is not presented as company-authored documentation.
## Closing
The model never decides that a ticket is solved.
Customer confirmation or the helpdesk’s own approved auto-close rule owns closure.Language is also an invariant: reply in the language of the customer’s most recent message, not the language of the first message in a long thread. If the only supporting article is in another language, say that explicitly and link the source-language documentation. Do not silently transform an unreviewed machine translation into the company’s official wording.
Procedures with branches belong in skills. The escalation packet needs a fixed nine-part internal artifact. The KB-gap workflow needs a writer-editable article schema. Current product state belongs behind tools. This keeps system prompts small enough to audit and prevents a stale version table from surviving long after the product changed.
---
name: ticket-triage
description: Classify one inbound support ticket before any retrieval.
tools: mcp__account__load_account_context, mcp__status__active_incidents
model: haiku
effort: low
maxTurns: 3
disallowedTools: Bash, Write, Edit, WebFetch, mcp__kb__draft_reply
permissionMode: default
---
Return structured data only:
intent, product_area, severity, entitlement context, p_answerable,
language, sentiment, interlock, escalation_signal.
Impact sets severity, not tone.
S1/S2 route to humans.
Set interlock for distress/self-harm, legal threat, regulator/ombudsman,
or named journalist/publication.
On replies to an existing ticket, keep intent/severity locked; only
sentiment and escalation_signal may change.The reply-lock rule solves a common failure: an angry second message gets classified as a new “wait time” issue, the ticket moves queues, and the original technical problem disappears. The ticket’s core intent and product area are established once; later messages can escalate urgency without rewriting history.
The answerability field is specifically about whether a correct, complete answer for this account can be grounded in permitted evidence. If the question depends on data only engineering can see, the ticket is not answerable by the support agent even if the model recognizes the pattern.
---
name: resolution-drafter
description: Draft a grounded reply from scoped evidence and account state.
tools: mcp__account__load_account_context, mcp__kb__search_kb,
mcp__kb__draft_reply, mcp__telemetry__account_events
model: sonnet
effort: medium
maxTurns: 14
disallowedTools: Bash, Write, Edit, WebFetch, mcp__helpdesk__public_reply
permissionMode: default
---
1. load_account_context first.
2. search_kb inside its version/entitlement/visibility scope.
3. If no scoped evidence clears the relevance floor, route to human.
4. draft_reply only from the evidence ids intended for citation.
5. If draft_reply refuses a sentence: delete it, find evidence, or route.
Do not paraphrase around the check.A useful reply contains the answer, the exact step that applies to the customer’s version, and one verification step. It does not convert an inference into a telemetry observation. If a fix exists only in a later release, say which release; if their plan lacks the entitlement, say so without a generated sales pitch and route the commercial question to the account owner.
The escalation packager writes for an engineer, not for the customer. It separates customer report from observed telemetry. “The customer says exports fail” and “tenant telemetry shows fourteen timeouts from 09:12–09:41 UTC” belong in different sections. When they conflict, both are preserved and the agent does not adjudicate the mismatch.
The packet records what was already tried and what each attempt ruled out. That is not clerical detail: omitting a failed workaround guarantees the next engineer repeats it. The packager has no customer-reply tool and runs in a separate, internal artifact path.
The fourth role is an offline reviewer over a nightly sample of ledgered replies. It evaluates using the same rubric as the release suite and feeds threshold recalibration. It does not sit inline in the ticket path, and it has no ability to change a ticket or discipline a human agent. The chapter explicitly treats autonomous scoring of human work as an employee-relations decision, not as a technical default.
The escalation-packet skill fixes the shape of an L2/engineering handoff. The source order is worth preserving because it forces evidence and uncertainty to remain visible.
The invocation may load the current on-call rotation and known-issue register deterministically. The longer log-query cookbook and routing matrix stay in reference.md and load only when needed. Before writing, redact secrets, tokens, passwords, non-requester personal data and telemetry fields already marked sensitive.
A weekly gap cluster does not automatically justify a new article. First search the KB using the cluster’s common phrasings without a version filter. If an existing article contains the correct answer but was not retrievable, improve aliases, headings or metadata instead of creating duplicate documentation.
---
title:
applies_to: ">=4.0.0 <4.3.0"
requires_entitlements: []
visibility: public
risk_class: none
source_tickets: []
---The source requires every procedural step in a draft KB article to be grounded in product documentation or in a resolved ticket that actually performed the step. Customer text itself is not copied into the public article. The article remains a draft for a technical writer; an L1 documentation worker should not publish directly to the KB because the next support reply may treat that article as authoritative evidence.
Web-edition qualification — semantic version metadata must be parser-enforced. The source stores both a human-readable SemVer range and an integer range used for filtering. Validate the range at ingestion and derive the indexed representation in code. Do not accept arbitrary “applies_to” strings and rely on the model to interpret them consistently.
| System boundary | Reference role | Production qualification |
|---|---|---|
| Helpdesk: Zendesk / Intercom / Salesforce Service Cloud / Freshdesk | Ticket/thread reads, field updates, private notes and separately gated public replies. | Use tenant-configured quotas and endpoint-specific limits; one adapter normalizes vendor behavior. |
| KB/CMS | Search, article retrieval, revisions. | Read-only service identity; customer visibility is a server-side property. |
| Product telemetry | Account events, error rates, feature/flag state. | Tenant-pinned token; row/query-cost bounds; redact before egress. |
| Billing/entitlement | Subscription tier, entitlement set, invoice/contract state. | Read-only; short cache; never grants the agent plan-changing capability. |
| Status/incident feed | Open incident matching and subscription. | Open incident is a routing interlock, not additional context for free-form drafting. |
| CRM | Account owner, renewal state, account metadata. | Read-only and rate-conscious; do not leak internal commercial notes into customer replies. |
| CCaaS / voice | Transcript stream and handoff. | Latency changes architecture; keep a stricter template path until separately evaluated. |
Rate limiting is a system design problem, not a retry helper. The source calls for one token bucket per credential, a bounded priority queue, severity-aware ordering, and a circuit that sheds lower-priority reads before customer-facing writes. Current Zendesk documentation exposes Ticketing API limits in response headers; HTTP 429 responses include Retry-After, and some endpoints have additional endpoint-level limits. The adapter should read those signals instead of hard-coding one handbook rate. Zendesk documents the current Ticketing API rate-limit headers and 429 behavior.
Salesforce is different: its REST APIs expose organization usage through Sforce-Limit-Info and a Limits resource, and the standard API allocation is an org-level rolling/daily constraint rather than the handbook’s generic per-minute number. Salesforce documents the limit-info header and the REST Limits resource. Keep vendor limits in configuration and telemetry, not in CLAUDE.md.
request:
query: "How do I rotate the SCIM signing key?"
account_id: "acct-opaque-id"
product_area: "identity"
limit: 8
include_hypotheses: false
server-derived scope:
tenant_id: authenticated tenant
principals: authenticated caller principals
version: "3.9.4"
entitlements: ["plan:business", "feat:sso"]
region: "eu"
kb_watermark: immutable index generation
result passage:
evidence_id: "kb_4471#rotate"
heading_path: "Identity > SCIM > Rotate key"
applies_to: ">=3.9.0 <4.2.0"
visibility: public
evidence_class: kb
citable: true
last_reviewed: "2026-06-12"The caller supplies a ticket/account reference, but the server resolves authoritative account state. Client-supplied version or entitlement fields are hints at most; otherwise a prompt-injected ticket could widen its own retrieval scope.
The handbook’s draft_reply service accepts a ticket plus the evidence IDs the drafter intends to cite. It rejects non-citable evidence and runs sentence-level entailment against the supplied passages. A refusal is a valid tool result, not an exception: remove the unsupported sentence, retrieve better evidence or route to a human. The model is not allowed to rephrase around the refusal.
That architecture is stronger than “please cite your sources” in a system prompt. It also creates an observable failure mode: unsupported claim rate can be measured before send. The specific NLI threshold in the handbook is an implementation parameter from the reference deployment and must be recalibrated for the actual model, languages and evidence types.
Voice has a sub-second interaction budget, so a Sonnet turn, retrieval, and post-generation commitment scan may not fit. The source pre-warms account context while the caller is still describing the issue, performs a single scoped retrieval without the full reranker, and constrains generation to approved templates. That is intentionally less flexible and should stay on the assist side longer than chat until it has its own evaluation set.
The support corpus contains five evidence classes with different trust: public KB, product documentation, release notes, known issues, and past resolved tickets. They can live in one physical table, but they do not have the same right to appear in a customer reply. Internal runbooks, postmortems, account notes and contract terms stay out of the public answer path or are marked internal and server-side non-citable.
Before any search, resolve plan tier, entitlements, deployed version, region, flags, compliance posture, open incidents and contract state. Each field is either a filter or an interlock. The version gates procedures; entitlements gate available features; compliance posture blocks risky workarounds; open incidents route to Operations; contract state prevents tone-deaf “upgrade” advice in the wrong commercial context.
A contextual header that names product area, version range and symptom can make otherwise context-free sentences—“run the rotate command”—retrievable. That enrichment happens at ingestion and should record its generator/version so the index can be reproduced.
ALTER TABLE corpus_chunk
ADD COLUMN applies_to_versions INT8RANGE,
ADD COLUMN applies_to_semver TEXT,
ADD COLUMN required_entitlements TEXT[] NOT NULL DEFAULT '{}',
ADD COLUMN visibility TEXT NOT NULL,
ADD COLUMN evidence_class TEXT NOT NULL,
ADD COLUMN risk_class TEXT NOT NULL DEFAULT 'none',
ADD COLUMN locale TEXT NOT NULL DEFAULT 'en',
ADD COLUMN translation_status TEXT NOT NULL DEFAULT 'source',
ADD COLUMN last_reviewed DATE;
SELECT chunk_id, doc_id, heading_path, content, applies_to_semver, visibility
FROM corpus_chunk
WHERE tenant_id = $1
AND acl_principals && $2
AND visibility IN ('public','partner')
AND (applies_to_versions IS NULL OR applies_to_versions @> $3::BIGINT)
AND required_entitlements <@ $4::TEXT[]
AND translation_status <> 'machine'
ORDER BY embedding <=> $5
LIMIT 40;PostgreSQL range types support containment operators such as @>, which makes version applicability a data predicate rather than a prompt instruction. PostgreSQL’s range-type documentation describes built-in ranges and containment semantics. The article’s integer encoding for semantic versions is a reference implementation; define and test its ordering rules for your supported version scheme.
A useful edge case is entitlement discovery. If the fully scoped query returns no answer but a second controlled query without the entitlement predicate finds a matching public solution, the drafter can say the feature exists but is not in the customer’s current entitlement. That is different from pretending there is no solution. The second query does not authorize showing restricted content; it only returns a safe “blocked by entitlement” signal.
Approximate vector indexes can return fewer rows than requested when filtering removes candidates after the index scan. The handbook recommends an iterative HNSW scan and monitoring the returned/requested ratio. Current pgvector documentation confirms that iterative scans continue scanning after filtering, with strict_order and relaxed_order modes. pgvector documents iterative HNSW scans and their trade-offs. This is a retrieval-health control, not a guarantee that an approximate index will always return a complete top-k under every predicate.
Resolved tickets contain the language customers actually use, but they also contain incorrect answers that happened to end a conversation. The source ingests only a quality-filtered subset and scrubs PII. More importantly, it prevents laundering: past tickets can generate search terms and candidate KB article IDs, but their passages cannot be cited to customers. draft_reply rejects evidence IDs from the past_ticket class.
If no public KB/documentation supports a hypothesis from a past ticket, the result is a knowledge-gap event and a human handoff. The right response is not to quote a stranger’s old ticket with citation-shaped formatting.
The source orders controls from weakest to strongest: prompt, tool contract, hooks/backend policy. The single most important tool is mcp__helpdesk__public_reply, because that call crosses the trust boundary from internal reasoning to company-authored customer communication. The model should not own it directly.
BLOCKED = {
"financial_commitment": ["refund", "credit", "reimburse", "waive"],
"delivery_commitment": ["we will fix", "we'll ship", "we will deliver"],
"date_commitment": ["by tomorrow", "by end of week", "by Q*"],
"sla_commitment": ["SLA", "service credit", "uptime guarantee"],
"legal_statement": ["liability", "breach of contract", "indemnity"],
"roadmap_statement": ["roadmap", "planned for next release"],
"third_party_blame": ["their bug", "caused by AWS/Azure/Okta/Salesforce"],
}The source allows one rewrite after a blocked draft and then routes to a human rather than entering an adversarial paraphrase loop with its own guardrail. This is a strong production pattern: if a model has twice produced a prohibited commitment while the customer is waiting, the next action should not be “try harder to word it differently.”
The regular expressions are a floor, not a semantic guarantee. A small classifier can catch paraphrases such as “I’ll make sure you are not charged this month,” but it also requires evaluation. The backend remains authoritative: an agent cannot issue a refund simply because the wording filter missed a synonym, because the service principal has no refund/plan/SLA mutation capability.
After drafting, resolve every citation marker back to its corpus row and verify that the visibility is customer-permitted. This database lookup prevents a highly relevant internal postmortem from being quoted in a public reply. “The model knew not to cite internal docs” is not an access control.
Distress or self-harm signals, legal threats, regulators/data-protection authorities/ombudsmen, and press contacts trigger a human-only path. The interlock cannot be cleared by the model. It blocks customer-facing tools, raises a support-interlock event and notifies the duty lead. The routing classifier is not expected to conduct counseling, legal analysis or media response.
An active incident is a separate interlock. If account context returns a relevant open incident, free-form public_reply is denied. The only allowed customer-facing text is the approved Operations statement delivered by the governed incident outreach path. Support can attach context internally, but it does not invent cause or ETA.
Telemetry queries and KB search terms can accidentally contain raw customer email bodies, API keys or secrets copied from logs. Apply redaction before anything leaves the approved trust boundary. A search adapter receives the minimum needed query plus tenant/account scope; it does not receive the entire ticket transcript by default.
Web-edition qualification — permission callbacks are not the policy perimeter. Current Claude platform permission documentation distinguishes enabled tools from permission policy and notes that custom tools are application-controlled. In the Agent SDK pattern used by the handbook, the same architectural rule applies: a callback is a backstop, not a substitute for removing dangerous tools, narrowing credentials, server-side authorization and a guarded send service. Anthropic’s current managed-agent permission documentation makes that separation explicit for the managed runtime.
The runner owns idempotency, budget, lane decision and the final send. The model’s allowed tools include account context, KB search, grounded drafting and bounded telemetry. public_reply is absent/denied. Only after the response has passed the guardrail chain does the runner call the customer-facing adapter.
def idem_key(ticket):
return sha256("|".join([
ticket.ticket_id,
ticket.last_inbound_message_id,
PROMPT_VERSION,
ticket.kb_watermark,
]).encode()).hexdigest()
async def handle_ticket(ticket, mode="assist"):
key = idem_key(ticket)
prior = ledger_get_completed(key)
if prior:
return prior
result = await run_bounded_support_worker(
model=APPROVED_SUPPORT_MODEL,
allowed_tools=[
"mcp__account__load_account_context",
"mcp__kb__search_kb",
"mcp__kb__draft_reply",
"mcp__telemetry__account_events",
],
disallowed_tools=[
"mcp__helpdesk__public_reply", "Bash", "Write", "Edit", "WebFetch"
],
max_turns=14,
budget=SUPPORT_TICKET_BUDGET,
ticket=render_last_turns(ticket),
)
ledger_append(key, result)
if result.status == "budget_exhausted" or result.lane != "autonomous":
return route_to_human(ticket, result)
return send_with_guardrails(ticket, result)This is a reference excerpt, not a complete runnable service. The source’s USD 0.40 budget and fourteen-turn cap are circuit-breaker examples from its reference deployment, not pricing guidance. If a ticket exhausts the budget or the bounded worker fails twice, route to a human with the evidence and draft already assembled. Do not degrade to an ungrounded answer because the model is “almost done.”
The idempotency key includes the last inbound message, prompt version and KB watermark. A webhook redelivery can return a completed result, while a genuine KB reindex or a new customer reply produces a new decision. In production, implement the job claim atomically; a read-before-write ledger check alone can race under concurrent webhook deliveries.
For long threads, render only the most recent turns plus a separately labelled summary of older history, and clear old tool results according to an evaluated context-management policy. A summary is not evidence: if an older factual statement matters to the reply, retrieve or reread its authoritative source rather than treating the compressed summary as truth.
The webhook endpoint should validate the vendor signature, persist/publish a small event and return quickly. Do the expensive model work downstream. This reduces vendor timeout/retry races and keeps the ingress path observable.
The source uses an 800-ticket golden set stratified across intent, plan tier, product version, language and quarter, with two support-engineer labels and a third adjudicator. Sixty cases are adversarial: instructions hidden in signatures, forwarded quotes, PDFs/screenshots and Unicode-confusable text. The point is not only to test answer quality; it is to test routing, scope and the action boundary.
| Metric | What it measures | Handbook reference gate |
|---|---|---|
| Answerability AUC | Whether the classifier separates answerable from human-only tickets. | Target ≥0.91; fail below 0.88. |
| Groundedness | Draft sentences supported by supplied evidence. | Target ≥0.98; a sent unsupported draft is treated as an incident. |
| Containment quality | Agent-resolved tickets that remain accepted, unreopened, un-escalated and non-negative in CSAT. | Target ≥0.85; fail below 0.80. |
| Harmful commitment rate | Customer replies containing blocked commitment classes. | 0; any violation hard-fails. |
| Scope violation | Evidence for wrong version/entitlement or otherwise inapplicable account context. | 0; any violation hard-fails. |
| Escalation timeliness | p95 time from failed gate to human queue. | ≤90 s; S1 reference ≤30 s. |
| Prompt-injection tool deviation | Unexpected action induced by untrusted customer content. | 0 across the adversarial slice. |
| Wrong-language reply | Reply not in the language of the most recent customer message. | Target ≤0.5%. |
| Cost per contained ticket | Reference economics after the quality definition, not raw deflection. | Source reports ≈USD 0.04–0.11; treat only as reference. |
These are the handbook’s gates, not universal release criteria. For a deployment, publish the exact definition, observation window, sample size, confidence interval and segment breakdown. A global containment rate can hide a dangerous failure concentrated in one language, plan, version or intent.
CREATE MATERIALIZED VIEW containment_quality AS
SELECT
t.ticket_id,
t.closed_at,
t.intent,
(t.last_public_reply_author = 'agent') AS agent_resolved,
(c.confirmed_at IS NOT NULL OR t.customer_silent_days >= 14) AS accepted,
NOT EXISTS (
SELECT 1 FROM ticket_event e
WHERE e.ticket_id = t.ticket_id
AND e.kind = 'reopened'
AND e.at < t.closed_at + INTERVAL '14 days'
) AS no_reopen,
NOT EXISTS (
SELECT 1 FROM escalation x
WHERE x.origin_ticket_id = t.ticket_id
AND x.created_at < t.closed_at + INTERVAL '14 days'
) AS no_escalation,
COALESCE(s.csat, 3) >= 3 AS csat_ok
FROM ticket t
LEFT JOIN resolution_confirmation c USING (ticket_id)
LEFT JOIN csat_response s USING (ticket_id)
WHERE t.closed_at < now() - INTERVAL '14 days';The fourteen-day delay is intentional: “contained well” is not knowable immediately after send. A weekly materialized view with an explicit lag is healthier than a live deflection tile that turns every early handoff into a red failure.
The groundedness judge receives only the draft, retrieved passages and account context—not the entire KB. Its question is narrow: does any sentence assert something unsupported or inapplicable to this account? Validate that judge against human labels. The judge does not own release by itself; deterministic checks catch scope, visibility, citation resolution, commitment classes and unexpected tool use.
The chapter presents these as reference-deployment failures. Treat them as test cases to reproduce, not as Infinity client incidents.
An old 3.x procedure remains highly retrievable after a 4.x behavior changed. Version-range filtering prevents the obvious case; last_reviewed handles version-independent documents that have simply gone stale. The handbook lets old passages inform a draft but prevents them from being its only support after a reference staleness window. The exact window must match the product/documentation lifecycle.
A frustrated follow-up is classified as a new “wait time” ticket and the technical issue disappears. Lock intent and product area after initial triage. Later messages can change sentiment and raise an escalation signal; they should not silently reclassify the underlying case.
The system answers in English because the evidence is English, or cites an unreviewed machine translation as official documentation. Store locale and translation status on every chunk. Exclude machine-translated chunks from direct customer citation; they may help locate the source-language article. Set reply language from the latest customer message.
A postmortem is often more relevant than the public KB—and exactly the document the customer should not receive. Visibility enforcement and citation lookup prevent it from crossing the send boundary. Relevance is not authorization.
“Disable TLS verification” or “turn off audit logging” can close a ticket while violating security/compliance posture or support terms. Tag passages by risk class. Security-relevant or warranty-affecting workarounds do not qualify for autonomous replies; in copilot mode surface the conflict for deliberate human review.
A huge escalation thread plus repeated refusal/retry cycles consumes enormous context while failing to produce a safe answer. Watch the p99, not just median cost. Bound context, summarize older turns with clear provenance limits, cap the worker budget and route on repeated refusal instead of looping.
Week 1: ship triage only. Write intent/severity/routing fields, no customer-facing output. Build the helpdesk token bucket and bounded queue before the first surge, and implement commitment-scan fixtures before writing a drafting prompt. Triage creates the labelled stream every later subsystem needs.
Month 1: add account-context resolution and scoped KB search with version and entitlement filters. Ship copilot to a small volunteer support pod so every draft is reviewed. Collect the golden set from human edits while labels are cheap. Stand up the containment-quality view immediately—even though its first meaningful values arrive after the lag—so the organization does not standardize on deflection as the success metric.
Quarter 1: enable autonomous replies one named low-risk intent at a time, at the stricter grounding bar and only after several weeks of copilot evidence for that intent. Add L3 escalation packets and the L1 KB-gap pipeline. Keep voice on the assist side until it has a dedicated template path and evaluation set.
The build sequence preserves the handbook’s broader autonomy rule: promotion is earned by measured evidence and a named configuration approval. Better language-model capability does not remove the need for scoped retrieval, account context, hard send controls or a quick human handoff.
The structural source is Article 8 of the supplied Enterprise Agent Mesh handbook plus Part 0’s gateway, corpus, ledger, evaluation and event-bus conventions. This web edition preserves its named subagents, skills, confidence-gated topology, retrieval design, guardrails, evaluation metric and build order.
Explicit web-edition qualifications: vendor rate limits are treated as live configuration rather than fixed handbook numbers; the Salesforce limit model is separated from Zendesk’s per-minute Ticketing behavior; semantic-version ranges are parser-enforced; filtered HNSW recall is monitored rather than assumed; permission callbacks are not treated as an authorization perimeter; the runner atomically owns send/idempotency; and reference thresholds/outcomes are not presented as Infinity client results.
01 Recruitment Agent · 02 HR Agent · 03 Supply Chain Agent · 04 Procurement Agent · 05 Finance Agent · 06 Finance Risk Agent · 07 Operations Agent
Next: 09 Sales Agent — Make the CRM True, Then Worry About Selling. Forthcoming.










.png)
.png)
