# v2.37.0 — the confined snap could not type, could not be launched, and could not say why

**Released 2026-09-19.** Upgrade:

```sh
sudo snap refresh yazses     # snap
pipx upgrade yazses          # or: uv tool upgrade yazses
scoop update yazses          # Windows
```

The full list is in the [CHANGELOG](https://github.com/MSKazemi/yazses/blob/main/CHANGELOG.md).
What follows is what actually affects you.

## The snap could not be used on the desktop it mostly runs on

Three findings, each verified by running the shipped product rather than by reading the
repository, and each invisible from inside it.

**Wayland keystroke injection now works under strict confinement.** The Snap Store
description said, in its own words, *"this strictly-confined snap supports hold-to-talk
dictation on X11 only."* Store metrics say who read that: of 59 installs on 2026-09-10, at
least 39 were on a desktop that defaults to Wayland — ubuntu 24.04, ubuntu 26.04, debian 13,
fedora 44, ubuntu 25.04 — and the base was shrinking, 11 new against 15 lost per week. A new
`inject/portal.py` backend types through
`org.freedesktop.portal.RemoteDesktop`, the one route that survives strict confinement:
`ydotool` needs a udev rule a strict snap cannot install, and `wtype` needs a protocol GNOME
and KDE deliberately do not implement — the two desktops this base actually runs. It types
by keysym rather than keycode, so it does not type `qwerty` into an AZERTY user's editor.
Verified end to end: a probe window read back every character `PortalInjector` typed through
the real GNOME portal, and a persisted restore token made the second and third run complete
in 4 seconds with no consent dialog.

**The snap had no application launcher, on any desktop, ever.** `snapcraft.yaml` declared
four apps and none carried a `desktop:` key, so nothing was exported to
`/var/lib/snapd/desktop/applications/` — verified against a real machine, where firefox,
vlc and snap-store are all in that directory and yazses was not. Every install from GNOME
App Center, KDE Discover or the snapcraft.io web button finished with nothing to click, and
nothing said a terminal was required. The launcher opens Settings rather than starting
dictation — an app-grid activation has no terminal, and it is also the one surface that can
now say the required interfaces are not connected, with a copyable command to fix it.

**A snap that cannot hear you started saying so.** Both interfaces YazSes needs are
manual-connect, and without them the daemon starts *perfectly*: the model loads, the state
machine reaches `IDLE`, `yazses status` reports healthy — and the microphone is never
opened. `yazses doctor`, daemon startup and a desktop notification now all check and report
this, answered as three-valued (connected / not connected / could not determine) rather than
guessing in either direction.

Alongside these: the store listing's own summary and description were rewritten (the
Wayland-only caveat is gone, since it is no longer true), the listing artwork was the
retired blue-speech-bubble logo and is now generated from the current brand mark, and a
permission dialog that could be raised behind whatever window was in front is now negotiated
at daemon startup instead of on the first hold-to-talk release.

## Packaging: Chocolatey, Fedora, and a reopened Microsoft Store route

**Chocolatey would have failed every install on a checksum mismatch.** The package has
never actually published — a separate, still-open gap is a missing API key — so this bug
had not reached anyone yet, but it would have failed the first install the moment publishing
starts. `render-chocolatey.py` built the download URL and the checksum independently — the
URL hardcoded `windows-x64.exe`, the checksum took the first `.exe` line in
`SHA256SUMS.txt`, which is arm64. Both now derive from one source, so naming two different
files is no longer representable.

**The Fedora COPR served a release seventeen versions old — where it existed at all.**
`packaging/fedora/yazses.spec` had carried `Version: 2.18.2` since it was written; bumped to
2.36.0 and verified in a clean `fedora:41` container. Separately, the COPR repository the
docs had told people to `dnf copr enable` since the spec was written did not exist yet. Both
are fixed: the repository is live, serving the current release for Fedora 43/44 (x86_64,
aarch64) and EPEL 10 (x86_64).

**The Microsoft Store route is open again, without a paid certificate.** The earlier
assessment that Store distribution needed a purchased code-signing certificate was wrong:
that requirement applies only to the EXE/MSI direct-download path, and an MSIX is signed by
Microsoft during certification. Packaging as MSIX does not force the AppContainer sandbox
either, so the app keeps the same `mediumIL` + `runFullTrust` integrity the unpackaged
`.exe` already runs at. A new `msix-validate` workflow runs `makeappx` for real and asserts
the built package ships unsigned.

**Fourteen `except IpcUnreachableError:` handlers were dead code on Windows.** `yazses
start` printed a traceback while the daemon it was polling came up fine a second later, and
`yazses restart` crashed outright on `signal.SIGKILL`. Two identically-named exception
classes with no relationship meant the Windows transport's error was never the one every
caller was written to catch. Reported by [@fall-water-zxc](https://github.com/fall-water-zxc)
on two independent install routes, fixed by [@auroraxo](https://github.com/auroraxo).

## Dictation

An opt-in fifth injector backend, `inject/unicode_injector.py`, types the non-ASCII
characters the Wayland `ydotool` path silently drops — accented letters, most non-Latin
scripts — by resolving each character through `libxkbcommon`'s XKB state. Ships non-default:
real Wayland hardware validation is still pending. Contributed by
[@vortsghost2025](https://github.com/vortsghost2025); merging it also surfaced and fixed a
pre-existing bug where `[injection] backend = "portal"` was silently reset to `"auto"`.

## Security

`lightning` (CVE-2026-58659) now has a patched release — 2.6.6 restricts the checkpoint
`_instantiator` hyperparameter to an allowlist, closing the arbitrary-code-execution path a
malicious checkpoint could take through the opt-in pyannote diarization backend. `uv.lock`
now resolves `lightning>=2.6.6`; the three compensating controls documented for this
advisory (opt-in extra, non-default backend, hardcoded checkpoint ids) are unchanged and
still apply, as defense in depth rather than a replacement.

## Localization

All 25 draft translation pages pointed their one reviewer-recruiting sentence at that
locale's **closed** `Translate the README` issue instead of the live, open `Review the
<language> translation` issue — so the sentence whose entire purpose is to recruit a
reviewer sent every reader who clicked it to finished, locked work. Found for Brazilian
Portuguese by [@YuuGR1337](https://github.com/YuuGR1337); the same shape held for all 25 and
every one is repointed.

## For maintainers

Two release-day CI waits were right about the wrong signal. The PyPI-readiness wait for the
Docker build read a representation of the package index that pip does not actually resolve
against, so it reported success fifteen seconds before the real build failed — it now runs
`pip download --no-deps`, the resolver that actually fails. The Windows-manifest wait
treated "the optional arm64 leg has not finished" and "it legitimately has none" as the same
observation, so it published ARM-less Scoop and winget manifests forty minutes before that
`.exe` finished uploading; it now waits for the producing workflow **runs** to finish before
checking for the asset. Separately, a re-run of the snap publish step uploaded a fresh store
revision unconditionally, even for an unchanged release — accounting for most of ~200 "your
revision was rejected" emails; it now asks the store first. And the GUI test job selected
its files from a hand-written list of nine, so a tenth test file joined nothing; it now globs.

## Upgrading

Your config, models and learning corpus are untouched.
