Closes the code-side v0.1 ship gate. All quality gates green: cargo fmt/clippy/test (~327 tests), npm check (0/0), vitest 13/13, scripts/dogfood-rebrand-drill.sh 8/8. Phase F — first-run onboarding promoted to v0.1 - FirstRunPage with skip-to-main + failure recovery + event recording - Six onboarding commands (record/list/has-completed + lumotia_events) - Storage migration v17 (onboarding_events + lumotia_events tables) UI hardening (in-scope items from v0.1-ui-hardening.md) - StatusPill + PostCaptureCard components, 21st preview entry - Sidebar recording-as-sacred-state (opacity + aria-disabled, reduced-motion) - Settings 6-section regroup + Help section + Activation log + Privacy toggle - Error-state copy sweep (DictationPage + SettingsPage, plain-language) - Global :focus-visible rule, textarea outlines restored - Ctrl+K / Ctrl+, / Escape bindings in +layout LLM resilience - rule_based_extract_tasks (regex-free imperative-verb extractor) + extract_tasks_with_fallback wrapper — task extraction never returns zero - tokio::time::timeout(120s) wraps cleanup/tags/tasks commands Release artefacts - LICENSE (canonical AGPL-3.0), CHANGELOG (Keep-a-Changelog format) - v0.1-release-notes, privacy-and-ai-use, install-warnings, tester-onboarding-kit, tester-acceptance-runbook, code-signing-setup, apple-silicon-rb08-runbook, virtual-audio-setup, v0.1-contrast-audit - Workspace versioning + AGPL spdx; npm exact-pin (10 ranges removed) - AppImage SHA-256 sidecar in build.yml - README v0.1 section + Reporting-issues; canonical repo slug Closure pass — items moved from human-required to code-complete - KI-02 Linux idle inhibit: zbus 5 → org.freedesktop.login1.Manager.Inhibit - KI-03 Windows sleep prevention: SetThreadExecutionState(ES_CONTINUOUS|...) - acquire/release_idle_inhibit Tauri commands, wired in DictationPage - Diagnostic-bundle frontend wire-up (Settings → Help button) - WCAG-AA contrast fix via .btn-filled-text utility (no token changes) - 8 destructive-action sites wrapped in plain-language confirm() guards - KNOWN-ISSUES.md + v0.1-known-limitations.md updated (KI-02/03 fixed) Scripts - pre-tag-verify.sh, tag-day.sh, smoke-linux + driver - parse-diagnostic-bundle.sh, parse-activation-log.py Per-item audit trail: docs/release/v0.1-completion-status.md Remaining: W-01…W-08 (signing certs, hardware probes, smoke matrix, tester recruitment) — see docs/release/v0.1-known-limitations.md.
7.6 KiB
Known issues
Tracked limitations and partial implementations in the current codebase. Each entry points at the code that owns the gap so future work can find it.
Power management
KI-01 — macOS App Nap guard pending Apple Silicon runtime verification
Status: macOS code path compiles and the registry tests pass, but runtime behaviour against actual OS idle-throttling has not been confirmed on Apple Silicon hardware. Also tracked internally as RB-08.
Source: src-tauri/src/commands/power.rs:73 (PowerAssertion::begin), src-tauri/src/commands/power.rs:140 (objc_bridge).
Impact: Long live-dictation sessions on macOS may still be slowed or paused by the OS until verified end-to-end on hardware.
Workaround: Keep the app window focused, or move the cursor periodically. For testing, App Nap can be disabled globally with defaults write NSGlobalDomain NSAppSleepDisabled -bool YES (revert with -bool NO).
KI-02 — Linux idle inhibit ✓ fixed in v0.1
Status: Resolved. acquire_idle_inhibit now calls org.freedesktop.login1.Manager.Inhibit
via zbus (blocking, offloaded to spawn_blocking) on recording start, holding the returned file
descriptor. release_idle_inhibit closes the fd on recording stop, which atomically releases the
lock. The inhibit scope is idle:sleep:handle-lid-switch in block mode.
If D-Bus is unavailable (non-systemd containers, exotic distros), the call fails gracefully with a
tracing::warn! and recording continues — the workaround below remains valid in those edge cases.
Source: src-tauri/src/commands/power.rs (acquire_idle_inhibit, release_idle_inhibit, linux_inhibit mod).
Workaround (edge cases only): Wrap launch with systemd-inhibit --what=idle:sleep:handle-lid-switch ./run.sh if logind is not available.
KI-03 — Windows sleep prevention ✓ fixed in v0.1
Status: Resolved. acquire_idle_inhibit now calls
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED) on recording start.
release_idle_inhibit calls SetThreadExecutionState(ES_CONTINUOUS) to restore normal behaviour.
Display sleep is intentionally NOT blocked — the user is dictating, not watching the screen.
Source: src-tauri/src/commands/power.rs (acquire_idle_inhibit, release_idle_inhibit, windows_inhibit mod).
Workaround (edge cases only): If the power plan has a policy override that blocks SetThreadExecutionState, set the active sleep timeout to "Never" while dictating.
Cloud providers
KI-04 — lumotia-cloud-providers crate is not user-exposed
Status: The crate is a declared workspace dependency in src-tauri/Cargo.toml:36 and compiles into the binary, but no Tauri command, page, or settings field invokes store_api_key / retrieve_api_key. There is no UI to enter or store a cloud API key in the current build.
Source: crates/cloud-providers/src/keystore.rs. The TODO in the doc comment captures the planned migration to OS-native credential storage (the keyring crate or equivalent) before the feature is wired up.
Impact: None for end users today (no exposed surface). When the feature is wired post-launch, cross-restart persistence must land before any "save key" UX ships, otherwise saved keys reset on every restart.
Workaround: N/A.
Frontend
KI-05 — Dual theme system: settings.theme and preferences.theme coexist
Status: Theme is stored twice. The legacy settings.theme ("Dark" / "Light" / "System", localStorage-only) is bound to two SegmentedButton controls in SettingsPage.svelte. The canonical preferences.theme ("dark" / "light" / "system", Tauri-persisted via save_preferences) is what the DOM and runtime actually consume. A migration $effect in src/routes/+layout.svelte (and the secondary +layout@.svelte files for /preview, /viewer, /float) syncs settings.theme → preferences.theme whenever the legacy value changes.
Source:
src/lib/stores/page.svelte.ts:61(legacy default:theme: "Dark")src/lib/stores/preferences.svelte.ts:30(canonical default:theme: "dark")src/routes/+layout.svelte:61-68(migration$effect)src/lib/pages/SettingsPage.svelte:1118,:2360(UI bindings still on the legacy field)
Impact: No user-facing bug; theme switching works. The cost is code complexity and a small race window where preference fan-out can lag behind a settings.theme change. The $effect is lightweight (string compare plus a debounced persist when the mapped value differs), not a hot-loop performance problem despite earlier framing.
Resolution (deferred): Switch the two SettingsPage bindings to preferences.theme with mapped options, retire the migration $effect in all four route layouts, drop theme from SettingsState, and add a one-shot localStorage migration that copies any historical settings.theme into preferences on first run after the cleanup. Touches ~5 files including the 2 484-LOC SettingsPage.svelte; deferred from the v0.1 polish pass to avoid a moderate-risk frontend change immediately before launch.
Workaround: N/A.
Engine architecture (Phase A)
KI-06 — transcribe_file and live-transcription commands not yet rewired through Orchestrator
Status: Phase A introduced the TranscriptionProvider async trait (crates/cloud-providers/src/provider.rs), EngineRegistry (crates/transcription/src/registry.rs), and Orchestrator plus LocalProviderAdapter (crates/transcription/src/orchestrator.rs). The abstractions compile, are object-safe, and pass unit tests against a mock provider. The existing dictation path (src-tauri/src/commands/transcription.rs) still calls LocalEngine::transcribe_sync directly via pick_engine, not through the orchestrator. Live and meeting commands likewise route around the orchestrator.
Source: src-tauri/src/commands/transcription.rs:29 (pick_engine), src-tauri/src/commands/live.rs, src-tauri/src/commands/meeting.rs.
Impact: None at runtime. The orchestrator path is dormant until a follow-up commit migrates the call sites. Cloud providers (Phase G) cannot be exercised end-to-end until this rewire lands.
Resolution (deferred): Phase A.1 follow-up commit. Build an EngineRegistry at app boot (one LocalProviderAdapter per LocalEngine), inject Arc<Orchestrator> into AppState, replace pick_engine plus engine.transcribe_sync chunking-loop calls with orchestrator.transcribe(audio, &profile) per chunk. Keep the chunking strategy in the command layer (it is a strategy concern, not a dispatch concern). Tests should cover both paths against a mock provider before touching the real engines.
Workaround: N/A. Existing path works as before.
How to add an entry
When shipping a partial implementation or known limitation, add a KI-NN entry here with the four standard fields: Status, Source (file:line), Impact, Workaround. Link from the affected module's doc comment back to this file by ID.