TokenSave logo TokenSave

TokenSave Data · Dataset

Claude Haiku vs Sonnet vs Opus on 25 real bugs: 225 runs scored by the maintainers' tests

Measured and written by · Updated . Disclosure: TokenSave gets no funding, credits or sponsorship from AI companies. All measurements use our own paid subscriptions.

On 25 real bugs from 13 open-source projects, Claude Haiku 5.5 fixed as many cleanly as Opus 5.5 (52 and 54 of 75 runs) at about 95% less cost per run. Opus pulled ahead on the hard bugs (16 of 30 clean fixes against Haiku’s 12), mainly because it broke other tests in fewer runs. None of the differences between Haiku and Opus is statistically significant with 3 runs per bug. Where the bug report left a case out, every model missed it.

Measured 2026-10-24 · 225 runs · 25 bugs · 13 projects · Claude Code 2.1.295 · License CC BY 4.0

DOI 10.5281/zenodo.23619927 · Also on Hugging Face · Kaggle · GitHub

Estimate your own Claude Code or Codex bill → See the monthly cost of Claude Code and Codex for your usage: API per task vs Claude and ChatGPT plans. Free, no sign-up. One square per run: 25 real bugs by Claude Haiku, Sonnet and Opus 5.5, colored by whether the run fixed the bug and broke other tests

Key findings

Hard round: test cases passed per run

Target cases = the maintainers’ tests for the fix that fail before it and pass after it. A red !n means the run broke n other tests in the same test files that pass both before and after the fix.

Project · bugHaiku 5.5Sonnet 5.5Opus 5.5Cases
cachetools · cachedmethod class access loses the explicitly supplied instance1, 1!1, 11, 1, 11, 1, 12
js-yaml · Sequence parsing in version 5 fails (BOM at the start of the file)1, 1, 11, 1, 11, 1, 12
markdown-it · Unclosed link/image label suppresses a later inline code span2!2, 2, 2!22, 2!2, 22, 2, 22
marked · A link inside link text produces nested links3!1, 3!1, 3!13!1, 4!1, 3!14, 4!1, 44
marked · Emphasis is lost in the text of a rejected reference link2, 2, 22, 2, 22, 2, 22
more-itertools · numeric_range: len(), in and index() disagree with the items produced, for float steps2, 2, 22, 2, 22, 2, 22
pyparsing · match_previous_expr fails on nested and repeated matches2, 2, 22, 2, 22, 2, 22
Python-Markdown · HTML comment inside inline raw HTML creates malformed output2!4, 2!4, 2!52!4, 2!3, 2!42!3, 2!3, 2!42
zod · Functions are executed twice for object property defaults3, 3!1, 33, 3, 33!1, 3, 33
zod · toJSONSchema on record with numeric keys results in invalid propertyNames3, 0, 62, 3, 04, 5, 58

Easy round: test cases passed per run

Cases written from the maintainers’ tests for the fix. No run broke the project’s own test suite.

Project · bugHaiku 5.5Sonnet 5.5Opus 5.5Cases
humanize · metric() shows one significant figure too many6, 6, 66, 6, 66, 6, 66
js-yaml · forceQuotes quotes non-string scalars and emits explicit type tags7, 7, 77, 7, 77, 7, 77
js-yaml · Block scalar with a whitespace-only body fails3, 3, 32, 2, 23, 2, 23
jsdiff · diffJson throws on truthy, non-callable toJSON2, 2, 22, 2, 22, 2, 22
jsdiff · applyPatch drops a literal carriage return at the end of a file5, 5, 53, 5, 35, 5, 55
jsdiff · diffJson serializes arrays with toJSON wrongly2, 2, 22, 2, 22, 2, 22
markdown-it · IPv6 address literal brackets are percent-encoded in link destinations3, 3, 33, 3, 33, 3, 33
more-itertools · seekable(..., maxlen=0): peek() and bool() drop items3, 3, 33, 3, 33, 3, 33
more-itertools · ichunked(..., 0) raises islice's ValueError on a nonempty iterable3, 3, 33, 3, 33, 3, 33
PapaParse · unparse crashes on a null cell when skipEmptyLines is true4, 4, 44, 4, 44, 4, 44
qs · stringify: a lone surrogate swallows the next character19, 19, 1919, 19, 1919, 19, 1919
qs · comma: true is ignored with charset 'iso-8859-1' and interpretNumericEntities11, 11, 1211, 11, 1211, 12, 1112
tomlkit · Emitting underscores in integers20, 20, 2020, 20, 2020, 20, 2029
tomlkit · Deleting a slice from an array corrupts the rendered output3, 3, 33, 3, 33, 3, 33
tomlkit · Parse errors report the wrong line and column for CRLF files3, 3, 33, 3, 33, 3, 33

Totals by round and model

Full fix = every target case passes. Clean fix = full fix and no other test broken. Cases passed = share of all target cases over all runs.

ModelRunsCases passedFull fixClean fixRuns that broke testsCost/runMedian s
Easy · Haiku 5.54591%40400$0.01148
Easy · Sonnet 5.54588%35350$0.09527
Easy · Opus 5.54590%38380$0.2647
Hard · Haiku 5.53072%181210$0.030154.5
Hard · Sonnet 5.53069%19147$0.2276.5
Hard · Opus 5.53082%21165$0.57167.5
All · Haiku 5.57587%585210$0.01966
All · Sonnet 5.57584%54497$0.1434
All · Opus 5.57588%59545$0.3884

Statistical tests

Fisher’s exact test on clean fixes per run; a paired sign-flip permutation test on the share of cases passed, pairing runs of the same bug and repetition; and a 95% interval for the difference in clean-fix rate from resampling whole bugs, because runs on the same bug are not independent. With 25 bugs, a real 10-point difference would usually go undetected; showing that two models are equal within ±10 points would take several hundred runs per model.

ComparisonClean fix, Fisher pCases, paired pClean-fix difference, 95% interval
Easy · Haiku vs Opus0.760.3760 to +13 pts
Easy · Haiku vs Sonnet0.260.0630 to +29 pts
Easy · Sonnet vs Opus0.590.185−18 to 0 pts
Hard · Haiku vs Opus0.440.092−33 to 0 pts
Hard · Haiku vs Sonnet0.800.870−17 to 0 pts
Hard · Sonnet vs Opus0.800.061−23 to +7 pts
All · Haiku vs Opus0.860.497−11 to +5 pts
All · Haiku vs Sonnet0.730.078−4 to +15 pts
All · Sonnet vs Opus0.480.006−16 to +1 pts

Method

Limitations

How to cite

Free to use, quote and republish with attribution under CC BY 4.0. Please link to this page.

TokenSave (2026). Claude Haiku vs Sonnet vs Opus on 25 real bugs: 225 runs scored by the maintainers' tests [Data set]. Zenodo. https://doi.org/10.5281/zenodo.23619927

BibTeX

@misc{tokensave_claude_haiku_vs_opus_real_bugs_2026,
  author    = {{TokenSave}},
  title     = {Claude Haiku vs Sonnet vs Opus on 25 real bugs: 225 runs scored by the maintainers' tests},
  year      = {2026},
  publisher = {Zenodo},
  doi       = {10.5281/zenodo.23619927},
  url       = {https://doi.org/10.5281/zenodo.23619927},
  note      = {Dataset, CC BY 4.0}
}

Embed the chart

Related

Questions or corrections: contact@jonhisking.com