Marketing

How Many Empty-Input Cases Your Regression Set Needs

Antonio Evans11 min read

A clean top-down diagram on a white background.
Key points

Key points

  1. 1A regression set built only from valid inputs never executes the fallback branches, so a broken refusal path can ship with a 100 percent pass rate.
  2. 2Treat empty and short inputs as their own stratum in the suite and size it from the number of distinct fallback branches, not from total volume.
  3. 3A practical floor is 12 empty and short cases, scaling at roughly 2 percent of total regression volume up to about 500 cases, then holding at 20 to 30 cases plus one per fallback branch.
  4. 4Hit every fallback branch at least three times so one flaky case cannot hide a regression.

Why a suite of good inputs never tests the fallback

Most regression suites grow from bug reports. A user pasted a valid order ID and got the wrong total, so you add that order ID. A customer used a 400 character product name, so you add a long name. The cases accumulate around the behavior that worked and then broke, which means they are almost all valid inputs. Nothing in that history pushes a test toward an empty string, a single space, or a three character fragment.

The fallback path is the code that runs when the primary path cannot proceed. In an LLM pipeline a fallback is any secondary instruction or code path invoked when the primary call fails to produce an acceptable output, where "acceptable" is defined by your schema, safety policy and task success criteria rather than by whether the model returned text at all (MLflow's fallback guidance). A model can return fluent, confident text that still violates your contract, which is why fallback triggers need to be explicit rather than a vague error check.

That definition matters for sizing. A fallback branch is not "the error handler". It is each distinct place where your code, prompt or orchestration layer decides that the input is not good enough and takes a different route. Critically, well-written system instructions usually include an explicit rule for what to do when information is missing, alongside role, boundaries, output rules and escalation logic (Promptessor's anatomy of a system prompt). Every one of those instructions is a branch, and every branch is a code path with no test until you write one.

There is a second reason fallbacks escape testing. Negative testing, the discipline that checks how a system responds to invalid input and adverse conditions, is the half of QA that quietly gets skipped because the happy path is easier to write, easier to demo and easier to sign off (Virtuoso QA on negative testing). The result is a familiar catalogue: a registration page that throws a server error on an address with no domain, a search field that falls over when someone types an emoji. None of those show up in a pass rate built only on valid inputs.

Count branches before you count cases

The number you need is driven by branches, not by volume. Before writing a single empty string test, sit with the code and the prompt and list every distinct way the system can reject, default or degrade on empty or short input. A useful starting inventory for an LLM-backed feature looks like this:

  • Input truncated to zero characters before the request is built.
  • Whitespace-only input that passes a naive length check.
  • Input below a minimum length enforced in application code, not by the model.
  • Input below a minimum length enforced only by prompt instruction.
  • Schema validation failure on the model's structured output.
  • Model refusal, where the response contains a refusal field rather than content.
  • Tool call that returns empty and needs a degraded data source.
  • Retrieval that returns no documents above a similarity threshold.
  • Timeout or provider error that should route to a static message.
  • Human handoff trigger for low confidence or safety-sensitive tasks.

The distinction between static, structured, model and tool fallbacks matters because each costs different latency and money, and static and structured fallbacks belong in almost every pipeline while model fallback and human handoff should be reserved for cases where a wrong answer is worse than a slow one (MLflow). Your empty-input stratum should cover the cheap ones exhaustively and sample the expensive ones deliberately.

If your feature extracts fields from documents, the branch count explodes in a useful way. A fallback field fires when a field returns an empty array, null or undefined, but does not fire when it returns an empty string or zero, and fallbacks can chain from a layout method to a model prompt and back (Sensible's fallback field docs). Each chain link is a branch. Read the config and count them, because that document alone shows at least three distinct branch types for one logical field.

Once you have a list, mark each branch as reachable by empty input, by short input, by both, or by neither. The ones marked "by neither" need a different stratum entirely and should not inflate this count. The ones marked empty or short form your denominator.

The sampling rule, with numbers

The rule has three parts: a floor, a scaling band, and a cap that flips to branch-driven.

Floor. Plan for a minimum of 12 empty and short inputs. This is not arbitrary. Boundary value analysis, the standard technique for testing at the edges of an input domain, typically probes the minimum, one value just above it, a nominal value, one just below the maximum, the maximum, and invalid values outside the range on both sides (Virtuoso QA on boundary value analysis). For a length domain whose minimum is zero, that gives you the empty case, a one character case, a nominal case, a just-below-maximum case, the maximum case and the over-maximum case. Run that set twice, once through the application layer and once through the prompt layer, and you have 12. If you have fewer than 12 because your domains are narrow, keep the 12 anyway; they will not be wasted.

Scaling band. Above the floor, scale the stratum at roughly 2 percent of the total regression volume, up to about 500 cases. The reason is proportional rather than statistical: a suite that is 2 percent edge cases will surface a broken fallback within one or two runs of any change that touches input handling, while a suite that is 0.1 percent edge cases will hide it behind 999 happy paths that all pass. A 2 percent share survives aggressive additions of valid cases, which is exactly what happens over a suite's lifetime.

Cap. Past about 500 total cases, stop scaling by volume and hold at 20 to 30 cases plus one per distinct fallback branch. Beyond that point, extra empty strings mostly duplicate each other; extra branches do not. This is where the branch count takes over. If you have 14 fallback branches, your stratum is 34 to 44 cases regardless of whether your suite holds 600 or 6,000 cases.

Total regression volume2 percent bandApplied figureCase for the stratum
1002Floor wins12
3006Floor wins12
80016Floor wins16
1,20024Band wins24
2,00040Band wins40
20,000400Band wins400
30,000600Cap wins30 plus one per branch

The last row is the decision rule in one line: past the cap, volume stops mattering and branches take over. Teams that keep scaling edge cases linearly with volume spend most of their test budget re-proving that an empty string is still an empty string.

Hit every branch three times

Coverage of a branch is not the same as confidence in it. A branch that is exercised exactly once will look healthy until that one test flakes, and then a broken fallback reads as an infrastructure problem rather than a regression. Three executions per branch gives you a signal you can act on: if two of three pass and one fails, you are looking at nondeterminism or a flaky fixture, not a code change. If all three fail, you have a real break.

Three hits also lets you vary the input meaningfully without inflating the count. For a refusal branch, for example, the three cases might be an empty string, a whitespace-only string, and a short greeting that is well formed but carries no task. That spread catches the difference between "the model refused because there was nothing to do" and "the model refused because the input was malformed", which are different bugs with different fixes.

This is where prompt regression suites overlap with software regression suites. A structured test case needs an exact input, an expected output or a set of expected properties, and tags so you can run subsets such as edge_case or high_priority, and the recommended starting point is 20 to 30 representative cases with an edge case added every time a bug is found and fixed (MLJAR's prompt regression suite prompt). Note the phrase "every time a bug is found and fixed": your branch count is not static. Every production incident on a fallback path adds a branch and therefore adds three cases.

For the cheapest branches, exact match testing against a fixed string is fine, run at temperature zero for reproducibility. For branches where wording may vary, use properties instead: the response must contain a refusal field, must not contain a URL, must be under 40 words, must name the missing field. Property checks are more robust than exact match for outputs with legitimate variability, and the same source catalogues exact match, schema validation, semantic equivalence and property tests as the four available types.

A worked checklist you can run against your repository

Sizing is arithmetic; finding the branches is the work. This checklist turns the count into an afternoon.

StepWhat you doOutput
1Grep the codebase for length checks, null guards and empty-string comparisonsCandidate input branches
2Read the system instructions and list every "if information is missing" or escalation ruleCandidate prompt branches
3Read the output schema and note refusal fields, required fields, enum defaultsSchema branches
4Read the orchestration layer for retry, fallback model and human handoff conditionsInfrastructure branches
5Deduplicate and mark each branch empty, short, both or neitherFinal branch count
6Apply the sampling rule to size the stratumTarget case count
7Assign three inputs per branch, tagging each with the branch identifierWritten cases
8Wire the stratum into CI as a suite that runs on every change to input handling or promptsGate

Steps 1 to 4 are discovery and they nearly always produce more branches than the team expected. A pipeline with a primary model, one fallback model and a human handoff typically has at least six infrastructure branches before any content rule is counted, and a routing function that walks a fallback chain collects an error for each provider and returns a diagnostic string when all of them fail (a multi-model fallback walkthrough). Each provider in that chain and each error path is a branch.

Step 8 deserves emphasis. Run the edge stratum on every pull request that touches prompt text, validation logic or the orchestration layer, because that is precisely the set of changes that can break a fallback silently. A static fallback that shipped last month and passes today proves nothing about the version under review.

Choosing the content of short inputs

"Short" is a range, not a point. If your minimum length is not enforced anywhere, an empty-input case and a one character case may take the same path, and your three hits per branch collapse into one test with three spellings. Choose short inputs that straddle your actual decision points:

  • The empty string, which fails every length check.
  • A string of spaces, which passes a naive length check and fails a trimmed one.
  • One character, the first value above zero.
  • One character below the declared minimum.
  • The declared minimum itself, which should pass.
  • The declared minimum plus one, which catches an off-by-one in the comparison.

That last pair is where off-by-one defects live. A field specified as accepting input from 18 characters might be implemented as longer than 18 rather than at least 18, functionally equivalent in the developer's mind and different in behavior for the value 18 itself (Virtuoso QA). The same class of error appears in token budgets, message length limits and pagination offsets.

Where prompt text is the only enforcement, the short-input cases are your only evidence that the instruction works. Test the instruction with both beginner and expert inputs, and test with a request that lacks essential context, because a system prompt that is silent on missing information will produce a confident guess rather than a question (Coursiv's prompt guide). A prompt that says "if the question lacks essential context, ask a clarifying question" turns one branch into a testable one.

One more trap: few-shot examples in a prompt can make short inputs look better than they are. Demonstrations condition the model, and the label space and format of the examples matter for subsequent performance (the Prompt Engineering Guide on few-shot prompting). If your short-input cases accidentally match the shape of a demonstration, they test the demonstration, not the fallback. Deliberately break the shape.

Wiring the stratum into your pipeline

Once the cases exist, the operational questions are which model serves them, how you record results, and when a failing fallback blocks a release. For the routing question, a single API surface for text, image and embedding models removes a whole class of fallback branches around provider-specific SDKs, which is one reason teams consolidate on Quanta Inference. The stratum gets simpler to maintain when the provider is not part of the test matrix.

Recording results is where most teams lose the signal. Log which branch each case hit, not just pass or fail, so a decline in fallback health is visible as a metric rather than an inference. Monitoring fallback rate alongside task success, tool-error and latency metrics reveals degradation trends and masking issues early, and validating fallback prompts against golden sets before they reach users is the stated core rule (MLflow). A stratum of 30 cases with branch identifiers attached gives you a fallback rate per branch for free.

For teams without a test engineer on call, the work of excavating branches from prompts and code is a good candidate for delegation: an expert who reads your repository and returns a finished branch inventory and case table is a faster path than a sprint of internal archaeology, which is what Quanta Experts is built for. Whichever route you take, the deliverable is the same: a branch list, a case count derived from it, and three inputs per branch wired into CI.

The final decision rule, restated plainly: count branches, multiply by three, add a floor of 12, and let that total override any volume-based instinct once your suite passes about 500 cases. If the resulting number feels large, it is almost certainly smaller than the number of empty strings your users have already sent you.

FAQ

FAQ

Why is 12 the minimum rather than 10 or 20?

Twelve comes from running boundary value analysis across the two layers that matter, the application code and the prompt instructions. Boundary value analysis produces six values per length domain (empty, one above the minimum, a nominal value, one below the maximum, the maximum, and one above the maximum), as described in Virtuoso QA's guide, and doubling for two layers gives 12. Ten would force you to drop a boundary, and 20 would be arbitrary padding before you know your branch count.

What counts as a distinct fallback branch?

A distinct branch is any point where the system takes a different action because the input is empty, too short, invalid or unusable. That includes application-level length checks, prompt-level instructions to ask a clarifying question, schema validation failures, model refusals, tool calls returning nothing, and human handoff triggers. Each one is a separate route through the code and deserves three inputs of its own (MLflow).

Should empty and short inputs live in the same stratum?

Keep them together for sizing and tag them separately for running. They share the same purpose (exercising rejection and default paths) so one count is easier to manage, but a whitespace-only input and a zero-length input often take different code paths. Tags such as empty, whitespace and short_below_min let you run subsets in CI while keeping one target total.

How often should the stratum run?

Run the full stratum before every deployment and on every pull request that touches prompt text, validation logic, schemas or the orchestration layer. The standard pattern is to run critical tests on every such change and block deployment when the critical pass rate falls below 100 percent (MLJAR). Changes to unrelated styling or copy should not need it.

What if a fallback branch is genuinely unreachable?

Remove it or document why it stays. An unreachable branch usually means dead code or a defensive check that duplicates one above it, and both are worth deleting rather than testing. If you keep it for safety, test it anyway with the closest reachable input and note in the case description that the branch is defensive, so the next person does not spend an hour trying to trigger it.

Sources

Sources

  1. One post tagged with "fallback message examples"
  2. System Prompts: How They Work and How to Write Them
  3. Negative Testing Explained With Real-World Examples
  4. Fallback fields - Sensible
  5. What is Boundary Value Analysis in Software Testing?
  6. Prompt Regression Test Suite AI Prompt
  7. Building a Multi-Model AI Agent: Automatic Fallback When ...
  8. What is a System Prompt? A Practical Guide
  9. Few-Shot Prompting
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles