# Bisecting a regression

Give Haystack a version that worked, a version that does not, and a script that tells the two apart. It returns the first bad commit.

## How it works

You know a version that worked and a version that does not, and you have a script that can tell the two apart. `haystack verify bisect` checks out real commits from that range in cloud sandboxes, runs your script against each, and reports the first bad commit and its clean parent. Nobody babysits a `git bisect` for an afternoon.

## The command

```bash
haystack verify bisect --repo . --good py-1.42.1 --bad py-1.43.0 \
--predicate ./check.py
```

Refs resolve to exact commits before the request leaves your machine, so a mistyped tag fails immediately with git's own error message, not minutes later in a sandbox.

| Option | Purpose |
|---|---|
| --repo | Local clone (its origin remote is what sandboxes clone) or a git URL |
| --good / --bad | Range boundaries: tag, branch, or SHA |
| --predicate | The test script (contract below) |
| --signal | One-line description of the regression, shown on the results page |
| --label | Title for the run |
| --wave-width | Max commits probed concurrently while narrowing |
| --server, --token, --json, --no-open | Same as the rest of verify |

## The predicate contract

The predicate is the whole interface between your test and the search. Its exit code is the verdict:

| Exit code | Meaning |
|---|---|
| 0 | Good: the behaviour is correct at this commit |
| 1 | Bad: the regression is present |
| 125 | Untestable; the commit is skipped, never narrowed on |
| anything else | Infrastructure failure; the search never narrows on errors |

The script must be self-contained: it brings up whatever it needs. It must be deterministic: a commit's verdict must not change between probes. It runs with cwd = the repository checkout.

## What you get back

The command prints a run id and results URL immediately. The results page shows the live probe timeline and, when found, the culprit card: the first bad commit, its clean parent, the predicate's readings on each side, and an independent confirmation probe at the reported-bad revision.

Follow the run like any other with `watch`, `status` and `findings`. A found culprit appears in `findings` as `First bad commit: <sha>` and makes `watch` exit 1 on purpose: the search succeeding means the regression is real. Put `watch` in CI and the exit code carries the verdict.

Coding agents get the same entry point: the `verify_bisect` tool on `haystack verify mcp`.

## A real run: polars

A regression reported between two releases of pola-rs/polars, bisected with a predicate that reads a data artifact and checks it for corruption:

| Range | py-1.42.1 to py-1.43.0: 145 commits, 139 that could affect the artifact, probed in parallel |
| Culprit | 6478498e, fix: Ensure BinaryView offset+len does not exceed i32::MAX where possible (PR #28048) |
| Clean parent | 00e0078c |
| Wall clock | About five minutes end to end with a warm build cache |

## What works today

Repositories whose predicate can run from a source checkout (interpreted languages, for example) work generically. For compiled projects, Haystack uses a build recipe for your repository; polars is the proven one today. Talk to us about adding yours.
