v2.25.1 — surfaces that stated things that were not true¶
Released 2026-08-17. Upgrade:
Every fix here is the same shape: a command printed something confident and wrong. None of them crashed, none failed a test, and every one was found by running YazSes on a real machine and reading what it said — several of them within minutes of each other, because once you start comparing what two commands say about the same thing the disagreements are not subtle.
Three of these describe the same underlying fact, arrived at from three directions: speech models answer near-silence with a confident invented word rather than with nothing. Nothing in YazSes accounted for that.
Your microphone gate may be below your room¶
yazses doctor --mic exists to warn when the room's resting noise level already reaches vad_threshold — because then ordinary silence passes the gate, reaches the model, and is transcribed. On a real machine it printed:
0.0010 is not under 0.0005. The warning was conditioned on not stats.is_silent, and is_silent is measured against a fixed floor (0.002) that has nothing to do with your gate — so for any vad_threshold below that floor, the warning was suppressed across exactly the band where the gate sits under the room, and the OK branch then asserted "under" for a value that was over.
The guard was disabled precisely when it was needed. It now compares against your gate and nothing else, and says what the consequence is: silence passes and is typed as invented words. The fix is yazses mic-level --set.
Silence transcribed to a confident word¶
Two seconds of digital silence through yazses transcribe:
A word, with a start and an end time, present in the JSON as an utterance. The empty-transcript note added in v2.25.0 cannot see it — the transcript is not empty.
No property of the output separates an invented word from a real one, so the check is on the input, where it is unambiguous: audio with no signal in it cannot contain speech. A muted microphone, an input device held by another application, and capture pointed at the wrong device all produce exactly this, and all three are ordinary.
Measured on the peak, not the mean — an hour of interview with sparse talking averages to almost nothing, so a mean-based gate would call a real recording silent.
yazses verify reported a count instead of the word¶
Run in a quiet room with nobody speaking:
[OK] Signal: level 0.0013 clears the gate (0.0005)
[OK] Transcription: produced 1 word(s)
✓ Dictation works end to end on this machine.
The one word was the same hallucination. A count cannot be checked against what you said, so it cannot contradict anything. The line now reads heard "You" — the person running this is the only one who knows what they said, so the evidence belongs in front of them.
yazses report understated the learning corpus 430x¶
Two surfaces, one corpus:
report sized corpus.db and nothing else; the encrypted audio clips beside it are almost all of a real corpus. That number is what gets attached to bug reports, so a maintainer reading 3 MB rules the corpus out of a disk problem it is causing — and it is what you check against [learning] max_corpus_mb, so someone 2.5× over the cap reads it as comfortably under.
The release gate certified a platform on one architecture of a pair¶
release-complete.yml counts two bundles per platform and explains why: "at least one .dmg" is what let v2.20.0 and v2.21.0 print All platforms published while carrying no Intel bundle. The wait was hardened at the time; the check it delegates the verdict to was not, and that check also decides whether an incomplete release keeps the "Latest" label. A release carrying only an arm64 .dmg passed it, was never demoted, and went on pointing Intel users at a download that did not exist.
Run against the real releases after the fix — v2.20.0 and v2.21.0 now report exactly the halves they shipped without, and v2.25.0 passes with both.
A second gate fix: the wait covered four of the five channels the tag push publishes and omitted the container image, so the report named Docker missing while it was still building. Both the wait and the verdict now go through one implementation, which is what let them drift apart in the first place.
Also¶
yazses tunelooked like a hang. Against a real corpus it printed one line and nothing more for over eight minutes — the re-transcription of 3280 clips, silently, on a run that would take about two hours. The count is a metadata query known before any audio is touched, so it now announces the total and counts up.- A missing file was reported as a format problem. Asking the MCP server for a path that does not exist answered "probably not an audio or video file, or it is truncated" when the real error was
No such file or directory— sending the reader to inspect the file's contents instead of its name.load_audiohad promisedFileNotFoundErrorin its docstring and never raised it. - Two status lines that read as faults.
meeting listdescribed an undiarized 8081-second meeting as0 speaker(s), which reads as a failed recording rather than as speaker labelling never having been attempted; it now saysnot diarized. Andyazses statusprinteduptime: 48176.17s— thirteen hours, in seconds, to two decimals never measured. - A privacy guard answered differently per Python. Carried over from v2.25.0's cycle:
is_loopback_endpointtrusted a stdlib predicate that changed behaviour in 3.13, so an IPv4-mapped loopback endpoint was refused on 3.11 and 3.12.