oven-sh/bun · PR #30412 · a study of 2,981 issues across 39 weeks

A million lines of AI-assisted Rust, merged as one pull request. What happened to the bug reports?

On 14 May 2026 Bun replaced its Zig runtime with a Rust one in a single merge — 1,009,257 added lines, 2,188 files, six days from open to merge. This is an attempt to measure what that did to the project's defect reports, using the canary channel as a controlled before/after and the untouched stable branch as a control group.

The rewrite
PR #30412
Merged
2026-05-14 08:09 UTC
Diff
+1,009,257 / −4,024
Files / commits
2,188 / 6,755
Branch
claude/phase-a-port
Window studied
13 Nov 25 → 10 Aug 26

What was merged

Scale

Six days, 6,755 commits

Opened 8 May 2026, merged on the 14th. A 1,009,257-line addition against 4,024 deletions across 2,188 files — the runtime rewritten in a different language, landing in one merge rather than incrementally.

Authorship

Branch claude/phase-a-port

Confirmed, not inferred: Sumner's retrospective (8 Jul 2026) says the port ran as ~50 parallel Claude Code workflows on a pre-release Claude model — 11 days end-to-end, ~$165,000 at API pricing, peaking near 1,300 lines a minute, against his one-year estimate for a human team. The claude/* branch prefix is the repo's standing convention (7,469 of 18,528 PRs carry the claude label). Disclosure that belongs beside every claim in that post: Anthropic acquired Bun in December 2025.

Throughput

Merge rate nearly tripled

Merged pull requests went from 45.7/week in the six months before to 126.1/week after — ×2.76. The AI-labelled share rose from 55.5% to 75.0%. The rewrite changed the development mode, not just the language.

In the author's words, on the day it merged

“It passes Bun's pre-existing test suite on all platforms … the binary size shrinks by 3 MB – 8 MB, the benchmarks are between neutral and faster … To try this, run bun upgrade --canary. Please do file issues if you run into any. … Still some optimization work to do before this lands in non-canary version.”

Three things in that note shape everything below: the Rust build shipped to canary only, stable was explicitly deferred, and users were asked to file issues — which is itself a reason canary reports would rise. The promised details post landed on 8 July 2026 (bun.com/blog/bun-in-rust) and is taken up in section 5.

Findings

Canary bug reports / week 5.9 → 20.7 ×3.5 · ×2.2 vs the final quarter 154 in 26 weeks of Zig canary, 248 in 12 weeks of Rust canary
Canary fix rate
(share ever closed as fixed)
43.5 → 41.9% −1.6 pt · unchanged 67 fixed before, 104 after
Canary bugs fixed within 30 days 18.8 → 30.4% +11.6 pt · faster Canary is now where the work happens, not a side branch
Stable-only bug reports / week
(the unchanged 1.3.x code)
45.8 → 31.5 −31.2% Attention moved off the branch users are still running
All bug reports / week 69.3 → 68.9 −0.6% · two moves cancelling The repo-wide total is the least informative number here
Stable releases / month 2.01 → 0 89-day drought, still running Longest prior gap since 2024: 27 days

1 — Canary bugs in, fixes out

Bug reports naming a canary build, per week, and how many have since been fixed

Closed as fixed Duplicate, not planned, or still open Stable release
A report counts here if its text names a canary build — 1.3.x-canary before the merge, 1.4.x after. The version lineage switches cleanly at the cut: not a single pre-merge issue names a 1.4.x Bun build (a plain version-string match finds nine, every one a library version like elysia 1.4.x), and 1.3.x-canary mentions stop within a week of the merge. Dashed rules are the period means for reports opened and for reports since fixed. The strip below marks every stable release — canary itself is a rolling tag with no per-build release entry, so the ticks show what reached ordinary users, which since the merge is nothing.

This is the comparison that isolates the rewrite. Both sides are the same distribution channel and roughly the same kind of user — people who deliberately run pre-release Bun. The only thing that changes at the cut is the language the runtime is written in, because the Rust port went straight into canary and has never left it. The version strings confirm the handover is clean: not one pre-merge issue names a 1.4.x Bun build, and 1.3.x-canary mentions stop within a week after the merge.

Through that channel, bug reports went from 5.9 a week to 20.7 — 3.5× against the full pre-window, or 2.2× against the busier final quarter before the merge, which is the conservative read. Fixes kept pace: 41.9% of Rust-canary bug reports have been closed as fixed against 43.5% of Zig-canary ones, and 8.7 a week are now being fixed against 2.6 before. The share fixed within 30 days of filing actually improved, from 18.8% to 30.4% — Zig canary was a side branch where reports could sit for months; Rust canary is the mainline.

What this cannot separate is how many people are reporting. Two things changed at the cut besides the language. Canary became the only way to get the Rust build, so the population behind those 20.7 reports a week is almost certainly larger than the population behind 5.9. And the PR asked for reports in as many words — “Please do file issues if you run into any” — which lifts the reporting rate independently of how many defects exist. Report volume is exposure × defect density × willingness to report, and only the product is observable. A ×2.2–3.5 rise is therefore an upper bound on any rise in defect density, not a measurement of it.

The ratios are the sturdier half of the finding. Fix rate and fix latency don't depend on how many people are looking: 41.9% against 43.5%, with 30-day resolution improving. Whatever the Rust port is generating, the team is clearing it at the rate it always did — while merging 126 pull requests a week against 46 before.

2 — The two populations diverge

All bug reports per week, split by the build they name

Canary build Stable 1.3.x only No version stated
Bar height is total bug reports; bands are the build named in the report text. Canary went from 8.4% of reports to 29.7% while stable-only fell from 66.2% to 45.9%. The unclassified share barely moves (25.4% → 24.3%), so the classifier isn't drifting across the cut.

The repo-wide total is motionless — 69.3 a week before, 68.9 after — and that is the least informative number in this study. It holds still because two populations moved in opposite directions by almost exactly the same amount: canary reports rose by 14.8 a week, and reports naming only a stable 1.3.x build fell by 14.3. Bun did not stop receiving bugs at the old rate; it stopped receiving them about the same code. Any analysis of this rewrite that stops at the repo total will conclude nothing happened.

The stable side is the natural control group. Nothing in 1.3.14 changed after 13 May — it is the same Zig binary every stable user is still running — and reports about it fell 31.2%, with the fix rate slipping from 42.6% to 39.2%. That's what a codebase looks like when the people who maintain it have moved to something else.

3 — Nothing has shipped

All bug reports and fixes per week, with every stable release marked

Closed as fixed Duplicate, not planned, or still open Stable release
The last four weeks are shaded because their issues are under ~30 days old — their fixed counts are still rising and should not be read as a decline. Week +12 is partial (5 days) and excluded from every average.
Before

12 releases in 182 days

2.01/month, median gap 16 days: v1.3.3 through v1.3.14. Already a slowdown — the same calendar window a year earlier shipped 25 releases at a 5-day median gap.

After

Zero releases in 88 days

The newest stable tag is bun-v1.3.14, 13 May 2026 — one day before #30412 landed. The longest gap between any two Bun releases in all of 2024–2026 was 27 days, against a median of 8. The current gap is 89 days and open-ended.

Consequence

The user base is split in two

Everyone on stable is running Zig code that is no longer being actively fixed; everyone on canary is running Rust code that cannot be installed by default. On the evidence here the rewrite's measurable cost so far is not a defect spike — it's that the two halves of the user base have been on different runtimes for three months, exactly as the PR said they would be until the optimization work lands.

4 — The debate this case lands in

The hypothesis this study set out against: Rust's whole-language rigidity and complexity — borrow checker, lifetimes, trait system, syntax, static types included — make it badly suited to everyday development, where tasks are rarely precisely defined and unexpected cases demand flexibility. That position is neither fringe nor strawman. It is held by senior practitioners with serious Rust mileage, by the designers of Go and of Zig — the language Bun left — and, in part, by Rust's own creator. The production record at scale points the other way. Every quote below was fetched from its source and verified on 10 Aug 2026.

The case that rigidity hurts
“…the borrow checker forces a refactor at the most inconvenient times.”LogLog Games — 3+ yrs full-time Rust, 100k+ lines, shipped games (2024). A section title in the same essay: “Making a fun & interesting games is about rapid prototyping and iteration, Rust's values are everything but that.”
“He's right about the pain of refactoring and the difficulties of interconnecting different parts of the program. It's quite common for some change to require extensive plumbing work.”John Nagle — five decades of systems engineering, ~45k lines of safe Rust on a metaverse client; adds that the C#/Unity teams on the same problem make faster progress.
Rust's own creator writes that shipped Rust is far from the language he wanted — he argued against explicit lifetimes, first-class borrows and the trait system as costing more cognition than they return — while conceding his simpler Rust “had no future.”Graydon Hoare, “The Rust I Wanted Had No Future” (2023) — paraphrased; the post resisted re-fetching for verbatim quotation.
“The key point here is our programmers are Googlers, they're not researchers… They're not capable of understanding a brilliant language but we want to use them to build good software.”Rob Pike — co-creator of Go and Plan 9, on Go's design rationale (as quoted); his 2012 essay “Less is exponentially more” treats feature-count as the disease, not the cure.
“One finds oneself debugging one's knowledge of the programming language instead of debugging the application itself.”Zig's official design rationale, naming Rust's feature volume directly — the stated philosophy of the language Bun walked away from.
In the Rust project's own 2023 survey, the top worry for the language's future was “Rust becoming too complex” — 43% of 9,374 respondents, up 5 points on the year; still top-of-list in 2024.Rust Annual Survey — the complexity worry is loudest among Rust's own users.
The case that rigidity pays
“For medium and large changes, the rollback rate of Rust changes in Android is ~4x lower than C++.” Rust changes also spend ~25% less time in review, need ~20% fewer revisions, and show “a 1000x reduction in memory safety vulnerability density” versus Android's C and C++.Google, Android (Nov 2025) — production data at one of the largest codebases in existence.
“In every case we've seen a decrease by more than 2x in the amount of effort required to both build the services in Rust as well as maintain and update those services…”Lars Bergstrom — Google engineering director, ex-lead of Mozilla's Servo. Google's survey of 1,000+ of its Rust developers found no productivity penalty vs their prior language, most reaching parity within four months.
“Rust has been a force multiplier for our team, and betting on Rust was one of the best decisions we made. More than performance, its ergonomics and focus on correctness has helped us tame sync's complexity.”Dropbox — who chose Rust precisely for their most edge-case-ridden component, setting compiler-checked invariants against a state space they call “astronomical.”
“Rust, by design, makes certain programming patterns more painful than others. This is a GOOD thing!”Catherine West — Starbound's lead programmer, RustConf 2018 keynote: from inside gamedev, the patterns Rust punishes are the ones that hurt games in any language.
“Rust's ubiquitous Option type allows for sentinel values to be eliminated from one's code – and with it some significant fraction of defects.”Bryan Cantrill — DTrace co-inventor, ~30 years of production C before Oxide bet its stack on Rust.

What is striking is that the two camps agree on where the boundary sits. The fiercest critique concedes it: “Rust fits very nicely in the low level algorithmic areas where one knows exactly what the problem is and just needs to solve it” (LogLog Games, the same essay). An ex-AAA engine developer in the same thread: “Rust excels when you know what you want to build… Once you get up in game logic/behavior that iteration loop is so dynamic that you are prototyping more than developing.” The disagreement is not really about Rust. It is about which regime the work lives in. The complexity tax is front-loaded — paid during exploration, while requirements churn. The strictness dividend is back-loaded — collected in production, as defect classes that never ship. Which side of the ledger dominates depends on how much of the work is exploration and how much is execution against a known spec.

Two scope notes keep this honest. Zig is also a statically-typed, compiled language — so this case measures the increment of ownership, lifetimes and traits, not “static versus dynamic typing,” and the static-typing literature is left out of this discussion as a different question. And a JavaScript runtime that embeds JavaScriptCore over FFI keeps a substantial unsafe surface where the borrow checker's guarantees lapse — “use-after-free becomes a compile error” is a property of safe Rust, not of the FFI boundary where much of a runtime's hottest code lives.

5 — The AI variable

The rigidity argument has always been an argument about human iteration speed — the cost of fighting the compiler while exploring. This rewrite changes who does the fighting. Per Sumner's retrospective and press reporting: ~50 parallel Claude Code workflows on a pre-release Claude model, 11 days end-to-end, ~$165,000 at API pricing, a peak near 1,300 lines a minute, 100% of the test suite passing — against his estimate of “a small team of engineers a full year.” (Disclosure, his and ours: Anthropic acquired Bun in December 2025, and this study was itself researched and written with Claude.)

“A large percentage of bugs from that list are use-after-free, double-free, and ‘forgot to free’ in an error path. In safe Rust, these are compiler errors… Compiler errors are a better feedback loop than a style guide.”Jarred Sumner — the rewrite's thesis: strictness as machine-checkable guardrails for machine-written code.
“A language-independent test suite with a million assertions, adversarial code review and when something does go wrong, fixing the process that generates the code instead of hand-fixing the code.”Simon Willison — ~25 years, Django co-creator; judges the port a success but credits the verification harness, not the language.
“If you do put the type check into the loop, my tests actually showed worse performance. That's because the agent manages to get the code running, and only after it's done does it run the type check.”Armin Ronacher — Flask's creator, ~20 years, long-time production Rust user — the credible dissent: his hands-on agent tests favor loose, “best-effort” typing, and he recommends Go, not Rust, for agentic coding.
“It's not sufficient to catch bugs in Zig code but it is sufficient to catch bugs in [a] million lines of unreviewed slop?”Andrew Kelley — Zig's creator, reacting to the rewrite; he explicitly rejects the language framing: “The main issue here had nothing to do with the language features of Zig vs Rust, and everything to do with the diverging value systems of the two projects and the relationship breakdown that followed.”

The peer-reviewed evidence leans Sumner's way on the narrow question: constraining LLM decoding with type-system rules cuts compilation errors by more than half (ETH Zürich / UC Berkeley, PLDI 2025), and an LLM iterating against rustc's error messages fixes roughly 74% of real-world compile errors unaided (Microsoft Research, ICSE 2025). In an agent loop, the strict compiler converges instead of blocking. Against that stand Ronacher's hands-on results — and Kelley's objection, which is not about Rust at all: compilation proves the absence of certain bug classes, not the presence of understanding. Nobody has read the million lines.

This study's numbers adjudicate a little of both. The language did not become the bottleneck — bug-fix throughput held at pre-rewrite rates against triple the canary report volume, with 2.76× the merge rate. The human loop did: triage collapsed and nothing has shipped to stable in 89 days. Machines absorbed the complexity tax. Humans kept the verification bill.

6 — Conclusions

  1. On its own numbers, the rewrite was neither catastrophe nor triumph. Canary bug reports rose ×2.2–3.5 (confounded by exposure and explicit solicitation), the fix rate held (43.5% → 41.9%), the stable branch's reports fell by a third as attention left it, and no stable release has shipped in 89 days.
  2. The rigidity-and-complexity critique of Rust is real, credible — and regime-dependent. Its best-sourced form comes from veterans with serious Rust mileage, from the designers of Go and Zig, and in part from Rust's own creator; the Rust project's own survey makes “becoming too complex” its users' top worry. The supporting evidence concentrates where requirements churn: prototypes, games, early products, exploratory work.
  3. In the opposite regime — a known spec, executed at scale — the production data contradicts it, and not narrowly: 4× lower rollback rates, 2× lower maintenance effort, no measured productivity penalty across a thousand Google developers. Even the critics concede this boundary; even the advocates concede the ramp.
  4. Bun's rewrite cannot arbitrate the hypothesis, because it sits entirely in Rust's home regime. A port against a million-assertion conformance suite is the most spec-frozen project imaginable — the exact condition under which critics and advocates agree Rust excels — and its FFI-heavy core keeps a large unsafe surface outside the borrow checker's guarantees. Kelley's counter-hypothesis (culture, not language: stable Zig projects exist) also survives this data untouched. Anyone citing this rewrite as proof about Rust for everyday, vaguely-specified development — in either direction — is overclaiming.
  5. What this case does show is the complexity ledger being redrawn. When ~50 agent workflows write the million lines, the rigidity that taxed human iteration becomes machine-checkable guardrails on machine-written code — and the binding constraint moves to the humans who must review, triage and ship it. That is precisely where this project stalled. The open question the next six months will answer is not whether Rust's strictness suits AI-scale development, but whether human verification can keep up with it.

Period averages

PeriodWeeksCanaryStable 1.3.x onlyAll bug reportsReleases/mo
per wkfix rateper wkfix rateper wkfix rate
Pre-rewrite baseline−26 … −15.9243.5%45.7742.6%69.3140.8%2.01
…final quarter only−13 … −19.3841.8%48.1542.0%69.6242.3%1.67
▼ PR #30412 — Rewrite Bun in Rust — merged 2026-05-14 08:09 UTC · canary switches from 1.3.x to 1.4.x
Post-rewrite, month 10 … 321.7547.1%32.5030.0%80.5038.5%0
Post-rewrite, month 24 … 721.0041.7%31.7542.5%66.2541.1%0
Post-rewrite, month 38 … 1119.2536.4%30.2545.5%60.0039.6%0
Post-rewrite, all0 … 1120.6741.9%31.5039.2%68.9239.7%0
Change vs baseline×3.49−1.6 pt−31.2%−3.4 pt−0.6%−1.1 pt−100%

Every week

WkWeek startingCanaryfixedStable onlyfixedNo versionAll bugsRelease
Method, definitions and limits

Source. All 2,981 issues (pull requests excluded by construction) created in oven-sh/bun between 2025-11-13 and 2026-08-10, pulled via the GitHub GraphQL API with createdAt, closedAt, state, stateReason, labels, author and body text. Release dates come from the Releases API — all 214 are marked non-prerelease. Totals were cross-checked against the Search API. The frozen snapshot, every analysis script, and an independent verification script that re-derives all 31 published figures from that snapshot live in the companion repository.

Binning. Weeks are 7×86400s bins anchored to the merge timestamp rather than to calendar weeks, so week −1 is the last seven days before the rewrite and week 0 the first seven after. Week −26 begins 2025-11-13, six months before the merge. Week +12 covers five days and is excluded from every average.

What counts as a bug report. Every issue not labelled enhancement, docs, idea, question, chore, duplicate, invalid or wontfix — 1,802 before the rewrite and 827 after. Whether an issue was triaged is irrelevant; only that it was opened. The bug label is deliberately not used as the definition, because label coverage collapsed across the cut (unlabelled share went from 0–3% in November 2025 to 50–63% after the rewrite), so a bug-label count measures triage effort rather than defect reports.

Which build a report is about. Classified from version strings in the title and body — Bun's issue template asks for bun --revision, so most reports carry one. Canary = the text matches 1.3.x-canary (Zig canary) or 1.4.x (the Rust line, which has never had a stable release). Stable only = matches 1.3.x with no canary suffix and no 1.4.x mention. No version stated = neither. Coverage is stable across the cut — 25.4% unclassified before, 24.3% after — so the split is not an artifact of reporting habits changing. Robustness: a stricter classifier that only accepts a 1.4.x token carrying canary/debug/a build hash, or sitting within 80 characters of bun/version/revision, moves the counts from 154→147 pre and 248→246 post, leaves both fix rates unchanged to one decimal, and raises the volume ratio from ×3.49 to ×3.63 — the published looser rule is the conservative choice. The false matches are library versions (elysia 1.4.x, tw-animate-css 1.4.0, WCAG criterion 1.4.3), and in a 25-issue random sample of post-rewrite canary classifications, 23 were the reporter's own bun --revision output.

What counts as fixed. GitHub's stateReason of COMPLETED on a closed issue. The 19 issues closed and later reopened count as open, not fixed. Headline fix rates compare final states as of the pull date, which penalises the younger cohort; the 30-day figures ask the same question of every week — what share was fixed within 30 days — over weeks old enough to answer it.

The limit that matters most. Report volume is exposure × defect density × willingness to report, and only the product is observable. Two of those three terms changed at the cut independently of the code: canary became the only route to the Rust build, and the PR explicitly solicited reports (“Please do file issues if you run into any”). The ×2.2–3.5 rise in canary reports is therefore an upper bound on any rise in defect density, not a measurement of it. The ratios — fix rate, fix latency — are population-independent and are the sturdier half of the analysis. Severity is unweighted throughout: a segfault and a typo count the same.

On calling the rewrite AI-assisted. Initially inferred from convention (the claude/phase-a-port branch; 7,469 of the repo's 18,528 PRs carry a claude label, 75% of everything merged since the rewrite), later confirmed directly: Sumner's 8 July 2026 retrospective states the port used a pre-release Claude model across ~50 parallel Claude Code workflows, and The Register reports 11 days and ~$165,000 at API pricing. Disclosures that cut in both directions: Anthropic acquired Bun in December 2025, and this study was itself researched and written with Claude.

On the quotes in sections 4–6. Every quotation was fetched from its source URL and verified verbatim on 10 Aug 2026, with one exception: Graydon Hoare's Dreamwidth post resisted re-fetching and is paraphrased, never quoted. Authors were included only where the page or an easily-found bio evidences roughly five or more years of professional software experience; institutional data (Google, Microsoft, Dropbox, the Rust surveys, peer-reviewed papers) is cited as data rather than opinion. The static-vs-dynamic-typing literature was researched and deliberately excluded: Zig and Rust are both statically typed, so that debate is orthogonal to this case.

  • Small pre-rewrite canary counts. 154 issues over 26 weeks, several weeks at zero or one, with spikes of 24 and 25 in late March and early April 2026. The ×2.2 figure against the busier final quarter is the conservative comparison; ×3.5 against the full window is the loose one.
  • Right-censoring. Recent issues have had less time to be fixed, which depresses every post-period disposition count. The last four weeks are shaded in the charts for that reason, and month 3 is omitted from 30-day figures.
  • Pre-window skew. Weeks −26 and −25 sit on the Bun 1.3.0/1.3.1/1.3.2 release wave (137 and 159 issues) and lift the pre-rewrite aggregate mean; the final-quarter row is given for comparison.
  • Data pulled 2026-08-10. Figures for the final weeks will drift as late fixes land.