Closes the 6 Codex review findings on the Day 1 mic-capture work
(commits 96980c7 + 41db162). Detail in
output/reports/kon-codex-mic-capture-followup-2026-04-17.md (CORBEL
workspace).
src-tauri/src/commands/audio.rs:
- D1: Sending an explicit stop signal before dropping stop_tx, so the
accumulator task wakes up immediately rather than waiting for the
Disconnected detection added below.
- D2: Wrapping MicrophoneCapture::start() in tokio::task::spawn_blocking.
start() can spend up to 350ms × N_devices × 2 passes; running it on
the async runtime froze other Tauri commands.
- M3: Match on rx.try_recv() error variants. Empty -> sleep + continue.
Disconnected -> exit accumulator task immediately. Previous behaviour
was an infinite loop after the capture stream died.
crates/audio/src/capture.rs:
- D3: Added DEAD_SILENCE_FLOOR (1e-7) gate that applies even in the
fallback pass. PulseAudio/PipeWire can stream zero-valued bytes from
a borked device; that is worse than failing fast.
- M1: Validation requeue (`for chunk in collected { try_send }`) now
counts drops in the same dropped_chunks counter.
- M2: New CaptureRuntimeError type. The cpal stream error callback now
forwards errors via a separate sync_channel (capacity 16) that the
live session can drain via take_error_rx() and surface as toasts.
Re-exported from kon_audio crate root.
cargo check -p kon-audio passes clean.
NOT YET DONE (M4): JACK-specific monitor name patterns. Defers until
testing on a JACK host. Current is_monitor_name() may miss JACK
conventions.
Wiring the new error_rx into the live session and surfacing as toasts
lands with the Day 3 error-toast system commit.
Day 1 of the upgrade plan (output/reports/kon-upgrade-plan-2026-04-17.md
in the CORBEL workspace). Fixes the HANDOVER.md blocker: native live
transcription was capturing silence because PulseAudio/PipeWire monitor
sources (speaker loopback) were winning the device-selection race —
they deliver zero-valued bytes that satisfied the original
"any device that produces data within 350ms" check.
WHAT CHANGED:
crates/audio/src/capture.rs (rewrite):
- New `DeviceInfo` struct (serde-derived) for the Settings device picker
- New `MicrophoneCapture::list_devices()` enumerates inputs with metadata
- New `MicrophoneCapture::start_with_device(name)` for explicit selection
- Refactored `start()` with monitor-source filtering by name pattern
(.monitor suffix, "Monitor of " prefix, "loopback" substring) and
RMS-energy validation in a 350ms window
- Two-pass selection: real inputs first, monitor sources only as
last-resort fallback with explicit warning log
- Drop counter (Arc<AtomicU64>) tracks chunks dropped by `try_send`
failure under load — Codex review caught this as a silent-failure risk
- `dropped_chunks()` accessor for the live session
- Verbose tracing at every step for diagnosis
- Unit test for monitor-name detection
- `cargo check -p kon-audio` passes clean
crates/audio/src/lib.rs:
- Re-export `DeviceInfo`
crates/audio/Cargo.toml:
- Add serde dependency (for DeviceInfo derives)
src-tauri/src/commands/audio.rs:
- New `list_audio_devices` Tauri command (returns Vec<DeviceInfo>)
src-tauri/src/lib.rs:
- Register `list_audio_devices` in invoke_handler
src/lib/pages/SettingsPage.svelte:
- New "Audio" section with microphone picker dropdown
- Auto-populates on mount via `list_audio_devices`
- Refresh button + clear messaging about monitor sources
- Likely-monitor entries marked disabled in the dropdown
- Auto mode is the default (empty string in settings.microphoneDevice)
src/lib/stores/page.svelte.js:
- New `microphoneDevice` field in defaults (empty = auto-select)
NEXT STEPS (per the upgrade plan):
- Wire `microphoneDevice` from settings into `MicrophoneCapture::start_with_device`
in the live and standalone capture paths (currently both still call
the auto-selecting `start()`)
- Test on real hardware (Wayland + multiple input devices)
- Codex sanity-check of this diff is running in parallel; addendum to
follow if anything substantive comes back
Refs: /home/jake/Documents/CORBEL-Projects/kon/HANDOVER.md
output/reports/kon-upgrade-plan-2026-04-17.md (CORBEL workspace)
The CTC model (onnx-community/parakeet-ctc-0.6b-ONNX) only has an encoder
— no decoder_joint or nemo128 preprocessor. transcribe-rs expects a TDT
transducer variant with all three. Switch to istupakov/parakeet-tdt-0.6b-v2-onnx
which has the correct int8 files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Upstream transcribe-rs 0.3.10 added required fields to TranscribeOptions.
Set both to None (use engine defaults).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add kon-hotkey crate with evdev-based global hotkey capture that works on
Wayland (and X11). Patterns from whisper-overlay: per-device async listeners,
inotify hotplug with udev permission retry, watch channel for live config
updates. Frontend detects Wayland at startup and selects evdev or
tauri-plugin-global-shortcut automatically.
Model downloads now support HTTP Range resume for interrupted downloads and
optional SHA256 integrity verification (incremental, no second pass).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove unused chrono and uuid dependencies from kon-storage
- Add schema versioning TODO to run_migrations() for pre-release safety
- Add doc comment and usage example to log_error() (uncalled public API)
- Add TODO to consolidate app_data_dir() with model_manager::dirs_path()
- Add safety comments and #[allow(deprecated)] to keystore set_var usage
- Add TODO for keyring crate migration in cloud-providers keystore
- Apply cargo fmt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Normalise BRITISH_REPLACEMENTS: remove baked-in \b from entries so all
entries are plain base words; the function adds boundaries uniformly
- Replace O(n*m) while-loop double-space removal with single-pass collapse
- Add debug_assert! documenting ASCII assumption for byte-indexed suffix slicing
- Expand llm_client.rs module-level doc comment
- Run cargo fmt on ai-formatting crate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Share single System::new_all() in probe_system() instead of calling it twice
- Rename CpuInfo::core_count to logical_processors (sys.cpus().len() returns logical, not physical)
- Add fallback arm to probe_os() for unsupported cfg targets
- Add serde::Serialize to KonError for structured frontend error reporting
- Annotate dead code (ProviderRegistry, TranscriptMetadata) with #[allow(dead_code)] + TODO comments
- Update downstream references in recommendation tests and tauri hardware command
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Security fixes from code audit:
- CSP re-enabled in tauri.conf.json with strict directives
(was null — critical vulnerability)
- XSS fix in viewer highlightText(): HTML entities escaped before
inserting <mark> tags via {@html}
- Removed 3 unwrap() calls in rule_based.rs British English conversion
— replaced with safe let-else guards
- Removed unwrap() on main window lookup in lib.rs setup — now uses
if-let for graceful handling
- Wrapped JSON.parse in DictationPage transcription-result listener
with try/catch
Rebrand cleanup:
- Renamed all localStorage keys from ramble_* to kon_* across
7 files (stores, viewer, float, history)
12 tests passing, clippy clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- VAD stubbed: voice_activity_detector and silero-vad-rust both pin ort rc.10
which conflicts with transcribe-rs requiring ort rc.12. Stubbed until ort
ecosystem aligns at 2.0.0 stable. All audio treated as speech (matches v0.2).
- Refreshed Cargo.lock to resolve ort rc.12 + whisper-rs 0.16 correctly
- clippy clean
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- LocalEngine wraps transcribe-rs SpeechModel behind Kon's own abstraction
- load_parakeet() and load_whisper() factory functions
- Unified model manager: download with progress callback, check, list, path resolution
- Atomic downloads: .part suffix with rename on completion
- run_inference() encapsulates spawn_blocking threading
- Zero Tauri dependency in this crate (progress via callback, not events)
- transcribe-rs v0.3.2 with onnx + whisper-cpp features
- 4 tests passing, clippy clean
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>