Point-in-time review of the backend, frontend, Rust shell, and CI/hygiene, with per-area grades, file:line evidence, a priority list, and a follow-up ledger of what was fixed the same day.
16 KiB
Code Quality Audit — 2026-07-26
Four parallel reviews of the codebase at 0.6-dictation-fixes (88e72d5): Python backend, React frontend, Tauri/Rust shell, and CI/repo hygiene. Line references are against that tree. A follow-up section at the bottom lists what was fixed the same day.
Scope: first-party code only (~20k LOC Python, ~29k LOC TypeScript, ~6k LOC Rust, ~4.4k LOC backend tests).
| Area | Grade | One-liner |
|---|---|---|
| Python backend | B | Well-layered local-inference server with above-average concurrency engineering; test hygiene and ~1,000 self-inflicted lint violations drag it down |
| React frontend | B | Strict typing and clean state architecture; zero tests and 1,748 lines of dead generated API client |
| Tauri/Rust shell | B− | The dictation/clipboard FFI is excellent; main.rs god-file and audio modules a tier below |
| CI / repo hygiene | B− | Strong release engineering and docs; PR gate was typecheck + web build only |
Consensus: the hard 10% — GPU lifecycles, clipboard/focus FFI, release packaging — is done unusually well. The gap to A-territory is verification: broken test hygiene, a near-empty CI gate, and second-tier modules that never got the rigor of the flagship paths.
Python backend — B
main.py is 45 lines; the routes-refactor (commit 88536d2) split routes into 21 domain modules under routes/, with real layering: routes → services → backends → database. (PROJECT_STATUS.md still described the pre-refactor 2,850-line god-file.)
Strengths
- MLX serialization (
services/mlx_thread.py): single-worker executor with a docstring explaining why (Metal streams are thread-local, issue #699). Load-and-infer submitted as one job so unload can't interleave (backends/mlx_backend.py:270-274). - Serial generation queue (
services/task_queue.py): distinguishes cancel-while-queued vs cancel-while-running (:105-117), keeps background-task references against GC (:31-36), force-fails orphaned DB rows when the worker dies mid-write (:69-93), with matching route-layer recovery (routes/generations.py:245-259) and real behavioral tests. - Shared backend plumbing (
backends/base.py): centralized HF cache checks, device detection, CUDA compute-capability validation with actionable errors, and amodel_load_progress()context manager all 7 engines use (:234-295). - Lifespan care: FastAPI + FastMCP lifespans composed with an explicit LIFO-teardown comment (
app.py:134-151); startup marks stalegeneratingrows failed after a crash (app.py:295-303). - Hardening details: RFC 5987 filenames (
app.py:112-120), SPA path-traversal guard (app.py:219-225), upload limits enforced while streaming (routes/generations.py:422-434), documented float64→float32 patches for upstream chatterbox bugs (backends/base.py:298-332). - Comments cite issues and explain decisions (no-Alembic rationale in
database/migrations.py:1-18).
Weaknesses
- Broken test file committed:
tests/test_profile_duplicate_names.pyimported the pre-refactor layout and killed collection — nobody ran the suite green since the routes refactor. (fixed, see follow-up) - No
conftest.py; six files did per-filesys.pathhacks, making tests order-dependent. (fixed) test_cors.pytested a hand-copied mirror of the origin list that had already drifted fromapp.py(missinghttp://tauri.localhost). (fixed — now uses the realcreate_app())- API routes untested: no TestClient coverage of
/generate,/profiles,/stories; the retry/regenerate/cancel state machine inroutes/generations.pyhas zero coverage. - ~1,000 ruff violations against its own config. (auto-fixed ~900; remainder baselined in
pyproject.toml— see follow-up) - Silent clone degradation:
mlx_backend.py:252-257catches any generate exception and retries without the voice prompt — the user gets the default voice and the generation records as successful. Open. - Inconsistent load-race protection: Chatterbox/Hume double-check with an
asyncio.Lock; Kokoro (kokoro_backend.py:156-160) and LuxTTS (luxtts_backend.py:65) don't.get_stt_backend(backends/__init__.py:739-753) unlocked while TTS/LLM factories are locked. Open. - SQLite has no WAL / busy_timeout (
database/session.py:37-40) while the code works around "SQLite lock racing" in two places. Backlog PRs #666/#667 add exactly this. Open. - Registry didn't deliver on its promise:
backends/__init__.pystill has five per-engine if/elif chains (:513-656); adding an engine touches at least four places. Open. - Assorted: 46 deprecated
datetime.utcnow()calls, 14 Pydantic v1-styleclass Configblocks, pervasive defensivegetattr()on own ORM columns,except Exception: passon corrupt effects-chain JSON (routes/generations.py:122-124).
React frontend — B
web/ is not a duplicate: 182 LOC of platform adapters injecting a Platform interface via PlatformProvider (app/src/platform/PlatformContext.tsx), with the entire app shared through a Vite alias. Best structural decision in the frontend.
Strengths
- Typing discipline: strict mode +
noUnusedLocals/Parameters; exactly oneas anyin ~29k LOC (AudioPlayer.tsx:183). - State architecture: server state in 19 react-query hooks, client state in 8 small zustand stores; persistence partialized so audio drafts never hit localStorage (
uiStore.ts:100-103). useAudioRecording.tsis genuinely strong concurrency work: generation counters for stalegetUserMediaresults, coalesced in-flight acquisition, deferred release during capture, with comments explaining why.- Every mutation has an
onErrortoast;ProfileFormdoes client-side rollback with rollback-failure reporting (:709-739).
Weaknesses
- Zero tests, zero test tooling — riskiest for the pixel-math in
StoryTrackEditor.tsxtrim/zoom (:595-640,:1035-1065), the 4-branchonSubmitstate machine inProfileForm.tsx(:491-754), and Web Audio scheduling inuseStoryPlayback.ts. Open. - 1,748 lines of dead generated API client (
app/src/lib/api/{core,models,schemas,services}) imported by nothing, with stale types (missingengine,personality,effects_chain) sitting beside the real hand-written client. Delete it or commit to codegen. Open. client.tsDRY violations: the sameif (!response.ok)multipart block copy-pasted ~11 times;useStories.ts:79-229is 12 near-identical mutation hooks. Open.- 35
console.logcalls in production paths (model download, story store, SSE lifecycle) despite an unuseddebug.tsgate. Open. - i18n two-thirds done: 6 locales ship but ~24 feature components are hardcoded English, including all of
StoryTrackEditor,AudioPlayer,DictateWindow. Open. - Effect hygiene:
ClipWaveformrecreates WaveSurfer (re-fetching audio) on every zoom step;getEffectiveDurationrecreated per render defeats the memos that list it;App.tsx:218-225failure timeout never cancelled; three deadeslint-disablecomments in a biome repo. Open. - God components:
ProfileForm.tsx(1,317),ModelManagement.tsx(1,102 — embeds a 75-line SSE migration workflow in a JSXonClick, categorizes models by name-prefix string match),HistoryTable.tsx(915),CapturesTab.tsx(909).StoryTrackEditor.tsx(1,531) is coherent but is three components in one file. Open.
Tauri/Rust shell — B−
Two codebases live here. The dictation/paste path is disciplined, documented, RAII-guarded FFI; the server-lifecycle half of main.rs and both audio modules are a tier below.
Strengths
clipboard.rs: full-fidelity multi-format snapshot/restore on both platforms, RAII guards throughout, correct HGLOBAL ownership semantics (:548-563). Conditional restore keyed onNSPasteboard.changeCount/GetClipboardSequenceNumber(main.rs:1411-1421) correctly yields to clipboard managers writing mid-paste.keyboard_layout.rs: Dvorak/AZERTY Cmd+V viaUCKeyTranslate+ input-source-change observer; hot path reads oneAtomicU16.input_monitoring.rs:42-58: declaresIOHIDCheckAccessasc_uintnotboolwith a comment explaining the UB risk — exemplary FFI care.focus_capture.rs: macOS 14 cooperative-activation handled with a cachedrespondsToSelector:probe; refused activation aborts before clobbering the clipboard (:325-331).- Hotkey lifecycle: single dispatcher thread serializes Start/Stop/Restart; shutdown is flag + join (
hotkey_monitor.rs:102-136); focus snapshotted before any window mutation.
Weaknesses
main.rsgod-file (1,828 lines): NSPanel surgery + ~660 lines of sidecar process management + paste pipeline + app builder;start_serveris 560 lines with the dev-mode fallback copy-pasted three times.lib.rs:1declares a vestigial duplicateaudio_capturemodule. Open.- Blocking calls in async commands:
reqwest::blocking::Clientinside asyncstop_server(main.rs:993-1000); blocking health checks andthread::sleepinside asyncstart_server. Open. println!logging with per-packet spam:audio_output.rs:217logs every decoded packet; nolog/tracingfacade anywhere. Open.audio_output.rsbugs: stop-flag set-then-reset race a 10 ms poll can miss (:105-108vs:413-419); "multi-device" playback is actually serial (:111-117);resampleis sample-and-hold while the comment claims linear interpolation (:268). Open.audio_capture/copy-paste divergence:samples_to_wavtriplicated verbatim; all threestop_captures dolet _ = tx.send(())on a tokio mpsc sender — the future is dropped and the signal never sent (works only because dropping the sender closes the channel); Windows stop is a fixed 500 ms sleep that can truncate the tail;linux.rs:113callsenv::set_varfrom a spawned thread (the setenv data race that isunsafein Rust 2024) and never unsets it; Windows/macOS assume Float32 sample format unchecked. Open.- Plausible deadlock: sync
enable_hotkey/disable_hotkeyrun on the main thread and join the dispatcher while holding the state lock (hotkey_monitor.rs:108-111); the dispatcher's effect path does main-thread round-trips (:252-260). Marking the commands async closes it. Open. start_serverTOCTOU on itself:child.is_some()guard and store separated by multiple awaits — two concurrent invocations double-spawn. Open.
CI / repo hygiene — B−
Strengths
- Release pipeline (
release.yml, 404 lines): 3-platform matrix, changelog extraction, Tauri updater JSON, DMG notarization + staple withspctlverification, SHA-pinned third-party action with written rationale, checksummed CUDA/ROCm sidecar archives with torch-compat metadata. - Developer docs:
docs/content/docs/developer/tts-engines.mdx(703 lines) with a mandatory dependency-research phase built from real scar tissue. 4,022 lines of MDX across 14 files. - justfile: fully cross-platform including native PowerShell, GPU auto-detection for CUDA/ROCm torch indexes, venv guards.
- Security claims check out: server binds
127.0.0.1by default, CORS is a real allowlist with a test, Docker binds host port to127.0.0.1. - Tracked-file state clean: 671 files, no venvs/worktrees/data tracked.
Weaknesses
- PR gate was ~15 effective lines: typecheck + web build. No biome, no ruff, no pytest, no cargo check — the entire 27-file backend suite ungated. This is how 100+ unverifiable PRs pile up. (fixed, see follow-up)
.gitignoretail was UTF-16LE — the.claude/settings.local.jsonpattern was garbage bytes git can't parse; the whole file was CRLF. (fixed)- Unpinned git dependencies:
linacodecandZipvoice(backend/requirements.txt:21-22, third-party personal account) andQwen3-TTS(justfile, Dockerfile) have no commit pins — a force-push upstream silently changes what every release ships. The single biggest supply-chain exposure. Open. - Stale contributor docs:
CONTRIBUTING.mdreferences a nonexistent autoupdater doc, Black instead of ruff, Python 3.11+,com.voicebox.app, and the pre-refactor layout.SECURITY.mdsays 0.3.x is the supported version. Open. - Vestigial root
requirements.txt: 9 unpinned lines including unusedtorchvision; nothing references it; it exists to mislead. Open. backend/pyproject.tomlversion stuck at 0.2.3 — missing from.bumpversion.cfg. Open.build-windows.ymluses floatingtauri-action@v0and a hardcoded stale release body. Releasebun installisn't--frozen-lockfilewhile CI is. Two venvs (backend/venv+backend/.venv) on dev machines. Open.
Priorities
CI: biome + ruff + pytest + cargo check on every PR(done 2026-07-26)Pin the three git deps to commit SHAs(done 2026-07-26)Fix the silent voice-prompt fallback in(done 2026-07-26)mlx_backend.pyDelete the dead generated API client (1,748 LOC)(done 2026-07-26)audio_capture/audio_outputrigor pass (dropped futures, stop races,set_var)SQLite WAL + busy_timeout(done 2026-07-26)Refresh(done 2026-07-26)CONTRIBUTING.md/SECURITY.md; delete rootrequirements.txt- Frontend test tooling + first unit tests for the pure pixel-math functions (in progress)
- Burn down the ruff/biome baselines (tracked in
backend/pyproject.tomlandbiome.jsonc)
Follow-up — fixed 2026-07-26
Same-day fixes landed on 0.6-dictation-fixes:
- CI (
.github/workflows/ci.yml): added biome lint to the frontend job, abackend-qualityjob (macOS arm64:just setup-python,ruff check,pytest), arust-qualityjob (cargo checkwith stub sidecars), and concurrency cancellation. - Tests green: fixed
test_profile_duplicate_names.pyimports, addedtests/conftest.py(kills the order-dependence), rewrotetest_cors.pyagainst the realcreate_app()factory (now covershttp://tauri.localhost), fixed the stale 1,000-byte simulation intest_progress.py(tracker's 1 MB reporting threshold). Suite: 134 passed, 2 skipped. - Ruff green: ~900 violations auto-fixed; remaining 151 baselined in
pyproject.tomlwith per-rule counts and per-file carve-outs for deliberate env-before-import patterns. - Biome green:
biome.json→biome.jsoncwith the failing rules baselined atwarn(annotated against issue #421); scanner ignores.worktrees/so local worktrees no longer breakbun run lint. - Real bug fixed:
pyi_rth_numpy_compat.pyreferenced_tbefore binding, so theNameErrorwas swallowed byexcept Exception: passand the torchfrom_numpypatch silently never applied in frozen builds. .gitignore: rewritten as UTF-8/LF; added.worktrees/,.hermes/,mlx-test/.- Git deps pinned to commits:
linacodec@c0ae7c7andZipvoice@381b160(the commits resolved in the working venv) inbackend/requirements.txt;Qwen3-TTS@022e286(upstream HEAD, verified as the installed 0.1.1) in the justfile and Dockerfile. - Dead generated API client deleted (~1,750 LOC):
app/src/lib/api/{core,models,schemas,services,index.ts}, plus its generator (scripts/generate-api.sh, thegenerate:apiscript, thejust generate-apirecipe) and the doc sections describing the codegen workflow. The client is hand-written inclient.ts/types.ts; docs now say so. - Voice-prompt fallback removed (
mlx_backend.py): a cloning failure now fails the generation with the real error instead of silently retrying with the model's default voice; the empty-audio-as-success path and the silent no-ref_audio-parameter fallback raise too. - Load races closed: Kokoro and LuxTTS
load_modelnow double-check under anasyncio.Lock(same pattern as Chatterbox);get_stt_backendgot the lock the TTS/LLM factories already had. - SQLite hardened (
database/session.py): WAL journal mode +synchronous=NORMALvia connect listener, 30 s busy timeout viaconnect_args— mitigates the lock racing the orphan-recovery machinery works around. - Hotkey deadlock closed:
enable_hotkey/disable_hotkey/update_chord_bindingsare now async commands, so joining the dispatcher no longer happens on the main thread the dispatcher may be waiting on. - Docs refreshed:
CONTRIBUTING.md(ruff not Black, Python 3.12,sh.voicebox.app, real backend layout, real testing story, fixed autoupdater link),SECURITY.md(0.5.x supported; describes actual CI enforcement), rootrequirements.txtdeleted (two stale references repointed atbackend/requirements.txt),backend/pyproject.tomlversion synced to 0.5.0 and added to.bumpversion.cfg.