# Phase 1 — Lean-pass (scan-only deliverable) *Read-only deliverable; no code changes applied. Removals and refactors deferred to a review pass.* Date: 2026-05-01. Branch: `main` @ `7ff7295` (working tree clean at scan start; a parallel agent is committing the Phase 0 §9 Tier A/B/D1 README and `Cargo.toml` documentation fixes alongside this scan). Status: scan-only. --- ## Methodology This is the find-first half of audit discipline. Every section below is a scan output, lightly categorised. No code was modified to produce this report; remediation gets a separate commit and review pass after Jake walks the findings. The Phase 1 playbook (`docs/audit/phases-1-8-playbook.md` §Phase 1) calls for `cargo machete`, `cargo udeps`, `knip`, `depcheck`, dead-code lints per crate, a tech-debt grep, an `unwrap`/`expect` panic-surface scan, manual notes on the five files >1k LOC, and `jscpd` cross-file duplication. All steps were attempted; toolchain gaps are logged in §"Scans deferred". Severity grades (per playbook): **P0** must-fix before any release; **P1** must-fix before sale or public beta; **P2** worth fixing, not blocking. --- ## 1. Unused Rust dependencies `cargo machete` (v0.9.2, freshly installed, recursive workspace mode) flags **4 unused-dependency hits across 4 crates**. | ID | Severity | Crate | `Cargo.toml` declares | Notes | |---|---|---|---|---| | L1.1 | P2 | `magnotia-cloud-providers` | `magnotia-core` | Crate is 80 LOC of in-memory keystore; no `magnotia_core::` imports in source. Likely dead since cartography §3 ("not earning its existence"). Cross-references Phase 0 Tier C4. | | L1.2 | P2 | `magnotia-core` | `async-trait` | Not used inside `core`'s own modules. Worth confirming with reverse-grep before removal — `async_trait` is sometimes pulled in by macro expansion only. | | L1.3 | P2 | `magnotia-core` | `serde_json` | Same caveat — many crates pull `serde_json` for downstream re-export, but `core` should not need it directly. | | L1.4 | P2 | `magnotia-hotkey` | `magnotia-core` | Hotkey crate compiles standalone; only depends on `core` for shared error types presumably, but the import is not present. | | L1.5 | P2 | `magnotia` (`src-tauri`) | `magnotia-cloud-providers` | The Tauri crate declares the cloud-providers crate, but no `magnotia_cloud_providers::` symbol appears in `src-tauri/src`. Folds into Phase 0 Tier C4 (kill or grow `cloud-providers`). | **Cross-check with `cargo udeps`:** *not run.* The repo currently has only a stable Rust toolchain installed (`rustup toolchain list` returned `stable-x86_64-unknown-linux-gnu` only). `cargo udeps` requires nightly. Logged under Scans deferred. **Recommended Phase-1 follow-up:** before deleting any of these, do a workspace-wide reverse grep for each dep name; macros and re-exports defeat machete. The L1.4 and L1.5 hits in particular suggest `magnotia-cloud-providers` as a unit is removable (cartography Tier C4 option a — fold into `magnotia-core::keystore`). --- ## 2. Unused frontend modules ### 2.1 `npx knip` **Files reported as unused (9):** | ID | Severity | File | Notes | |---|---|---|---| | L2.1 | P2 | `src/app.d.ts` | SvelteKit ambient declaration. Knip almost always false-positives on these; **keep**. | | L2.2 | P2 | `src/design-system/colors_and_type.css` | Reference design-system, not live code (cartography §2 already excludes the design-system from active LOC). Verify before deletion. | | L2.3 | P2 | `src/design-system/ui_kits/DictationPage.jsx` | Reference UI kit (JSX in a Svelte project — clearly a sketch, not a build target). | | L2.4 | P2 | `src/design-system/ui_kits/OtherPages.jsx` | As above. | | L2.5 | P2 | `src/design-system/ui_kits/Sidebar.jsx` | As above. | | L2.6 | P2 | `src/lib/components/VirtualSegmentList.svelte` | Possible orphan after a refactor. Worth a `grep -r VirtualSegmentList src/` to confirm before removal. | | L2.7 | P2 | `src/lib/components/VisualTimer.svelte` | Same — verify no dynamic import or string-named lookup. | | L2.8 | P2 | `src/lib/shims.d.ts` | TypeScript shim. Knip false-positive class; **keep**. | | L2.9 | P2 | `static/pcm-processor.js` | AudioWorklet module — loaded by URL string at runtime, not by import. **Keep** (false positive). | **Unused dependencies (3):** | ID | Severity | Package | Notes | |---|---|---|---| | L2.10 | P2 | `@tauri-apps/plugin-autostart` | Likely registered Rust-side in `src-tauri/Cargo.toml` and configured via `tauri.conf.json` rather than imported from JS. Verify — if the Rust side uses it, the JS dep can go. | | L2.11 | P2 | `@tauri-apps/plugin-global-shortcut` | Same — Rust-side registration. | | L2.12 | P2 | `@tauri-apps/plugin-opener` | Same. | **Unlisted binaries (1):** | ID | Severity | Reference | Notes | |---|---|---|---| | L2.13 | P2 | `du` in `.github/workflows/build.yml` | Just a system tool used in CI. Informational; nothing to do. | **Unused exports (31) and exported types (28):** see `/tmp/claude-1000/.../bq57g56il.output` for the full list. The high-density file is `src/lib/utils/textMeasure.ts` (5 exports, none consumed) and `src/lib/utils/settingsMigrations.ts` (3 exports + 2 types). Treat each as a candidate for either consumption or deletion. **Severity P2 across the board** — the exports are dead but harmless; their LOC saving is real but the risk of collateral damage is nonzero (they could be imported by name from another package or via dynamic lookup). Manual review per-file in Phase 2. ### 2.2 `npx depcheck` Run with `--skip-missing` to avoid false positives on dev tooling. | ID | Severity | Package | Notes | |---|---|---|---| | L2.14 | P2 | `@tauri-apps/plugin-autostart` | Confirms L2.10. | | L2.15 | P2 | `@tauri-apps/plugin-global-shortcut` | Confirms L2.11. | | L2.16 | P2 | `@tauri-apps/plugin-opener` | Confirms L2.12. | | L2.17 | P2 | `lucide-svelte` | **Worth investigating.** Declared but depcheck found no JS-side import. If icons are inlined as SVG, the dep is genuinely dead. If imported via a wrapper component, false positive. | | L2.18 | P2 | `tailwindcss` (devDep) | Almost certainly a false positive — Tailwind is wired in via `@tailwindcss/vite` plugin in `vite.config.js` rather than a direct import. **Keep.** | **Convergent signal:** L2.10/11/12 plus L2.14/15/16 — both tools agree the three Tauri plugins are JS-unused. They are still required Rust-side (the Tauri JS bridge ships separately from the Rust plugins), so the safe pattern is to keep them only if the JS API is invoked from the frontend. Quick `grep -r 'autostart\|globalShortcut\|opener' src/` answers it; that is a Phase 2 pass, not a Phase 1 deletion. --- ## 3. Dead Rust code Each crate was rebuilt (workspace + `--all-targets`) with `RUSTFLAGS="-W dead_code -W unused"` to surface the strictest defaults. **Result:** **zero warnings emitted across all nine library crates and `src-tauri`.** This is genuine — both `cargo build --workspace` and `cargo build --workspace --all-targets` came back clean with the elevated flags. The codebase does not carry obvious unreachable Rust code, unused imports, or unused private items as scored by rustc's default dead-code detector. Stronger lints (`clippy::pedantic`, `clippy::nursery`) are deferred to Phase 3 per the playbook. **Caveat:** rustc's `dead_code` only fires when a `pub` item has no callers *anywhere in the same crate*; cross-crate dead `pub` items (where the only callers are inside a sibling crate that has since stopped using them) require the workspace-wide reverse-grep pass scheduled for Phase 2 step 5 (the `magnotia-core` 104-public-items audit). The L1.* dependency hits above are early evidence that some inter-crate links are already dormant. --- ## 4. Tech-debt grep `grep -rnE "TODO|FIXME|HACK|XXX|unimplemented!\(\)|todo!\(\)" --include="*.rs" --include="*.svelte" --include="*.ts"` returned **5 hits** total — a remarkably low count for a 36k-LOC codebase. | ID | Severity | File:line | Marker | Bucket | Suggested action | |---|---|---|---|---|---| | L4.1 | P2 | `crates/cloud-providers/src/keystore.rs:13` | TODO | (a) genuine reminder | Replace process-local `Mutex` keystore with `keyring` crate or platform-native credential storage so secrets persist across sessions. Cross-references Phase 0 Tier C4 (and the Plinth `MEMORY.md` note about plaintext Foundry secrets — same family of issue). Log to issue tracker. | | L4.2 | P2 | `crates/storage/src/database.rs:166` | (TODO) | (b) historical comment | Already-resolved TODO referenced in a doc comment ("the rename was a UI-only state change with a TODO never wired up"). Reads as historical narrative; not actionable but cluttery. Optional: shorten the comment in a docs pass. | | L4.3 | P1 | `crates/storage/src/database.rs:1124` | TODO | (c) silent admission | `log_error` is implemented but the doc comment states it is *not yet wired into Tauri command error paths*. Result: every command's error is converted to a `String` and returned to the JS layer, but the persistent `error_log` table is never written to from production paths. **This is real audit signal**: the README and crate surface advertise an error-log capability that is dormant. Wire it into the command-layer `?` translations in Phase 3. | | L4.4 | P2 | `src/lib/components/MorningTriageModal.svelte:262` | TODO | (a) genuine reminder | Promote inline `#1a1816` 50%-alpha overlay colour to a `--color-overlay` token in `app.css`. Cosmetic; safe to action in Phase 8 (docs/style truth) or whenever a token-pass happens. | | L4.5 | P2 | `src-tauri/src/commands/transcripts.rs:6` | TODO (in narrative comment) | (b) historical | Comment narrates that a previous TODO ("persist to SQLite when update_transcript exists") has been resolved. Like L4.2: historical, not actionable. Optional cleanup. | **Bucket totals:** 1 × bucket (a), 2 × bucket (b), 1 × bucket (c, escalated to P1). Zero `FIXME`, zero `HACK`, zero `XXX`, zero `unimplemented!()`, zero `todo!()` in the entire active codebase. That last point is itself a strong-positive finding — see §Defect log summary. --- ## 5. Panic surface (`unwrap` / `expect` outside tests) The raw grep returned **385 hits**, but a context-aware Python pass (which tracks `#[test]`, `#[tokio::test]`, and `#[cfg(test)] mod`) finds that **359 of those are inside test bodies or `#[cfg(test)]` modules** and **only 26 sit on production paths**. Production list below. | File:line | Context (1 line) | Risk note | |---|---|---| | `crates/mcp/src/lib.rs:230` | `serde_json::to_string_pretty(&summaries).unwrap()` | Serialising a `Vec` we just built; cannot fail in practice but the `.unwrap()` will panic the MCP stdio worker on any bug in the type. Trade for `?`. | | `crates/mcp/src/lib.rs:262` | `text_content(serde_json::to_string_pretty(&value).unwrap())` | Same family — JSON-stringifying a value of our own construction. | | `crates/mcp/src/lib.rs:294` | `serde_json::to_string_pretty(&summaries).unwrap()` | Same. | | `crates/mcp/src/lib.rs:319` | `serde_json::to_string_pretty(&summaries).unwrap()` | Same. | | `crates/llm/src/lib.rs:102` | `let mut guard = self.inner.lock().unwrap()` | Standard `Mutex::lock().unwrap()` — only panics on poison. Acceptable in practice but a poisoned LLM mutex would panic the whole engine; an explicit `expect("LLM engine mutex poisoned")` would at least name the failure. | | `crates/llm/src/lib.rs:137` | `let mut guard = self.inner.lock().unwrap()` | Same. | | `crates/llm/src/lib.rs:145` | `self.inner.lock().unwrap().model.is_some()` | Same. | | `crates/llm/src/lib.rs:149` | `self.inner.lock().unwrap().loaded.clone()` | Same. | | `crates/llm/src/lib.rs:169` | `NonZeroU32::new(n_ctx).expect("n_ctx must be non-zero")` | Construction-time invariant; preceded by a guard that should rule out zero. Fine, but the invariant is not encoded — if a caller bypasses the guard, this panics on engine init. Reasonable to keep with the `expect`. | | `crates/llm/src/lib.rs:380` | `let guard = self.inner.lock().unwrap()` | Mutex poison. | | `crates/transcription/src/streaming/commit_policy.rs:125` | `self.history.back().expect("history is non-empty here")` | The expect string asserts a precondition that is enforced four lines above by `if self.history.is_empty() { return … }`. **Defensible** — the panic message even names the invariant. Document in a Phase-3 inline justification rather than refactor. | | `crates/cloud-providers/src/keystore.rs:18` | `api_key_store().lock().unwrap()` | Mutex poison; same family as the `llm` ones. | | `crates/cloud-providers/src/keystore.rs:31` | `api_key_store().lock().unwrap()` | Same. | | `src-tauri/src/lib.rs:442` | `.expect("error while running Magnotia")` | The Tauri `run()` call. A panic here is the conventional pattern (no recovery anyway — process exit). Keep. | | `src-tauri/src/commands/power.rs:61` | `.unwrap()` | Power-assertion mutex lock. Mutex poison. | | `src-tauri/src/commands/power.rs:103` | `assertion_registry().lock().unwrap().insert(…)` | Mutex poison. | | `src-tauri/src/commands/power.rs:134` | `assertion_registry().lock().unwrap().remove(&self.id)` | Mutex poison. | | `src-tauri/src/commands/audio.rs:159` | `all_samples.lock().unwrap().clear()` | Mutex poison. | | `src-tauri/src/commands/audio.rs:165` | `*state.wav_writer.lock().unwrap() = Some(writer)` | Mutex poison. | | `src-tauri/src/commands/audio.rs:166` | `*state.temp_audio_path.lock().unwrap() = Some(temp_path)` | Mutex poison. | | `src-tauri/src/commands/audio.rs:316` | `let mut all = state.all_samples.lock().unwrap()` | Mutex poison. | | `src-tauri/src/commands/live.rs:330` | `self.state.resampler.as_mut().expect("resampler just set")` | Local invariant immediately after a `set` — defensible. | | `src-tauri/src/commands/live.rs:497` | `let running = live_state.running.lock().unwrap()` | Mutex poison. | | `src-tauri/src/commands/live.rs:581` | `*live_state.running.lock().unwrap() = Some(RunningLiveSession {…})` | Mutex poison. | | `src-tauri/src/commands/live.rs:600` | `let running = live_state.running.lock().unwrap().take()` | Mutex poison. | | `src-tauri/src/commands/live.rs:606` | `*live_state.running.lock().unwrap() = Some(running)` | Mutex poison. | **Pattern summary.** The 26 production unwraps cluster into three categories: - **Mutex poison** (19 occurrences): `Mutex::lock().unwrap()`. The well-known Rust idiom; only fails if a thread panicked while holding the lock. Acceptable but **inconsistent**: every site should at minimum carry an `expect("&str describing what")` so a poison-panic crash log names the lock. Phase 3 task: standardise. - **Self-built JSON serialisation** (4 occurrences in `magnotia-mcp`): `serde_json::to_string_pretty(&value).unwrap()`. Cannot fail for our own types in practice, but the playbook's "prove it can't panic on user data" rule says these should become `?` or carry explicit `expect`s. Phase 3 task. - **Locally-enforced invariants** (3 occurrences in `commit_policy`, `live`, `lib.rs`): the line above the `unwrap`/`expect` enforces the precondition. These are the most defensible; Phase 3 should add an inline `// SAFETY: …` comment naming the invariant rather than rewrite. **Severity:** all P2 in isolation. Collectively → P1 to standardise before sale; an acquirer reading this list will want the convention named. --- ## 6. Largest-file duplicate-logic notes ### 6.1 `src/lib/pages/SettingsPage.svelte` — 2,250 LOC Confirmed seven `` top-level groups (lines 972, 1020, 1379, 1569, 1808, 1947, 2119) corresponding to the planned seven-group split documented in HANDOVER.md §"9c — Settings (scaled down)". The structural decomposition is **already in source** — what remains is the file split: each top-level `` should move to its own `*.svelte` file under `src/lib/pages/settings/`. The page-level component then becomes a slim shell ~200 LOC. **Inline observations:** - 49 `