Commit graph

3 commits

Author SHA1 Message Date
Doxa Maps
46a53f0b4e The carried commits keep the reason and drop the speaker
Thirteen lines arriving in this landing named or quoted the Driver: the
packet renderer and its two gates, and the desktop build. check:no-new-driver-references fails on each of
them, so they are reworded here the same way as the sweep: the date and
the requirement stay, the speaker and the quote go.
2026-09-29 05:26:26 +00:00
Doxa Maps
c067a5d069 Dictation fell behind because our own build took every core
Rudder was measured slowing after about 1,400 words while a Tauri build
ran. The word count is incidental — it is a proxy for how long the build had
been going. The speech model runs on the CPU (backend/rudder-engine starts it
with --device cpu), and a Rust build saturates every core, so at equal priority
it starves the one process whose latency a person can hear.

Three changes, and the direction of the first is forced rather than chosen:

1. internal/desktop-build.mjs nices the whole build tree to 10, through the one
   run() helper every step goes through, so cargo, rustc and the linker inherit
   it. We nice the COMPETITOR because an unprivileged process cannot raise its
   own priority on Linux — a negative nice needs CAP_SYS_NICE — so "promote the
   ASR" would fail with EPERM. If nice(1) is missing the build still runs and
   says so, because a silent fallback would look exactly like the fix working.

2. cargo is capped at cores-1. nice decides who wins a CONTESTED core; it does
   not stop the build taking all of them, and a fully subscribed machine still
   adds scheduling latency to the audio path. An explicit CARGO_BUILD_JOBS is
   honoured rather than overridden.

3. yieldCPU reports its error instead of discarding it. It was
   `_ = syscall.Setpriority(...)`, which cannot fail visibly — a call that
   silently does nothing is indistinguishable from one that worked, and this one
   guards something audible.

Also, one real O(n) in the widget, found while checking studio's answer that the
collapsed pill already shows the last words: sendActivity split the ENTIRE draft
on every activity tick to take five words. Measured at 3,000 words: 1.61ms per
tick against 0.051ms for a bounded tail, 31x, with byte-identical output.

Verify the priority work with `ps -o ni=` on the running cargo processes, never
by any of these calls returning.
2026-09-29 05:26:25 +00:00
Doxa Maps
6451a2b158 bun run desktop:build <plugin> packages a desktop plugin as an app; check:targets keeps non-web plugins out of the web build
A plugin's <profile>.meta.json targets (web, mobile, desktop, widget; absent = web)
now decide where it is built. internal/plugin-targets.mjs is the one reading.
desktop:build builds a desktop plugin into .desktop/<plugin>/ with a page that
names its engine, builds its backend as a Tauri sidecar for this machine, and runs
tauri build with a --config override; tauri.conf.json and public/ are untouched.
The shell starts the bundled rudder-engine (RUDDER_AUDIO=browser, RUDDER_HOME in the
app data folder) and stops it on exit. A plugin whose targets leave out web
(Rudder: desktop + widget) is no longer built for the web tree: run-parallel,
generate-tree and check-composite-freshness skip it, and its public/ folder is
removed; the dev server still gives the Studio its corner. check:targets
(gates:pre, with a self-test of five planted violations) validates the values,
widget corners and backend folders and fails if a non-web plugin reaches the built
tree. Measured: desktop:build rudder-voice on Linux produced Rudder_0.1.0_amd64.deb
(8.8 MB) with the app and the engine side by side; the app has not been launched.
2026-09-28 06:44:14 +00:00