Found by the first three-way verify_dsp run, 2026-09-09. 18 of 54 probe lines differ between the patched CircuitPython build and our other two targets, and they are exactly the rails cases — the full-scale alternating material. Every other case agrees to the byte, which is the signature of an overflow that only bites at the extremes.
The cause, at the source
cmods/circuitpython/shared-module/audiodelays/Flanger.c:365:
int32_t wet = s0 + (((s1 - s0) * (int32_t)delay_frac) >> 16);
With the delay line holding adjacent samples at opposite rails, s1 - s0 reaches 65535 and delay_frac reaches 65535 too — a product of 4.29e9, past INT32_MAX. Signed overflow, and reachable on ordinary full-scale material.
Upstream widened the other product and not this one. Eighteen lines above, at :347:
uint32_t delay_q16 = delay_min_q16 + (uint32_t)(((uint64_t)delay_span_q16 * tri) >> 16);
so the (uint64_t) cast is there where it is needed for the span, and absent where it is needed for the interpolation.
Where each target stands
| target |
form |
correct? |
| CircuitPython 10.3.0 (upstream's C) |
int32_t product |
no |
| audioif CPython twin (Python) |
arbitrary precision |
yes, by accident — Python does not overflow |
| audioif MicroPython (our C) |
(int64_t) product |
yes, fixed in 2a95091 |
Our port inherited the bug because Cursor ported from that same upstream file; I found it here by cross-interpreter comparison and widened it. The twin was never wrong because Python has no int32 to overflow — which is also why a twin cannot be relied on to surface this class of defect.
What this needs
- An
upstream-diff.md entry, because under docs/correctness-standard.md a deliberate departure from CircuitPython in a node CircuitPython has must be written there or it is a bug. We are deliberately not reproducing this overflow.
- A stated skip in
verify_dsp's PROBES for flanger_probe.py on circuitpython, naming this issue — otherwise the three-way stands red on a defect that is not ours to fix.
- An upstream report, drafted into
docs/upstream-reports/ and not filed yet: Brad's rule of 2026-09-09 is that no upstream report goes out until our own house is clean, in case something related changes the report. The fix upstream is one cast, the same one they already used eighteen lines earlier.
Related: audioif#75 (our CircuitPython bindings lagging), which the same three-way run surfaced.
Found by the first three-way
verify_dsprun, 2026-09-09. 18 of 54 probe lines differ between the patched CircuitPython build and our other two targets, and they are exactly therailscases — the full-scale alternating material. Every other case agrees to the byte, which is the signature of an overflow that only bites at the extremes.The cause, at the source
cmods/circuitpython/shared-module/audiodelays/Flanger.c:365:With the delay line holding adjacent samples at opposite rails,
s1 - s0reaches 65535 anddelay_fracreaches 65535 too — a product of 4.29e9, past INT32_MAX. Signed overflow, and reachable on ordinary full-scale material.Upstream widened the other product and not this one. Eighteen lines above, at
:347:so the
(uint64_t)cast is there where it is needed for the span, and absent where it is needed for the interpolation.Where each target stands
int32_tproduct(int64_t)productOur port inherited the bug because Cursor ported from that same upstream file; I found it here by cross-interpreter comparison and widened it. The twin was never wrong because Python has no int32 to overflow — which is also why a twin cannot be relied on to surface this class of defect.
What this needs
upstream-diff.mdentry, because underdocs/correctness-standard.mda deliberate departure from CircuitPython in a node CircuitPython has must be written there or it is a bug. We are deliberately not reproducing this overflow.verify_dsp'sPROBESforflanger_probe.pyon circuitpython, naming this issue — otherwise the three-way stands red on a defect that is not ours to fix.docs/upstream-reports/and not filed yet: Brad's rule of 2026-09-09 is that no upstream report goes out until our own house is clean, in case something related changes the report. The fix upstream is one cast, the same one they already used eighteen lines earlier.Related: audioif#75 (our CircuitPython bindings lagging), which the same three-way run surfaced.