Build1 distinct publisher3 min readUpdated
A one-qubit circuit optimised to nothing in Qiskit 2.5.0, fixed in 2.5.1. The durable lesson is that a simulator handing back a clean number is not a passing test.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
A one-qubit circuit holding three gates (sxdg, sxdg, sx) run through Qiskit's CommutativeCancellation transpiler pass on version 2.5.0 comes back empty, with count_ops() printing OrderedDict() [1][2]. Those three compose to a quarter turn in the negative direction, so one gate should have survived; instead the rotation is gone, with no error, no warning and nothing in the logs, and measuring that qubit then gives a different answer than the circuit specifies [3][4].
The finder was not a test suite. According to the developer's account, published on dev.to while building nqf-lint, a linter for quantum chemistry setups [7], he had stopped trusting the simulators because they looked too tidy: every run handed back a clean number and never complained [6]. So he wrote a fuzzer that throws random circuits at multiple backends and flags disagreement, and the first stop was two backends failing to match [5]. That is the whole argument for differential testing in one line. A single backend cannot tell you it is wrong. Two can tell you at least one of them is.
The failure reproduces on qiskit==2.5.0 and is fixed in 2.5.1 [8]. What happened between those versions is instructive about diagnosis. The report named a cause: that _x_rotations at line 69 of commutative_cancellation.py includes both sx and sxdg, so two sxdg get treated as an inverse pair [9]. Jake Lishman, a core maintainer, replied the same day that the root cause was quite different, that all of the code in question is in Rust, and that the pass computes the required rotation angle correctly but fails to synthesise it back into gates when the combined X rotation is a negative odd multiple of pi/2 and sx appears to be a supported gate [10]. The reporter conceded he had been reading the Python and guessed wrong [11].
He then did the part that was actually worth something: he measured. Sweeping the combined rotation across every multiple of pi/2 from -8 to 8, forcing exact angles with pairs of rx gates and checking each result against the exact operator, he found even multiples failing as well [12]. That is a wider failure set than the stated root cause, which was scoped to negative odd multiples [16]. He also retracted a precondition from his own report, that a gate on another qubit had to sit between the two sxdg; it happens on one qubit with nothing else in the circuit, and he posted that correction before anyone asked [13].
The code he landed on is short: num_sx is computed as (total_angle / FRAC_PI_2).round(), then a loop runs 0..(num_sx as i64) % 4 inserting gates [14]. For a combined angle of minus a quarter turn that rounds to -1, and Rust's remainder keeps the sign of the dividend, so -1 % 4 is -1 and the range 0..-1 is empty, which emits zero gates [15]. That reading is mine, from the excerpt; it is consistent with an angle computed correctly and then synthesised into nothing.
The operational takeaway is not about one pass. A transpiler is a compiler, and this class of bug is silent by construction: output that type-checks, runs, and returns a number. If your pipeline's only oracle is "the simulator did not throw", you have no oracle. Pin the transpiler version alongside the SDK version, keep an exact-operator check on small circuits after optimisation, and treat backend disagreement as a build failure rather than noise.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
A one-qubit Qiskit circuit built as qc.sxdg(0); qc.sxdg(0); qc.sx(0) and run through PassManager([CommutativeCancellation()]) returns a circuit whose count_ops() prints OrderedDict().
On paper the three gates add up to a quarter turn in the negative direction, so one gate should come out of the pass.
There is no error, no warning and nothing in the logs; the rotation is gone, and measuring the qubit gives a different answer than the circuit says it should.
The author wrote a fuzzer that throws random circuits at simulators and checks whether they disagree with each other; the first time it stopped, it reported that two backends did not match.
The author says he stopped trusting the simulators because they looked too tidy: every run handed him a clean number and never complained about anything.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Reproducible but single-sourced
The core technical claims are unusually well specified for a single blog post: a minimal runnable reproduction with its printed output, an explicit affected version and fix version, a verbatim maintainer quote naming the language and failure mode, the offending Rust lines, and a measured angle sweep. What is missing is any second source: the issue, the PR and the 2.5.1 release are asserted and linked, not independently present in the cluster, and the author's own earlier diagnosis was demonstrated to be wrong once already.
Fix shipped upstream, impact unquantified
There is real uptake evidence at the project level: a filed issue, same-day maintainer triage, two open PRs and a patch release said to carry the fix in a widely used quantum SDK. There is no evidence at all about who was affected, how many workloads ran the pass on 2.5.0, or whether users have upgraded, so adoption is scored on maintainer-side movement only.
Slightly understated
The post consistently claims less than its material would allow: it foregrounds the author's wrong diagnosis, states plainly that his comment was not the fix and that the maintainer got there first, and frames the takeaway as a small habit rather than a discovery. The one place the framing runs ahead of confirmed ground is the measured even-multiple failures, which the quoted maintainer description does not cover and which nothing in the cluster confirms were addressed by 2.5.1.
Visible but disclosed self-promotion
The piece is a personal developer-brand post that opens with the author's own linter, nqf-lint, and closes by linking his fuzzer repository, so there is a clear reputational and project-visibility incentive in casting the episode as a validated find. Those interests are stated openly rather than concealed, and the narrative repeatedly cuts against the author's own credit, which limits the distortion.
Moderate: one publisher, verifiable artifacts
Confidence is capped by the cluster having exactly one source and one publisher, and by that source being self-reported. It is lifted by how checkable the artifacts are - a pinned version, a minimal snippet, a named maintainer quote, an issue number and a PR number - and by the internal consistency of the mechanism with the line the maintainer says the PRs touch. The unresolved even-versus-odd multiple discrepancy keeps it out of the high band.
leadership
Expressiveness Is A Cost: The Tradeoff Behind Every "Make It More Flexible" Request1 distinct publisher
build
Force the tool call, then hand Lightsail a long-lived key1 distinct publisher
build
Stop timing your GraphQL tests and start counting loader calls1 distinct publisher
security
Google's reference agent approved a $10,000 refund on a $149 order, on purpose1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 17, 2026