Skip to content
Harness Engineering2026-10-028 min read

Test an Agent's Fallback Path Against the Same Acceptance Bar

A fallback model runs rarely, so production traffic barely measures it and the aggregate hides it. Derive why, then force failover on your eval set and grade the fallback against the primary's contract.

Key takeaways

  • Overall acceptance is a weighted average, a·p_primary + (1 − a)·p_fallback, so a fallback that engages 2% of the time barely moves it, however badly it performs.
  • At 2% engagement, 10,000 requests give the fallback about 200 natural trials, and those arrive clustered in outages, not as a random sample.
  • Force failover on the eval set instead: about 246 to 384 cases pin a fallback's acceptance rate to within five points.
  • A fallback answer that parses is not accepted; it must meet the same case-specific rule as the primary, including stopping when data is missing.
  • Retry discipline and answer quality are separate requirements; bounded retries do not make a fallback's answers correct.

Rod Rivera

Author

Test an Agent's Fallback Path Against the Same Acceptance Bar

Rod's note: read with a pencil; the margins are for you.

The fallback that parses and still fails

An agent reads papers and technical reports and fills rows in a team's comparison table. Its primary model is rate limited during a busy afternoon, so the harness falls back to a smaller model. The fallback returns this row:

json
{"benchmark": "long-context-qa", "metric": "accuracy", "value": 0.713, "status": "ok", "source_ref": null}

It is valid JSON with the right keys. A dashboard that checks "did we get a well-formed row" shows green. But the paper never reports that benchmark. The number 0.713 came from nowhere. If it lands in the comparison table, it looks exactly like a measured result, and someone may cite it in a design review.

The primary configuration is required to answer needs_data when the paper does not contain the number. The fallback is held to the same rule. Switching models does not change what counts as an acceptable row. A degraded mode can promise less, such as "draft only, never written to the table", but that promise has to be declared and tested. It does not follow from the switch.

This article is about the evaluation problem underneath: a fallback runs rarely, so the usual measurements barely see it.

Why production traffic cannot measure a fallback

Let a be the fraction of requests the primary handles, p1 the primary's acceptance rate and p2 the fallback's. Every request goes to exactly one path, so the overall acceptance rate is a weighted average:

text
P(accepted) = a · p1 + (1 − a) · p2

Put in numbers. These are illustrative, chosen to show the arithmetic: the primary handles 98% of requests and is accepted 94% of the time; the fallback is accepted 70% of the time.

text
P(accepted) = 0.98 × 0.94 + 0.02 × 0.70 = 0.9212 + 0.0140 = 0.9352

The fallback drops overall acceptance from 0.94 to 0.935. Half a point. If the fallback accepted nothing at all, overall acceptance would be 0.921. A dashboard that tracks the aggregate cannot tell a decent fallback from a useless one.

The sample is the second problem. At 2% engagement, 10,000 requests give the fallback about 200 trials. Those trials are not a random sample of your work. They arrive clustered in outages and rate-limit spikes, when traffic is unusual and other dependencies may be degraded too. A fallback measured only in production is measured late, on a biased sample, and diluted in the average.

The same arithmetic runs through a whole day

Chapter 20 of the book applies the product rule to a day of steps: twelve steps at 99% each succeed together only about 88.6% of the time. A fallback is one more branch inside one of those steps. If it is weak, it lowers that step's reliability on exactly the days you can least afford it.

Force failover on the eval set

Measure the fallback directly. Run your eval set with the primary disabled, so every case goes through the fallback path: same inputs, same tools, same grader.

How many cases? To estimate an acceptance rate p to within ±5 points at 95% confidence, solve 1.96·√(p(1−p)/n) = 0.05 for n:

text
n = 1.96² · p(1 − p) / 0.05²
p = 0.5:  n = 3.8416 × 0.25 / 0.0025 ≈ 384
p = 0.8:  n = 3.8416 × 0.16 / 0.0025 ≈ 246

So a few hundred cases pin the fallback down. That is a normal eval run, and it takes an afternoon rather than months of waiting for outages. If a forced-failover run accepted 140 of 200 cases, the 95% Wilson interval would be 0.633 to 0.759. Chapter 16 derives that interval and explains why it behaves better than the textbook one near 0 and 1.

Grade each case against the rule for its family, decided before you run anything:

Case familyInput conditionRequired behavior
Reported metricThe paper reports the benchmark and metricCorrect value with a source reference, status: ok
Missing metricThe paper does not report itstatus: needs_data, no value
Held-out splitThe request asks for numbers from the team's reserved test splitstatus: refused, citing the rule

Report each family separately. The fixture above fails the missing-metric family even though it parses, because the required status is needs_data and the actual status is ok. A grader that only checks parseability passes it.

Grade the fallback against the shared contract. Eval case; Primary disabled: fallback path; Row produced; Check against the family's rule; Accept: ok, needs_data or refused; Reject: invented value or wrong status
Grade the fallback against the shared contract

Before trusting the grader, give it controls. A needs_data row with no value must be accepted in the missing-metric family; change only its status to ok and the verdict must flip. This checks the grader's decision boundary without calling any model.

A fallback admitted under an operation ID is validated by case, arbitrated to one terminal result, and recorded with the configuration that produced it.. Primary unavailable; Fallback admitted under operation ID; Case-specific validation; Arbitrate one terminal result; Primary recovers while fallback runs; Record winning configuration and disposition
A fallback admitted under an operation ID is validated by case, arbitrated to one terminal result, and recorded with the configuration that produced it.

Compare the fallback to the primary, pair by pair

You now have two graded runs over the same cases: primary and forced fallback. Compare them case by case, as in the routing study. The cases both pass or both fail say nothing about the difference. The discordant cases do: those only the primary passes show what failover costs you, and they tell you which family to restrict.

Three outcomes are common:

  • It meets the bar on every family: ship it as a true fallback.
  • It meets the bar on reported metrics but fabricates on missing ones: restrict the degraded mode. Let it draft reported-metric rows for review, and send missing-metric cases to a queue instead of the table.
  • It fails the held-out-split rule: that rule should not depend on a model in the first place. Move the permission check into code that runs before either model sees the request.

The book's Chapter 14 measured another fallback-specific failure: a model that answers in words instead of calling a tool. In its runs, every model did it sometimes, from 5 to 33 times in 216 native answers. In an agent loop, a text answer ends the turn, so a weaker fallback can quietly skip the lookup that would have told it the metric is missing. Count answers with no tool call as their own row in the fallback's results.

Retry discipline is not answer quality

AWS's Well-Architected guidance on retries covers bounding them, backing off with jitter and not multiplying attempts across layers (AWS Well-Architected Framework, "Control and limit retries," https://docs.aws.amazon.com/wellarchitected/2023-04-10/framework/rel_mitigate_interaction_failure_limit_retries.html). That is good engineering for the mechanics of failing over. It says nothing about whether the fallback's answers are right once it engages.

A forced-failover protocol you can run

Freeze the families and rules

Write the acceptance rule for each case family before you run either configuration. Deciding after seeing outputs invites you to accept a bad answer.

Size the run

Use n = 1.96² · p(1 − p) / 0.05² for ±5 points. Budget about 250 to 400 cases for the fallback, reported by family.

Run primary and forced fallback on the same cases

Disable the primary in the harness, not by waiting for an outage. Record configuration identity, tool access, raw output, tool calls and the graded verdict for each case.

Read the discordant cases

List the cases the primary passes and the fallback fails. Group them by family. That list decides whether to ship, restrict or redesign the fallback.

Test recovery and overlap

Bring the primary back mid-run and check that each case resolves to one attributed terminal result. Add cases where two conditions overlap, such as a missing metric on a held-out-split request, and decide in advance which status wins.

Anthropic's engineering writeup on agent evaluation makes the general case for this structure: separate tasks, trajectories and outcomes, and grade with domain-specific criteria rather than one aggregate score (Anthropic, "Demystifying evals for AI agents," https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents). A fallback changes the configuration answering the task. The task's criteria stay the same.

Quick check — A fallback engages on 2% of requests. Overall acceptance is 0.935 with the fallback and would be 0.94 if the primary handled everything. What can you conclude about the fallback's quality?

Check the decision

Why this matters in a lab

Research and applied teams run agents against rate-limited APIs, shared inference clusters and preview models that come and go. Fallbacks are everywhere, and they fail when the system is already stressed. A team that owns an agent in production will expect you to know that a rarely used path is barely measured by traffic, that its failures hide in the aggregate, and that the fix is a designed experiment: force the condition, size the sample, grade against the same contract. An interviewer might ask, "Your fallback model has never caused an incident. Is it safe?" The answer starts with the weighted average and ends with a forced-failover run.

What would prove this wrong

If your fallback engages often, say a third of the time, production traffic measures it well and the aggregate reflects it; the argument here is about rare paths. If your eval set does not resemble outage-time traffic, a forced-failover run on it can pass while real failover fails; add cases drawn from past incidents. And if the fallback is nondeterministic, one pass per case is one trial. Repeat the missing-metric family, knowing from Chapter 16 that repeats measure variability on a case, not new cases.

Read Chapter 16: error bars and paired comparisons

Build the Wilson interval, the sample-size calculation and McNemar's test from first principles, then apply them to a real model run.

Learn the mechanism. Test the claim.

Join the Prof Rod newsletter for one educational lesson a week, with worked examples attached. It is free to register for and separate from the Zero Employee community.