# v2.17.0 — what real use found in a day

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

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

[v2.16.0](v2.16.0.md) made the snap a first-class channel. Within a day of people actually
using it, three defects surfaced that no amount of unit testing had caught, because each
needed a real desktop, a real microphone and a long sentence.

## Streaming dictation deleted text it had never typed

Reported as: a long dictation ends in a flood of repeated characters, then the correction
pass removes text you wanted to keep. Three separate defects, each able to cause it alone.

**A fixed timeout on the X11 injector.** `XdotoolInjector` used `timeout=10` on every
method. At `--delay 12` that expires around 833 characters — and it expires *after* xdotool
has already typed part of the text. The caller sees a failure for work that partly
happened, `LinuxInjector` reads that as a broken backend and falls back to the clipboard,
and the text lands **twice**. `YdotoolInjector` has scaled its timeout since the Wayland
flood fix, and its comment says exactly why; the X11 path simply never got the same fix.
Timeouts now scale with the keystrokes actually requested.

**The correction pass hit the same wall.** Committing a streamed burst sends one
`shift+Left` per typed character, so a long dictation crossed the timeout twice — once
selecting, once retyping. A run of one repeated key now goes out as a single `--repeat`
spec, the way `inject_backspaces` always has.

**A genuine race.** `inject_partial` runs on the daemon's poll thread while `commit` runs
on hold-release, and the daemon's `join(timeout=1.0)` cannot outwait an injection allowed
ten times that. A partial could land *after* `commit` had read the character count, leaving
`shift+Left × N` selecting a span that no longer matched the screen — so the correction ate
whatever happened to sit next to it. Every mutation now happens under one lock held across
the injection itself, and a committed injector is **sealed**: a late partial is dropped
rather than typed behind the final text.

Verified red/green — the new behavioural tests fail on the previous code and pass on this.

## A fresh snap install never mentioned `raw-input`

`snap install yazses` leaves **both** `audio-record` and `raw-input` unconnected. snapd
auto-connects neither, and a snap cannot connect its own. That produces the two most
visible failures available — it cannot hear you, and it cannot see the hotkey — and the
daemon starts and reports healthy in both cases.

`yazses setup` / `start` already surfaced the microphone. It now surfaces `raw-input` too,
so the tool says what is wrong instead of leaving it to documentation nobody re-reads after
installing. The Snap row in the install guide lists every required step, including
`yazses setup` — which it told `pipx` users to run but never snap users.

```sh
sudo snap install yazses
sudo snap connect yazses:audio-record   # microphone
sudo snap connect yazses:raw-input      # hold-to-talk key
yazses setup
```

## `yazses start` now survives a reboot

`install_autostart()` existed so that a `pipx` / `uv tool` / `pip` install gets a login
service like the packaged ones do — its own docstring says *"a daemon you must remember to
launch is not a daemon."* It had exactly one caller: `yazses autostart enable`, a command
you only find if you already know it exists. The ordinary path was install → `yazses start`
→ dictate happily → reboot → the daemon is gone, with nothing anywhere saying why.

`yazses start` now installs the login service once the daemon is actually up, and says so
the single time it does. Best-effort by design: a daemon that died during startup is never
scheduled to run at every login. `yazses start --no-autostart` opts out.

## Five default filler words were load-bearing content

`like`, `right`, `sort of`, `kind of` and `actually` shipped in the default
`[filters.disfluency] filler_words`. Each is a hesitation in some positions and meaning in
others, and the filter cannot tell them apart — so a hedge became a fact
(`she is sort of stable` → `she is stable`), a negated assessment lost its predicate
(`that dose is not right` → `that dose is not`), and a correction marker was erased. YazSes
is used for clinical and legal notes, where a confident falsehood is worse than a visible
disfluency. All five are removed from the defaults and remain available to anyone who wants
aggressive filler removal. Contract **5.1.0 → 6.0.0**.

## Also

- **Style-Consistency Enforcer** now reads a config-driven rules source (#36)
- **`yazses gitvoice`** — the Voice Git Choreographer is wired up (#37)
- **Diagrams-as-Code by voice** parses a whole graph, not just one edge
- **Tray → Settings…** opens the graphical settings window
