> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trunk.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Predictive testing

> Test PRs against the projected future state of your main branch to catch conflicts before they reach production.

## What it is

Trunk Merge Queue tests pull requests against the projected future state of your main branch, not just the current state.&#x20;

This means when multiple PRs are in the queue, each PR is tested as if all the PRs ahead of it have already been merged. This prevents "queue collapse" - where PRs pass tests individually but fail when merged together.

## Why use it

Normally, pull requests are tested against a snapshot of the head of `main` when the pull request is posted to your source control provider. This can mean that by the time the pull request is actually merged - the results of the automated testing are **stale**.

When you merge a pull request with stale results, you are effectively merging in **un-tested code**. The changes to the protected branch since the test was run create a blind spot in your testing regimen. With predictive testing, you no longer have a blind spot because the merge queue ensures that the pull request is tested against the state of `main` that will exist when your pull request is merged.

## What's Happening? The "Happy Path"

This example shows how pull requests (PRs) are tested in a queue. PR `B` is tested with the changes from `A`, and `C` is tested with the changes from both `A` and `B`.

<Frame caption="Test your pull request with the changes ahead of it in the queue">
  <iframe allow="autoplay; fullscreen; picture-in-picture; display-capture; clipboard-write" allowfullscreen="" allowtransparency="true" referrerpolicy="no-referrer-when-downgrade" class="vidyard-iframe-31gaLwGNSYTn2ec2BSQjkn" frameborder="0" height="100%" width="100%" scrolling="no" src="https://play.vidyard.com/31gaLwGNSYTn2ec2BSQjkn?disable_popouts=1&disable_analytics=0&preload=auto&disable_larger_player=false&theater_button=0&pip_button=0&controller=hubs&action=show&type=inline&v=4.3.20" title="trunk.io merge queue // predictive testing" spellcheck="false" />
</Frame>

<table><thead><tr><th width="331">What's Happening?</th><th>Queue</th></tr></thead><tbody><tr><td><strong>A</strong> begins testing</td><td><code>main</code> \<- <mark style={{backgroundColor: 'orange'}}><strong>A</strong></mark></td></tr><tr><td><strong>B</strong> begins predictive testing by including the changes in <strong>A</strong></td><td><code>main</code> \<- <strong>A</strong> \<- <mark style={{backgroundColor: 'orange'}}><strong>B</strong>+a</mark> \<- <strong>C</strong>+ba</td></tr><tr><td><strong>C</strong> begins predictive testing by including the changes in both <strong>A</strong> and B</td><td><code>main</code> \<- <strong>A</strong> \<- <strong>B+a</strong> \<- <mark style={{backgroundColor: 'orange'}}><strong>C</strong>+ba</mark></td></tr><tr><td>as testing completes - pull requests can merge safely</td><td><code>merge</code> <strong>A</strong>, <strong>B</strong>, <strong>C</strong></td></tr></tbody></table>

## The "Unhappy Path": How the Queue Handles Test Failures

Predictive testing is effective, but it creates a new challenge: **failure cascades**.

In the "Happy Path" example, if PR `A` introduces a failing test, the predictive tests for `B` and `C` are *also* guaranteed to fail, because they both include the broken code from `A`.

A simple queue would kick `B` and `C` as soon as their tests failed. This would disrupt their authors, who did nothing wrong, and force them to restart their PRs multiple times, wasting valuable CI time .

This is solved by **Pending Failure**.

### How Pending Failure Works

The main purpose of "pending failure" is to **minimize disruptions to the queue** by intelligently finding the ***true*** source of a failure.

Instead of immediately kicking a PR just because its test run failed, the queue follows this logic:

1. **A Test Fails**: Let's say PR `C`'s test run fails.
2. **Enter** `Pending Failure` **State**: `C` is *not* kicked. It enters a `Pending Failure` state and *waits* for the PRs it depends on (`A` and `B`) to finish testing.
3. **Identify the Root Cause:** The queue's goal is to determine: "Did this PR fail because of its own code, or did it fail because of a change in a PR ahead of it?".
   * `C` (failed) waits for `B`.
   * `B` (also fails) waits for `A`.
   * When `A` (at the top of the queue) fails, the queue knows it *must* be the PR that introduced the failure, as it only depends on `main`.
4. **Minimize Disruption:** The queue only kicks the first faulty PR (`A`).
5. **Automatic Recovery:** PRs `B` and `C` (which are likely healthy) stay in the queue. They are automatically re-scheduled for testing with a new predicted state that *excludes* the bad PR (e.g., `B` now tests against `main`, and `C` tests against `main + B`).

**Pending Failure** is the essential recovery mechanism that makes **Predictive Testing** practical. It ensures the queue is resilient and that engineers are not disrupted by test failures they didn't cause.

<Info>
  The predecessor-waiting described above is built into the Pending Failure state and always happens. The [Pending Failure Depth](./pending-failure-depth) configuration adds an additional hold: it also waits for *successor* test runs to complete, which enables [optimistic merging](./optimistic-merging) to automatically clear failures caused by flakes.
</Info>
