Yesterday I recorded the second video in my kernel engineering series. Since C-Kernel-Engine already had Whisper support, I wanted to use it to transcribe my own recording. Not another small demonstration. My actual microphone, my explanations, my pauses, and a video I wanted to publish.
That should have been a useful small win. Instead, one of the broken runs gave us essentially one word: “The.”
So this became a debugging session before it became a video-editing workflow. We found a wrong connection in the generated audio encoder, fixed it, and then found a separate problem at the end of long recordings. The fixes also exposed another mismatch between how the graph named its inputs and how lowering looked them up. I want to explain all three, because saying “Whisper works again” is much less useful than understanding why it stopped working.
The Kernels Were There. The Connection Was Wrong.
In CKE, I think of a model as a circuit. The kernels do the mathematics. The circuit describes how those operations connect. Kernel maps describe the interfaces, and the DSL turns those declarations into a memory plan and generated C. If you want the visual explanation, start with the kernel concepts and infographics, then the kernel-map documentation.
For this Whisper failure, the problem was not that we needed to invent a new attention kernel. The generated encoder was reading the wrong activation buffer at its first attention projection.
The audio circuit explicitly connected its projection input A to main_stream. But lowering still contained a compatibility shortcut that treated names such as A, x_q8, and input as aliases for x. That lookup could take precedence over the circuit's actual declaration. The resulting encoder read an uninitialized Q8 activation buffer instead of the intended stream.
Declared circuit edge:
projection input A <- main_stream
Broken lookup:
A becomes x before resolving the declared edge
-> wrong planned activation buffer
Required contract:
declared edge + validated interface + planner assignment
-> the intended allocated buffer
missing or incompatible information -> errorThat is a compiler wiring error. A matrix multiplication can be implemented correctly and still produce nonsense if the generated program gives it the wrong input. Testing the kernel alone cannot prove that the complete model is connected correctly.
Find The First Wrong Number, Not Just The Wrong Sentence
The investigation paired encoder and decoder variants to isolate the failure to the current encoder. Then X-Ray comparisons narrowed it to the layer-zero Q projection. PR #455 records the before-and-after measurements:
| Layer-zero Q projection | Before repair | After repair |
|---|---|---|
| Maximum absolute error | 8.49496126 | 0.0000057220459 |
| Root mean square error | 1.53243092 | 0.000000545792371 |
These are measurements at one diagnosed numerical boundary, not a claim that every output tensor in every Whisper model is bit-identical. But they explain why the repair mattered: we restored the intended input to the projection, rather than adjusting the transcript until it looked plausible.
I had previously written about making Whisper faster and strengthening its evidence. This regression does not erase that earlier work. It does show that a working result on an earlier revision is not a permanent guarantee about the next generated runtime.
Why I Did Not Want The Old Fallback Left In Place
The first repair preferred the exact declaration but retained the legacy lookup as a fallback. I asked to remove that fallback. If a circuit needs an input, it should declare it. Otherwise, we would be leaving the same ambiguity available for a future model or compiler cleanup.
The final changes in merged PR #455 removed the projection alias/default-buffer fallback, added explicit input declarations across the affected in-tree circuits, and made missing planner assignments or unallocated buffers fail loudly. This was broader than a Whisper-only exception. Llama, Qwen, Gemma, Cohere and the other affected circuits had to own their projection inputs too.
The code also includes a comment explaining the actual failure: the old alias path selected an uninitialized buffer and reduced a real transcript to “The.” That comment is there for the next person, or agent, cleaning up the DSL. It explains why this check exists instead of merely saying what the next line does.
The Follow-Up: Exact Ownership Does Not Mean Identical Port Names
There was another repair after that. PR #457 includes an audio port-canonicalization fix: graph construction could already express a provider's A/C ports as operation-level x/y ports, while lowering was trying to consume the declaration under a different spelling.
The correct response is not to bring back “if this lookup fails, try some other buffer.” It is to use the validated interface mapping, or the same canonical mapping used during graph construction, while preserving ownership of the declared slot. A naming translation is acceptable. Silently changing which tensor an input reads is not.
This is an important part of the story. Making the compiler stricter was the right direction, but that stricter contract also had to agree across compiler stages. A fix itself needs integration testing. The reviewed lowering implementation contains both the explicit binding checks and this follow-up.
Then Forty Milliseconds Became Another Thirty Seconds
After restoring the encoder, the longer recording exposed a different bug. Whisper processing advances through timestamp-guided windows. In the five-minute fixture, progress reached 299.96 seconds. That left just 40 milliseconds.
The runner launched another padded 30-second inference window for that remainder. It hallucinated another sentence and reported a timestamp beyond the end of the recording. This was not the same wrong-buffer bug. It was a long-audio windowing problem in the runner.
The repair consumes timestamp-sized tails of 100 milliseconds or less without launching another padded inference window. In this fixture, the final consumed source position becomes exactly 4,800,000 samples: 300 seconds at 16 kHz. The threshold is a deliberate boundary policy with tests, not a general instruction to discard arbitrary quiet speech.
My Recording Is Now A Regression Fixture
We took the first five minutes of the final MIC1 recording, converted it to 16 kHz mono, and checked it in losslessly as FLAC with a corrected reference transcript. The public corpus records audio hashes, duration, model identifiers and acceptance thresholds.
The gate checks more than whether a process exits successfully. It checks source progress, timestamp bounds, completion, minimum transcript length, sufficient windows and normalized word error rate. A transcript containing only “The” must not count as a successful five-minute transcription.
The short token-exact oracle still has a purpose. The longer recording adds a different test: can the complete system keep processing realistic speech across multiple windows without losing its place? Different Whisper sizes can produce different valid words, punctuation and token sequences, so this corpus uses a defined word-error policy rather than requiring every size to produce identical tokens.
What The Nightly Evidence Actually Shows
When PR #455 was merged, the reported physical certification on this new corpus was for Base. As of this September 5 review, scheduled run 33950678686 has published passing certification artifacts for all five sizes. I downloaded those JSON reports rather than relying only on the green workflow badge.
| Model | Word error rate | Configured maximum | Windows | Duration |
|---|---|---|---|---|
| Tiny | 18.55% | 35% | 11 | 300 seconds |
| Base | 5.65% | 28% | 11 | 300 seconds |
| Small | 5.36% | 22% | 11 | 300 seconds |
| Medium | 4.93% | 20% | 12 | 300 seconds |
| Large-v3 | 6.38% | 18% | 11 | 300 seconds |
This is one English recording against a 690-word reference, not a general model ranking. Large-v3 did not score best on this sample. WER counts substitutions, deletions and insertions relative to the reference; it is not a percentage of sentences understood.
The scheduled run used commit 117f83a1. The local source reviewed for this article is newer, 075464be, and includes PR #457. These are different evidence points. The newer main-branch workflow I checked passed its build job but skipped the five-minute matrix by design: that matrix runs on scheduled or manual dispatch, not every push. I am not presenting the scheduled artifacts as a fresh five-model run of the newest commit.
The workflow gives each size its own job, does not use continue-on-error for certification, and treats missing evidence files as an error. That makes an attempted run's failure visible. It does not mean the test runs on every event or can never be prevented from starting by infrastructure problems.
What Would Make This Harder To Repeat?
The immediate safeguards are explicit circuit declarations, validated interfaces, missing-binding errors, focused regression tests and a real artifact-backed transcription gate. On the pulled main revision, the focused audio suites passed 48 tests and 42 subtests; two optional-dependency tests were skipped. That local result is useful, but it is not a replacement for executing all five models.
There is still work worth doing. The configured WER ceilings are considerably looser than the measured results, so a meaningful quality regression could remain below the failure threshold. We should track change from the accepted baseline as well as catastrophic failure. The corpus pins the audio hashes, but model names alone are not immutable checkpoint revisions; the runtime reports' weight and configuration hashes help provenance, and explicit checkpoint revision pinning would strengthen reproducibility further.
I also want clean conversion and compilation checks after changes to circuits, kernel maps or lowering. A cached runtime can demonstrate that an old artifact still works without proving that today's compiler regenerates it correctly. More speakers, silence patterns, technical vocabulary and recordings should follow this first fixture.
We have identified the failure mechanism. I am not claiming this article establishes the exact original commit that introduced the Whisper alias regression. That requires a reproducible history bisect, not an assumption that the latest large change must be responsible.
Back To The Video
CKE's Whisper transcript became one input to the editing workflow. FFmpeg handled audio cleanup and video edits, and Kdenlive was used for review. The waveform came from the microphone audio, not Whisper. Speech timestamps helped locate pauses, but we still had to inspect the video so a useful animation was not removed just because I stopped talking.
You can watch the finished video: How AI Runs on CPUs: A Beginner's Guide to Kernels | CKE Part 2. This is the recording we used for the CKE Whisper transcription and assisted editing workflow described here. CKE supplied the transcription, not the video editor itself.
That is the kind of progress I want from CKE: use it for something I actually need, understand where it breaks, and turn the failure into evidence the next change has to survive. I would rather have this recording sitting in the test suite than another claim that the architecture is robust.
If you want to reproduce the workflow, see the Whisper E2E documentation and the contributor guide. The relevant changes are PR #455 and the audio follow-up in PR #457. The next useful contribution might be another recording, a better failure fixture, or a compiler test that catches the wrong connection before it reaches a user.
Related Notes
- How Audio Becomes Words: Whisper's Kernels Step By Step On A CPU explains the audio pipeline behind this failure.
- How CKE Made Whisper Faster In Two Days connects optimization work to numerical evidence.
- A Green Checkmark Should Name Its Machine explains why test reports need hardware and execution context.
- CKE Now Runs More Than Qwen provides context for the expanding model portfolio these shared compiler contracts must protect.
- Qwen3.8 Broke In CKE shows how a different compiler defect exposed the same need for pinned, recurring end-to-end tests.