ADR-034 — Whether to recommend Parakeet where it loads (default-engine decision, proposed)¶
Status: Proposed (2026-11-04; figures and file references re-checked against main on 2026-11-05) · no runtime, config, default, CLI or test change; awaiting the maintainer's decision
Decision owner: YazSes maintainer (pending). Changing [stt] engine's default is L3 work (AGENTS.md, "Public interfaces").
Tracking: #645 (TRUTH-ENGINE-002)
Context: ADR-030 §2 Pillar 1.3, ADR-033 (Proposed), ADR-011, ADR-019, ADR-021, ADR-028
Evidence labels: [R] a file in this repository says so (path and conditions quoted) · [F] an upstream model card says so, as cited in src/yazses/language/capability.py · [O] engineering judgement · [U] unmeasured. Nothing in this ADR was benchmarked for it; every figure is quoted from an existing file, and where a comparison the decision needs was never made on comparable conditions, it says unmeasured and does not estimate.
Context¶
ADR-030 Pillar 1.3 says the engine question is answered by measurement, that a change of default engine is an L3 config change needing its own ADR, and that a Parakeet that fails to load must say so loudly. The loudness half is done (#644, CHANGELOG 2.45.0: yazses status names the decoding engine and prints a FALLBACK: line). This ADR is the other half: should YazSes recommend Parakeet, and how?
What is measured¶
All of the following is from docs/benchmarks.md, section "Every engine, measured against every other" [R]: 200 LibriSpeech test-clean utterances (speaker-stratified, 40 speakers), Whisper EnglishTextNormalizer, one 16-vCPU Intel Xeon Platinum 8573C VM, Ubuntu 24.04, CTranslate2 4.8.1, int8 on CPU, every engine built through stt.factory.build_engine.
| Engine / model | WER | 95 % CI | Sub / Del / Ins | RTF (lower = faster) |
|---|---|---|---|---|
parakeet-tdt-0.6b-v2 | 2.06 % | 1.54–2.68 | 73 / 12 / 11 | 0.050 |
small.en | 2.66 % | 2.05–3.28 | 100 / 16 / 8 | 0.092 |
large-v3 | 3.23 % | 1.95–5.00 | 62 / 8 / 89 | 0.451 |
base.en (shipped default) | 4.01 % | 3.21–4.87 | 141 / 16 / 30 | 0.042 |
Same page, section "How much worse: the same models on test-other" [R] (200 utterances, 33 speakers, same machine and method): Parakeet 2.88 % (1.4x its clean figure), small.en 5.59 %, base.en 9.46 %. Same page, "The same number, measured twice": Parakeet and base.en were bit-identical across repeated runs on both splits [R].
Readings the page itself supports, and two it does not:
- Against the shipped default on this corpus and machine, Parakeet's point estimate is about half
base.en's WER on clean audio and under a third ontest-other(2.88 % vs 9.46 %). The two clean-split marginal intervals (1.54–2.68 vs 3.21–4.87) do not overlap, but that is not a paired test; no paired, speaker-clustered test was run [U]. The page itself warns that Parakeet vslarge-v3overlaps and is "not something 200 utterances establish". - The
large-v3row is one of several runs on this machine (test-clean: 3.23 %, 3.41 %, 3.98 %; ontest-otherthe page says it "cannot be ranked at all"). The Parakeet,base.enandsmall.enrows were identical in every run [R]. Quotinglarge-v3at 3.23 % is therefore the favourable end of its range, which is also the figureyazses featuresand ADR-030 use. - Parakeet is not faster than the default: RTF 0.050 vs 0.042 on the same box, i.e. about 19.8x vs 24.1x real time (same table). "About twice
small.en's speed" (0.092/0.050) is true but is not the comparison a default change makes. - Everything is read audiobook speech [R]. The page says its own numbers are "a comparison between models, not a promise about your desk". Spontaneous dictation, accented speech and a real microphone are [U] for Parakeet.
What is not measured [U]¶
- Parakeet on a consumer laptop CPU: the only Parakeet row is the Xeon VM above. The laptop tables in
docs/benchmarks.mdanddocs/models.md(i7-1370P; Ryzen 5 PRO 4650U) contain no Parakeet row. - Release-to-final latency, cold model-load time and resident/peak memory for Parakeet. The upstream card for v2 states only "at least 2GB RAM for model to load" [F]. The latency figures elsewhere in
docs/benchmarks.mdanddocs/models.mdare single-run historical numbers that the pages themselves say were never reconciled with the Xeon matrix; do not mix the two sets in one comparison.docs/benchmarks.md"Memory" anddocs/models.mdlisttiny.en,base.en,small.enonly (base.en: 202 MB after load, 342-344 MB peak, Ryzen 5 PRO 4650U, 2026-10-21). - Behaviour on silence and trailing room tone.
src/yazses/stt/parakeet.pystates Parakeet "does not hallucinate text on silence"; the measurement behind it is 11 inserted words vslarge-v3's 89 on 200 utterances of speech. That is an insertion count on speech, not a silence test. - Whether losing
initial_promptpriming costs a user with a personal vocabulary more than the engine gains; and how well[stt] vocab_correctionsubstitutes. Neither was compared. - Parakeet TDT v3 (25 European languages [F],
language/capability.py): no YazSes measurement of any kind. - macOS and Windows dictation are still labelled preview (ADR-030 Pillar 1.1); Parakeet there is a fortiori unverified.
- How often Parakeet fails to load across real installs. Not measurable by design: there is no telemetry (AGENTS.md rule 1, ADR-011). Only opt-in reports can inform it.
Facts about the engine that any recommendation must carry¶
| Fact | Source |
|---|---|
English-only for the default checkpoint nemo-parakeet-tdt-0.6b-v2 ("designed for high-quality English transcription") | src/yazses/language/capability.py [F] |
A [stt] language the resolved engine cannot do is refused (LanguageUnsupportedError), not fallen back from | src/yazses/stt/factory.py (#515) [R] |
initial_prompt is accepted and ignored; task="translate" is unsupported; transcribe_words returns no word timings, so prosody and confidence decorations are skipped | src/yazses/stt/parakeet.py [R] |
The personal dictionary reaches Parakeet only through [stt] vocab_correction, which is False by default | src/yazses/config.py line 120; docs/models.md [R] |
Model download about 600 MB on first use (stt-parakeet ~604 MB, 1 package) vs base.en 148 MB, so about 456 MB more | docs/install-cost.md; docs/models.md [R] |
The dependency onnx-asr is an optional extra (stt-parakeet), imported lazily; the Linux snap does not bundle it; the Windows installer bundles the library but not the model | src/yazses/system/features.py; docs/install-linux.md; docs/install-cost.md [R] |
The feature is tier OPTIONAL, so the first-run seeded config (system/firstrun.py::ensure_recommended_config) does not enable it; no setup flow offers an engine choice today | src/yazses/system/features.py, firstrun.py [R] |
A failed load degrades to faster-whisper base.en, with a FALLBACK: line in yazses status and a doctor WARN for a missing dependency. Doctor reads the environment (find_spec), so it cannot see an installed package whose model fails to load | stt/factory.py; system/doctor.py::_configured_engine_check; docs/architecture.md [R] |
Why "where it loads" is not a formality¶
Parakeet has failed silently in practice, for reasons that were not the user's: CHANGELOG 2.37.2 records that uv tool upgrade deleted an enabled Parakeet's onnx-asr and dictation fell back to a smaller Whisper model "with nothing surfaced anywhere" (fixed; the 2.44.0 entry "an update could still delete an enabled feature's libraries" closes the remainder). That 2.37.2 entry and docs/architecture.md both say the configured-but-absent case was found on a real machine: engine = "parakeet" with onnx_asr missing, decoding on base.en. A separate CHANGELOG entry ("Cache-first model loading left offline mode switched on, so Parakeet could never download") records that features enable stt-parakeet appeared to succeed while dictation stayed on faster-whisper. All three are fixed and now visible; they show that "configured" and "running" have differed for real users, which is why a load probe is part of Option B. How many installs are affected today is [U].
Decision options¶
The maintainer is asked to choose one. None is implemented by this ADR.
Option A — Keep faster-whisper base.en as the default and make no new recommendation¶
Parakeet stays as today: documented in docs/models.md ("best English accuracy per unit of CPU"), listed in yazses features, enabled by the user with yazses features enable stt-parakeet.
- Privacy / rule 1: unchanged; the only network use remains the user-initiated model download.
- Rule 3: unchanged; extra stays optional and lazy.
- Rule 2: nothing new, so nothing to default off.
- Cost: users who would benefit never learn of it unless they read the models page. The
yazses featurestext forstt-parakeetalready states 2.06 % againstlarge-v3's 3.23 %, English-only and the ~600 MB download (src/yazses/system/features.py), but it does not compare Parakeet with the shipped default (base.en, 4.01 %), which is the comparison a user deciding whether to switch needs. So discoverability is partial rather than absent.
Option B — Recommend Parakeet only where it loads and passes a probe; never switch automatically¶
A recommendation, surfaced as advice, never a config write. It would be shown only when all hold:
[stt] languageis supported by the Parakeet checkpoint perlanguage/capability.py(initiallyenwith v2 only; v3 languages only after they are measured);onnx_asris importable;- the checkpoint is already cached, so the advice and the probe cause no download. The existing
stt.download.is_cachedis built for Whisper repo names; whether it detects the onnx-asr cache layout is not verified here and would have to be established first; - a smoke load and one decode of a bundled or synthetic clip succeeds with
describe_active_engine(...)["engine"] == "parakeet"and nofallback_from. Loading a ~600 MB model costs seconds and memory, so this would be an explicit user command, not a background check. [O]
Surfaces, in increasing order of reach; the maintainer may take any prefix:
- B1:
featuresadvice. Already largely present. The change would be wording only: state the measured conditions (Xeon VM, clean read speech) and the English-only, no-priming and download costs beside the WER, so the claim is not read as a laptop dictation promise. - B2: a
yazses doctor/yazses statushint when conditions 1-3 hold and the engine is still faster-whisper: one line, naming the enable command. New wording, no behaviour change. - B3: an offer in a setup or first-run flow. There is no engine-choice step today. This adds one, so it is the largest scope, and ADR-030's freeze permits only work within the four pillars (Pillar 1.3 arguably covers it).
Consequences:
- Rule 1: no new egress. The ~600 MB download already exists behind
features enableand is already classified; B must not trigger it, which condition 3 enforces. - Rule 2: advice only, so an existing install is unchanged until the user acts.
- Rule 3: no change to dependencies.
- The probe (condition 4) is new code and needs tests with a fake
onnx_asr; the pure/injected-backend split of AGENTS.md rule 5 applies. - Residual risk: a user acts on a recommendation grounded in read-speech WER and gets worse results on their own vocabulary (no priming). Mitigated by stating the cost in the advice; not eliminated, because the size of that effect is [U].
Option C — Make Parakeet the default where it is installed¶
e.g. an engine = "auto" or a changed default that selects Parakeet when onnx_asr is present and the language is en.
- Rule 2: this is the opposite of "an existing install is unchanged until the user opts in". Any existing install that has the package (the feature enabled for any reason, or a Windows installer, which bundles the library) would change engine on upgrade.
- Rule 1 / ADR-019: on an install that has the package but not the checkpoint, the first load would start a ~600 MB download the user did not request. That would need an explicit escalation entry or a rule that it never downloads implicitly; the second makes "default where installed" mean "where installed and cached", which is Option B's condition set.
initial_promptpriming andvocabwould silently stop applying for those users; the existing vocabulary feature is documented as priming the decoder (docs/settings-gui.md).- Word timings and translate would disappear for them (see facts table).
- Evidence needed for C is the entire list below, not part of it. It is the only option that changes what existing users get without their action.
- A silent-fallback incident under C changes from "user chose Parakeet and lost it" to "user never chose Parakeet and was moved off it", a worse honesty position even with #644's status line.
Option D — Make Parakeet the default for every fresh install¶
Listed for completeness; not proposed. It makes a ~600 MB download part of first run (against rule 3's "a fresh install with no extras must import and run"), is English-only against a project whose language plan includes Persian and Mandarin work (Persian is not in the v3 list either, language/capability.py), and is unsupported by the evidence above on every [U] item.
What evidence would settle it¶
Per ADR-033 (Proposed), a new default-engine comparative conclusion needs its protocol v1: pinned model/runtime identity, the resolved engine asserted (the benchmark must not score a silent Whisper fallback as Parakeet), per-sample failures kept in the denominator, speaker- clustered paired uncertainty, warmed decode separated from cold load and release-to-final. If ADR-033 is not accepted, the same requirements stand as the bar this ADR sets for itself.
| Needed for | Measurement | Today |
|---|---|---|
| B1, B2 | None beyond quoting the existing Xeon rows with their conditions and the English-only caveat | Available [R] |
| B2, B3 | Parakeet vs base.en on a consumer laptop CPU: WER, release-to-final p50/p95, cold load, peak RSS | [U] |
| B3, C | Paired speaker-clustered WER difference, Parakeet vs base.en, on test-clean and test-other | [U] (marginal intervals only) |
| B3, C | Spontaneous / real-microphone speech (the protocol names Common Voice Spontaneous Speech as a candidate) | [U] |
| B3, C | Silence and no-speech stress: words inserted per second of non-speech | [U] |
| C | Personal-vocabulary accuracy: Whisper with initial_prompt vs Parakeet with vocab_correction, same word list | [U] |
| C | Probe pass rate across real installs on Linux, macOS, Windows, snap, .exe | [U], opt-in reports only |
| any multilingual claim | Parakeet v3 per-language results | [U] |
Assessment¶
My reading of the evidence, with confidence stated.
- High confidence: the evidence does not support C or D. C changes what existing users get without opt-in (rule 2), and most rows C needs are unmeasured.
- Moderate confidence: the evidence supports B1 and B2 for English-configured users whose Parakeet already loads. Basis: a 2x lower point-estimate WER on clean read speech and under ⅓ on
test-otherthan the shipped default on one machine, bit-reproducible, with the costs (English only, no priming, 456 MB more download, decode no faster thanbase.en) stated in the advice. Why only moderate: one machine, read speech only, no paired test, and the user-visible effect on personal vocabulary and latency is unmeasured. - Low confidence, and I do not recommend it on current evidence: B3, because it puts the advice in front of people who have not looked for it, before laptop latency and vocabulary cost are known.
- A is defensible if the maintainer judges that advice beyond what
yazses featuresalready says is not worth the surface. The evidence neither requires nor forbids it.
Decision needed from the maintainer¶
- Choose A, B (and how far: B1 only, B1+B2, or B1+B2+B3) or C/D. This ADR recommends nothing beyond B1+B2 on current evidence.
- If B: is the probe (condition 4) an explicit command, a
doctorflag, or dropped in favour of the cheaper conditions 1-3? - Is ADR-033's protocol the required bar before B3 or C, or is a smaller matched run enough?
- Which CPU classes count for the laptop run (the table above leaves this open)?
- If any option is accepted: is it an ADR-030 Pillar 1.3 act, or does it need an amendment under the breadth freeze?
Non-goals¶
No default, config key, code path, CLI flag, test or dependency changes. No new benchmark was run. No claim about Parakeet on hardware, languages or speech styles listed [U]. Nothing here is accepted until the maintainer changes the status line.