Discovered while spinning up a Tauri dev session on v0.3 for live UI review. The app aborts on startup the moment DictationPage mounts and calls load_llm_model — llama.cpp's GGML_ASSERT on the Fused Gated Delta Net tensor-name prefix fires before the WebView paints, taking the parent process with it. All four configured model variants (Qwen3.5 2B/4B/9B + Qwen3.6 27B) share the architecture, so picking a different size does not work around it. Adds a new LLM section with KI-07 (Status / Source / Impact / Workarounds). Four ordered workarounds, cheapest first: 1. Park the .gguf file — autoload bails, non-LLM features work 2. Set aiTier = "off" in lumotia_preferences before launch 3. Bump llama-cpp-2 to a release with the upstream FGDN fix 4. Add a non-FGDN model variant to LlmModelId (1) unblocked tonight's live review of the Phase 5f polish. (3) is the real resolution.
125 lines
11 KiB
Markdown
125 lines
11 KiB
Markdown
# 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`](src-tauri/src/commands/power.rs#L73) (`PowerAssertion::begin`), [`src-tauri/src/commands/power.rs:140`](src-tauri/src/commands/power.rs#L140) (`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`](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`](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`](src-tauri/Cargo.toml#L36) 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`](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`](src/lib/stores/page.svelte.ts#L61) (legacy default: `theme: "Dark"`)
|
|
- [`src/lib/stores/preferences.svelte.ts:30`](src/lib/stores/preferences.svelte.ts#L30) (canonical default: `theme: "dark"`)
|
|
- [`src/routes/+layout.svelte:61-68`](src/routes/+layout.svelte#L61) (migration `$effect`)
|
|
- [`src/lib/pages/SettingsPage.svelte:1118`](src/lib/pages/SettingsPage.svelte#L1118), [`:2360`](src/lib/pages/SettingsPage.svelte#L2360) (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`](crates/cloud-providers/src/provider.rs)), `EngineRegistry` ([`crates/transcription/src/registry.rs`](crates/transcription/src/registry.rs)), and `Orchestrator` plus `LocalProviderAdapter` ([`crates/transcription/src/orchestrator.rs`](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`](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`](src-tauri/src/commands/transcription.rs#L29) (`pick_engine`), [`src-tauri/src/commands/live.rs`](src-tauri/src/commands/live.rs), [`src-tauri/src/commands/meeting.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.
|
|
|
|
## LLM
|
|
|
|
### KI-07 — `llama-cpp-2 v0.1.146` panics on Qwen3.5+ Fused Gated Delta Net (FGDN) tensors
|
|
|
|
**Status:** Loading any of the four configured model variants (`Qwen3_5_2B_Q4`, `Qwen3_5_4B_Q4`, `Qwen3_5_9B_Q4`, `Qwen3_6_27B_Q4`) at startup aborts the whole process with a GGML assert inside the bundled `llama.cpp`:
|
|
|
|
```
|
|
llama-cpp-sys-2-0.1.146/llama.cpp/src/llama-context.cpp:487:
|
|
GGML_ASSERT(strncmp(n->name, LLAMA_TENSOR_NAME_FGDN_AR "-", prefix_len) == 0) failed
|
|
```
|
|
|
|
The assert fires during `llama_context` construction while resolving Fused Gated Delta Net support, which is the recurrent / Mamba-style attention mechanism Qwen3.5+ uses. `llama-cpp-2 v0.1.146` bundles a `llama.cpp` snapshot whose FGDN tensor-name prefix check rejects tensors as named in current Qwen3.5 GGUFs. Because the assert is in C++ via `ggml`, the panic kills the parent Tauri process — Tauri's crash handler then attaches GDB, which is what surfaces in the dev log as a stack trace ending in `tao::event_loop` rather than as a Rust panic.
|
|
|
|
All four enum variants share the same architecture family, so picking a different size does not work around it.
|
|
|
|
**Source:**
|
|
- Dep pin: [`crates/llm/Cargo.toml:24`](crates/llm/Cargo.toml#L24) (`llama-cpp-2 = "0.1.146"`)
|
|
- Model enum: [`crates/llm/src/model_manager.rs:15`](crates/llm/src/model_manager.rs#L15) (the four Qwen3.5+ variants)
|
|
- Frontend autoload trigger: [`src/lib/pages/DictationPage.svelte:274`](src/lib/pages/DictationPage.svelte#L274) (`ensureLlmModelLoaded` → `invoke("load_llm_model", …)`)
|
|
- Backend command: [`src-tauri/src/commands/llm.rs:94`](src-tauri/src/commands/llm.rs#L94) (`load_llm_model`)
|
|
- Upstream assert: `llama-cpp-sys-2-0.1.146/llama.cpp/src/llama-context.cpp:487`
|
|
|
|
**Impact:** App will not start in dev (and presumably release) on any machine that has a Qwen3.5+ `.gguf` present and `settings.aiTier !== "off"`. There is no UI to recover — the crash precedes the WebView paint, so the user cannot reach Settings to disable AI features or swap the model. Affects every code path that exercises the LLM (transcript cleanup, task extraction, micro-step decomposition).
|
|
|
|
**Workarounds (in order of cost):**
|
|
1. **Park the model file** so `check_llm_model` returns `downloaded: false` and autoload silently bails:
|
|
```
|
|
mv ~/.local/share/lumotia/models/llm/Qwen3.5-4B-Q4_K_M.gguf{,.crash-parked}
|
|
```
|
|
Non-LLM features (dictation, transcript history, file imports) work normally. Reverse with `mv …{.crash-parked,}`.
|
|
2. **Set `aiTier = "off"`** in `lumotia_preferences` before launch (also bypasses the autoload guard).
|
|
3. **Bump `llama-cpp-2`** to a release that includes the upstream `llama.cpp` FGDN fix. Track upstream PRs at <https://github.com/utilityai/llama-cpp-rs/releases>; verify the bundled `llama.cpp` SHA covers Gated Delta Net tensor-name handling before adopting.
|
|
4. **Add a non-FGDN model variant** to `LlmModelId` (e.g. Llama 3.2 3B Q4 — well-supported in 0.1.146 — or Qwen2.5 3B) and ship a Settings UI to switch to it. Larger change because the enum, the on-disk URL/size constants, and the Settings model picker all need entries.
|
|
|
|
**Resolution (deferred):** Option 3 is the real fix and matches the spirit of `crates/llm` (Qwen3.5+ explicitly listed in the crate description). Option 4 is the right fallback if upstream is slow — having one non-FGDN model on the enum prevents the dev-blocker class of crash entirely.
|
|
|
|
## 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.
|