diff --git a/HANDOVER.md b/HANDOVER.md index b7b396f..ce9718b 100644 --- a/HANDOVER.md +++ b/HANDOVER.md @@ -7,6 +7,8 @@ description: Session handover — 2026/04/24-25 Phase 9 polish debt mostly shipp # Magnotia Handover — 2026/04/25 +> **Note:** Session-specific handover. Migration v14 (`transcripts.llm_tags`) was the head **at the time of this session**. Subsequent work has advanced the schema; current head is v15 (`idx_transcripts_profile_created`, composite index). For the current codebase shape, see [`docs/architecture-map/`](docs/architecture-map/) and [`KNOWN-ISSUES.md`](KNOWN-ISSUES.md). + Phase 9 session. Spec + plan written from scratch and committed; plan corrections layered in after critical review against the actual codebase (Codex was unreachable for cross-model review, three retries failed at the ChatGPT-account-entitlement layer). Sub-phases 9a + 9b + sparkline polish landed end to end. Sub-phase 9c reduced to the Phase 8 carryover bug fix; sub-phase 9d's walkthrough sweeps deferred to Phase 10a QC. ## Rebrand note diff --git a/src-tauri/src/commands/tasks.rs b/src-tauri/src/commands/tasks.rs index 5c2f7a6..5f67201 100644 --- a/src-tauri/src/commands/tasks.rs +++ b/src-tauri/src/commands/tasks.rs @@ -18,6 +18,7 @@ use magnotia_storage::{ FeedbackRow, FeedbackTargetType, TaskRow, }; +use crate::commands::power::PowerAssertion; use crate::AppState; /// Frontend-facing task shape. Matches the in-memory object in page.svelte.js. @@ -319,6 +320,7 @@ pub async fn decompose_and_store( let engine = state.llm_engine.clone(); let parent_text = parent.text.clone(); let steps = tokio::task::spawn_blocking(move || { + let _power_guard = PowerAssertion::begin("magnotia LLM micro-step decomposition"); engine.decompose_task_with_feedback(&parent_text, &examples) }) .await @@ -361,10 +363,13 @@ pub async fn extract_tasks_from_transcript_cmd( .unwrap_or_default(); let engine = state.llm_engine.clone(); - tokio::task::spawn_blocking(move || engine.extract_tasks_with_feedback(&transcript, &examples)) - .await - .map_err(|e| e.to_string())? - .map_err(|e| e.to_string()) + tokio::task::spawn_blocking(move || { + let _power_guard = PowerAssertion::begin("magnotia LLM task extraction"); + engine.extract_tasks_with_feedback(&transcript, &examples) + }) + .await + .map_err(|e| e.to_string())? + .map_err(|e| e.to_string()) } #[tauri::command] diff --git a/src-tauri/src/commands/transcription.rs b/src-tauri/src/commands/transcription.rs index ec7720a..afd0b6a 100644 --- a/src-tauri/src/commands/transcription.rs +++ b/src-tauri/src/commands/transcription.rs @@ -154,6 +154,11 @@ pub async fn transcribe_pcm( profile_id: Option, ) -> Result<(), String> { ensure_main_window(&window)?; + if !state.whisper_engine.is_loaded() { + return Err( + "Whisper model not loaded. Download a Whisper model in Settings.".to_string(), + ); + } let resolved_profile_id = profile_id.unwrap_or_else(|| magnotia_storage::DEFAULT_PROFILE_ID.to_string()); @@ -352,6 +357,11 @@ pub async fn transcribe_pcm_parakeet( profile_id: Option, ) -> Result<(), String> { ensure_main_window(&window)?; + if !state.parakeet_engine.is_loaded() { + return Err( + "Parakeet model not loaded. Enable Parakeet in Settings.".to_string(), + ); + } let resolved_profile_id = profile_id.unwrap_or_else(|| magnotia_storage::DEFAULT_PROFILE_ID.to_string());