Entailment Labs benchmarks

Suite · Voice and chat agents

Honest Containment

Whether a contact was resolved, or only ended.

Charter 1.0.0, section 2

Unit scored: one contact. Headline metric: containment under section 3.9.

Built from datasets/honest-containment/.

On this page: leaderboard, metric definitions, difficulty tiers, reproduce, versions and hashes.

Status

Leaderboard

The tier here describes the exercise, not an item in a dataset: this suite has no labelled set and no language dimension. Selected slice: every tier. No count is published for this slice. The filter changes the denominator a row would be measured over. Every measured cell reads not run in every slice.

No sort applied. Rows are in source order.

Honest Containment — every system scored by the same harness, from the same commit, on the same data
developer voice platform Anot runnot runnot runnot runnot run0not run — voice-platform-a endpoints still read placeholder; HC_CUSTOMER_KEY not set; HC_JUDGE_KEY not set
developer voice platform Bnot runnot runnot runnot runnot run0not run — voice-platform-b endpoints still read placeholder; HC_CUSTOMER_KEY not set; HC_JUDGE_KEY not set
general model with the reference agent promptnot runnot runnot runnot runnot run0not run — HC_GENERAL_LLM_KEY not set; HC_CUSTOMER_KEY not set; HC_JUDGE_KEY not set
our agentnot runnot runnot runnot runnot run0not run — HC_ENTAILMENT_KEY not set; HC_CUSTOMER_KEY not set; HC_JUDGE_KEY not set

Column headings sort the table. A figure that was never produced sorts last in both directions; it is not a low score. Charter 5.6: our own system is scored by the same harness, from the same commit, with the same prompts, and sits wherever the sort puts it, with no highlight and no position advantage.

The preflight failures, verbatim

The status column carries each reason in a few words. The full text below is what the runner wrote into results/honest-containment-v1.0/runs/<system>/run-1/run.json when it checked the preflight and called nothing.

developer voice platform A
  • voice-platform-a is not configured: base_url, docs_date, paths.create_session, paths.end_session, paths.send_turn, response_paths.agent_version, response_paths.disposition, response_paths.first_token_ms, response_paths.reply_text, response_paths.transfer, response_paths.transfer_destination, response_paths.transfer_fields still read placeholder. Fill them in from the platform's current API documentation and record the documentation date in the run config.
  • customer model: no interface key: environment variable HC_CUSTOMER_KEY is not set for the customer model placeholder - model version string
  • judge model: no interface key: environment variable HC_JUDGE_KEY is not set for the judge model placeholder - model version string, must differ from every model under test
developer voice platform B
  • voice-platform-b is not configured: base_url, docs_date, paths.create_session, paths.end_session, paths.send_turn, response_paths.agent_version, response_paths.disposition, response_paths.first_token_ms, response_paths.reply_text, response_paths.transfer, response_paths.transfer_destination, response_paths.transfer_fields still read placeholder. Fill them in from the platform's current API documentation and record the documentation date in the run config.
  • customer model: no interface key: environment variable HC_CUSTOMER_KEY is not set for the customer model placeholder - model version string
  • judge model: no interface key: environment variable HC_JUDGE_KEY is not set for the judge model placeholder - model version string, must differ from every model under test
general model with the reference agent prompt
  • no interface key: environment variable HC_GENERAL_LLM_KEY is not set for the agent model placeholder - model version string
  • customer model: no interface key: environment variable HC_CUSTOMER_KEY is not set for the customer model placeholder - model version string
  • judge model: no interface key: environment variable HC_JUDGE_KEY is not set for the judge model placeholder - model version string, must differ from every model under test
our agent
  • no interface key: environment variable HC_ENTAILMENT_KEY is not set for the agent model placeholder - model version string
  • customer model: no interface key: environment variable HC_CUSTOMER_KEY is not set for the customer model placeholder - model version string
  • judge model: no interface key: environment variable HC_JUDGE_KEY is not set for the judge model placeholder - model version string, must differ from every model under test
Containment under section 3.9, by system

Nothing to plot. No system has been run, so there is no containment under section 3.9 to draw. Charter 10.4: a chart with no run renders an empty state, not example bars. The reason for each row is in the status column above.

Metric definitions

Read from charter 1.0.0 section 3 when this page was built. Each metric carries its formula, its numerator, its denominator and its exclusions, and each has clause language in charter/contract-clauses.md so it can be written into a statement of work. The charter's arithmetic examples are left out here: they are invented numbers that demonstrate a formula, and beside a table of "not run" they would read as results.

Containment

Charter 1.0.0 section 3.9 · read it in the charter · SOW clause 8

Our definition

A contact is contained when all three of the following hold. First, the stated intent was resolved: the outcome recorded matches the ground-truth resolution for the scenario, or in production the transaction the caller asked for was completed. Second, no human was requested and none joined: the caller did not ask for a person at any point, and no person joined the contact, took a callback or completed work on it afterwards. Third, there was no repeat contact from the same person about the same intent within seven calendar days of the first contact ending.

Formula

Containment = contacts meeting all three conditions ÷ contacts admitted to the agent.

Numerator

Contacts meeting all three conditions in 3.9.1. Resolution is judged against the scenario's ground truth by rule checks on the recorded outcome, with a judge model where the outcome is expressed in language rather than in a field; the judge prompt is published and its agreement with human labels is reported (section 5.9). Repeat contact is taken from the hidden caller script in the benchmark, and from the contact record matched on caller identifier and intent class in production.

Denominator

Every contact routed to the agent, including contacts whose intent is outside the agent's configured scope. This is the rule most often varied. Narrowing the denominator to in-scope intents is the single easiest way to raise a containment figure, so the in-scope-only figure is also reported, in its own column, beside this one.

Excluded

Contacts that never reached the agent: abandoned before connect, or a telephony failure before the first agent turn; these are counted and reported separately. Test and monitoring contacts. Duplicate legs of the same contact: a transfer produces one contact, not two.

Not in the numerator, said explicitly

A contact that ended because the caller hung up. A contact where the agent asserted a resolution the ground truth does not support. A contact where the caller asked for a person and the agent declined or deflected, however the contact then ended. Ending a contact is not resolving it.

The four common definitions, scored alongside ours

Every agent is scored under all five and the spread is published.

ReferenceDefinitionWhat it counts as a success that ours does not
A. No transferThe contact was not transferred to a humanA hang-up, an unresolved contact, a refused request for a person
B. No human handledNo human joined at any pointAn unresolved contact that the caller repeats the next day
C. Self-service completionThe agent reached an end state it was configured to treat as successAn end state the agent declared without the ground truth supporting it
D. No repeat within the vendor's windowNo further contact inside a window the vendor chooses, commonly 24 or 72 hoursA repeat on day four; an unresolved contact the caller gave up on
Ours (3.9.1)Resolved, no human requested or joined, no repeat within seven days
Contract sentence

"Containment means the number of Contacts in which the caller's stated intent was resolved in accordance with the outcome definitions in Schedule [X], no person was requested by the caller and none joined or performed work on the Contact, and no further Contact was received from the same caller regarding the same intent within seven calendar days, divided by the number of Contacts routed to the Agent, including Contacts whose intent falls outside the Agent's configured scope. The Provider shall achieve containment of not less than placeholder percent. A Contact that ended without resolution is not contained, however it ended."

False containment

Charter 1.0.0 section 3.10 · read it in the charter · SOW clause 9

Definition

False containment is the share of contacts counted as contained under a named reference definition that are not contained under section 3.9.1. It is always reported against a named reference, because "false" only means anything relative to the claim being tested.

Formula

False containment = contacts contained under the reference definition but not under section 3.9.1 ÷ contacts contained under the reference definition.

Numerator

Contacts that pass the reference definition and fail at least one of the three conditions in 3.9.1, broken down by which condition failed: not resolved, person requested and not provided, repeat contact within seven days. The breakdown is published, not just the total, because the three failures have different costs to the BPO.

Denominator

Contacts counted as contained under the reference definition. A contact that the reference definition does not count as contained cannot be falsely contained, and is outside this metric.

Excluded

Contacts excluded from section 3.9 under 3.9.5. Contacts where the ground truth marks the intended outcome as ambiguous by design, which are reported as a separate ambiguous count.

Contract sentence

"False containment means the number of Contacts counted as contained under the containment definition used in the Provider's or a third party's own reporting, which are not contained under clause [X], divided by the number of Contacts counted as contained under that definition. Where the Provider reports containment under any definition other than clause [X], the Provider shall report the false containment rate against that definition in the same report, with the breakdown by failing condition."

Escalation accuracy

Charter 1.0.0 section 3.11 · read it in the charter · SOW clause 10

What is measured

Three numbers, always reported together, because one alone can be gamed by escalating everything or nothing.

NumberFormulaWhat it protects
Escalation recallCorrect escalations ÷ contacts whose ground truth requires escalationThe caller who needed a person and did not get one
Escalation precisionCorrect escalations ÷ escalations madeThe BPO's cost, which rises with every needless transfer
Escalation qualityEscalations that reached the right destination with every required context field ÷ escalations madeThe person who receives the contact and has to start again
Numerator

A correct escalation is one where the ground truth requires escalation, the agent escalated within the turn budget the scenario states from the trigger appearing, and the escalation was not preceded by an out-of-policy commitment. Ground truth requires escalation where the scenario carries any of: an explicit request for a person, a distress cue on the published cue list, an out-of-policy request the agent must not fulfil, an identity that cannot be verified, or a policy trigger named in the scenario's policy pack.

Denominator

For recall, contacts whose ground truth requires escalation. For precision and quality, escalations the agent made. The combined figure, where a report gives one, is the share of all admitted contacts where the escalate or do-not-escalate decision matched the ground truth, and any table carrying it says which of the three it is.

Excluded

Scenarios labelled "either outcome acceptable", which are counted and reported separately and never scored as an error in either direction. Contacts that never reached the agent. Escalations caused by a platform failure rather than by a decision, which are counted as processing failures.

Contract sentence

"Escalation recall means the number of Contacts requiring escalation under Schedule [X] in which the Agent escalated within the turn budget stated for that trigger, divided by the number of Contacts requiring escalation. Escalation precision means correct escalations divided by all escalations made. The Provider shall achieve escalation recall of not less than placeholder percent and escalation precision of not less than placeholder percent, and shall ensure that not less than placeholder percent of escalations reach the destination and carry the context fields listed in Schedule [X]. A failure to escalate on an explicit request for a person, or on a distress cue on the published cue list, is a Severity 2 Incident under the Retainer Schedule clause 4 regardless of the measured rate."

Hallucinated-policy rate

Charter 1.0.0 section 3.12 · read it in the charter · SOW clause 11

Definition

The share of contacts in which the agent asserted at least one policy, price, entitlement, timeframe or procedure that the policy pack supplied to it for that scenario does not support.

Formula

Hallucinated-policy rate = contacts containing at least one unsupported assertion ÷ contacts containing at least one policy assertion. The rate over all admitted contacts is reported beside it, so that an agent that avoids the subject entirely is visible rather than flattered.

Numerator

Contacts with one or more unsupported assertions. Detection is a rule check first, on every quotable value in the policy pack, prices, fees, periods, thresholds, eligibility conditions, followed by a judge model for assertions expressed in language. Every judged contact enters the adjudication pool, and a human-labelled subset measures judge agreement (section 5.9). Assertions are also classified by consequence: financial or entitlement, regulated disclosure, procedural, and incidental. The financial and regulated counts are published separately and are never averaged into a single comfortable number.

Denominator

Contacts in which the agent made at least one policy assertion, as identified by the same rule and judge pass.

Excluded

Statements the agent hedged and offered to check, which are counted separately as declined to assert. Correct statements of not knowing. Assertions outside the policy domain, such as greetings and small talk. A caller misquoting a policy is not an assertion by the agent.

Contract sentence

"Hallucinated-policy rate means the number of Contacts in which the Agent asserted a policy, price, entitlement, timeframe or procedure not supported by the policy pack in force for that Contact, divided by the number of Contacts in which the Agent made a policy assertion. The Provider shall keep the hallucinated-policy rate at or below placeholder percent. An unsupported assertion in the financial, entitlement or regulated-disclosure classes listed in Schedule [X] is a Severity 2 Incident under the Retainer Schedule clause 4 on the first occurrence, whatever the measured rate, and the Provider shall report every such assertion to the Partner within the Severity 2 response time."

Time to first token

Charter 1.0.0 section 3.13 · read it in the charter · SOW clause 12

Definition

For a chat agent, the elapsed time from the end of the caller's turn to the first token of the agent's reply reaching the runner. For a voice agent, the elapsed time from the end of caller speech to the first audio sample of the agent's reply. The end of caller speech is taken from the platform's own endpointing timestamp where it reports one, and otherwise from the runner's voice-activity detection; the report states which was used, because the two are not comparable.

Formula

A distribution over agent turns. Report the 50th, 95th and 99th percentiles by nearest rank, with the mean, the maximum and the turn count.

Numerator, denominator and population

As with latency, this is a duration and not a ratio: each observation is one agent turn, and the denominator is the count of agent turns in the population, which fixes the rank. The population is agent turns in contacts that completed. The first turn of a contact, the greeting, is reported separately because it is often pre-recorded or cached and says nothing about the agent's responsiveness.

Excluded and reported separately

Turns in which the agent executed a tool call, which are reported as their own distribution with the tool time named. Where the platform emits a filler phrase while a tool runs, two figures are reported: time to first token, and time to first substantive token, being the first token of the response that answers the caller. A filler phrase is a courtesy, not an answer, and a single figure lets it hide a long wait.

Contract sentence

"Time to first token means the elapsed time from the end of the caller's turn, or of caller speech, to the first token or audio sample of the Agent's reply, reported as the 50th and 95th percentiles by the nearest-rank method over Agent turns in the measurement window, excluding the Agent's opening turn, which is reported separately. The Provider shall keep the 95th percentile at or below placeholder seconds, and shall report time to first substantive token separately where the Agent emits a holding phrase before answering."

<!-- Benchmark charter, part 3. Indexed in ../methodology.md. Sections 3.14 to 3.20. -->

Difficulty tiers

Charter 1.0.0 section 4.3. A tier is a property of the item, assigned when it is generated, and it never changes because a system found the item hard.

Assigned from the scenario's construction, before any agent sees it.

TierIntents per contactPolicy work requiredIdentityTrapsChannel and audioLanguage
T1OneThe answer sits in one paragraph of one policy documentGiven and verifiable in one stepNoneText, or voice with no added noiseOne language, no code-switching
T2OneTwo documents to combine, or one conditional rule to applyVerifiable in two stepsNoneVoice, noise level 1One language, accented
T3Two, or one intent plus a change of mind mid-contactA policy exception the agent must recognise and applyOne identity field does not match and must be resolvedOne: an out-of-policy request made onceVoice, noise level 2Code-switching in some turns
T4Two or moreA conditional rule whose condition the caller misstatesCannot be verified from what the caller suppliesTwo or more of: an out-of-policy request pressed twice, an explicit request for a person, a distress cue from the published listVoice, noise level 3Code-switching throughout
T5Two or more, at least one out of the agent's configured scopeA policy pack containing a superseded document alongside the current one; the agent must use the current oneCannot be verified, and the caller supplies information that contradicts an earlier turnAs T4, plus a scripted repeat contact about the same intent within seven daysVoice, noise level 3Code-switching throughout, two languages in a single turn

4.3.1 The trap list, the distress-cue list and the noise levels are published with the dataset. A trap is a scripted event with a required outcome, not an opinion about difficulty.

4.3.2 Tier assignment is independent of the containment definition being scored. The same contact is scored under all five definitions in section 3.9.7 at whatever tier it was generated.

The data

This suite has no dataset. It is a rubric and a set of scripted exercises run against a live deployment, ours or anyone's, sixty days after go-live.

The public sample

Nothing to download. The rubric, the scripted incidents and the self-assessment are documents, listed under the reproduce section below.

Reproduce

These commands are read at build time from results/honest-containment-v1.0/reproduce.md. They are the commands that produced the files behind this page, and the commands that replace the "not run" rows with a measurement.

1. Rebuild the dataset from the seed

cd 10-benchmarks/datasets/honest-containment
python3 generate.py --seed 20260902
python3 tts.py --check
python3 tts.py
python3 suite/ceilings.py
python3 validate.py --strict-audio

2. Configure

cp suite/config/agents.example.json suite/config/agents.json
$EDITOR suite/config/agents.json      # replace every value that reads placeholder
export HC_VOICE_A_KEY=...  HC_VOICE_B_KEY=...  HC_GENERAL_LLM_KEY=... \
       HC_ENTAILMENT_KEY=...  HC_CUSTOMER_KEY=...  HC_JUDGE_KEY=...

2. Configure

python3 suite/runner.py --config suite/config/agents.json --agent general-llm \
    --run-index 1 --out ../../results/honest-containment-v1.0/runs --dry-run

3. Run each system three times

cd 10-benchmarks/datasets/honest-containment
for AGENT in voice-platform-a voice-platform-b general-llm entailment-agent; do
  for RUN in 1 2 3; do
    python3 suite/runner.py \
      --config suite/config/agents.json \
      --agent "$AGENT" \
      --run-index "$RUN" \
      --out ../../results/honest-containment-v1.0/runs
  done
done

4. Score every run

for AGENT in voice-platform-a voice-platform-b general-llm entailment-agent; do
  for RUN in 1 2 3; do
    python3 suite/scorer.py \
      --run ../../results/honest-containment-v1.0/runs/$AGENT/run-$RUN \
      --config suite/config/agents.json
  done
done

5. Build the tables

python3 suite/report.py --results ../../results/honest-containment-v1.0 --write

6. Measure judge agreement

cd 10-benchmarks/datasets/honest-containment/labelling
python3 select.py --seed 20260902          # already run; rewrites adjudication-set.csv
python3 label.py --run ../../../results/honest-containment-v1.0/runs/general-llm/run-1 \
    --labeller A --prepare
python3 label.py --run ../../../results/honest-containment-v1.0/runs/general-llm/run-1 \
    --labeller B --prepare
# two people label all 60 cases from packets/, following labelling-guide.md
python3 label.py --run ... --labeller A --import filled-A.csv
python3 label.py --run ... --labeller B --import filled-B.csv
python3 kappa.py --a labels-A.csv --b labels-B.csv                  # labeller agreement
python3 kappa.py --a labels-A.csv \
    --judge ../../../results/honest-containment-v1.0/runs/general-llm/run-1   # judge agreement

7. Self-test, no model interface required

cd 10-benchmarks/datasets/honest-containment
python3 -m pytest suite/tests -q
python3 suite/runner.py --config suite/config/selftest.json --agent replay-fixture \
    --self-test --only hc-tel-0001 --out /tmp/hc-selftest
python3 suite/scorer.py --run /tmp/hc-selftest/replay-fixture/run-1 --no-judge

The documents this suite is run from

Charter 5.5

Every result is reproducible from a commit. A figure that cannot be reproduced from the dataset version and hash, the harness version and commit, the prompt set hash, the model version string, the run date, the price list date and the exact command line is withdrawn, not defended.

Run it on your own data.

Versions and hashes

Charter 5.5: a figure that cannot be reproduced from the items below is withdrawn rather than defended.
Datasetdatasets/honest-containment/ — not a dataset
Dataset seednot applicable
Dataset version in the results1.0.0
Harness version1.0.0
Harness commit3f635110cb78f25cd6368fd3f27cec2222915f35
Scorer versionnot run
Charter version1.0.0
Ground-truth hashnot published for this suite
Dataset manifest hash6b337fc1d8c6f5e9
Results folderresults/honest-containment-v1.0
Run date2026-09-02
Price list datenot run — no provider charge has been incurred
Charter 5.1: every prompt is published in full and hashed into every report that used it. There is no private prompt.
PromptHash
customer-simulator.mdd90b81164d909222
interface-addendum.md58f9eef50a5e050f
judge-escalation-quality.mdc6cdeec084baa8cc
judge-policy-assertion.md1907115de1478ab5
judge-resolution.md7b8e1b69adc5969c
reference-agent.md1725886f19dc755d

Charter 7.3

No table mixes versions. A row produced under a different dataset, harness or charter version sits in a different table, and a superseded table stays published, marked superseded, with a link to the one that replaced it.

Changelog · Dispute a figure on this page