diff --git a/docs/audit/phase0-cartography.md b/docs/audit/phase0-cartography.md new file mode 100644 index 0000000..a873efe --- /dev/null +++ b/docs/audit/phase0-cartography.md @@ -0,0 +1,235 @@ +# Phase 0 — Cartography + +*Acquisition-grade audit, Phase 0 deliverable. Date: 2026-04-30. Branch: `claude/rebrand-to-magnotia-UWYkg`.* + +This is a survey, not a verdict. It maps what exists, sizes the surface, and flags every place the README disagrees with the code. Phase 1 (lean-pass) and Phase 2 (architecture conformance) consume this as input. + +--- + +## 1. Workspace shape + +| Layer | Path | Notes | +|---|---|---| +| Rust workspace root | `Cargo.toml` | `members = ["src-tauri", "crates/*"]`, `resolver = "2"` | +| Tauri app crate | `src-tauri/` | Library `magnotia_lib` + binary `magnotia` | +| Library crates | `crates/*` (×9) | See §3 | +| MCP standalone binary | `crates/mcp/` | Bin `magnotia-mcp` (separate process from main app) | +| Svelte frontend | `src/` | SvelteKit, Svelte 5 runes, Tailwind 4 | +| Static assets | `static/`, `src-tauri/icons/`, `src-tauri/resources/` | | + +**Binaries shipped (2):** `magnotia` (Tauri app), `magnotia-mcp` (stdio MCP server). + +--- + +## 2. Lines of code + +| Area | LOC | Files | +|---|---:|---:| +| `crates/` (Rust, all 9 crates) | 13,261 | 52 | +| `src-tauri/` (Rust) | 8,330 | 27 | +| Frontend (Svelte/TS/JS, excl. design-system) | 15,192 | ~80 | +| `src/design-system/` (reference kit, not live code) | 1,412 | — | +| **Total active** | **~36,800** | | + +### Largest files (top complexity candidates) + +| LOC | File | +|---:|---| +| 2,534 | `crates/storage/src/database.rs` | +| 2,250 | `src/lib/pages/SettingsPage.svelte` | +| 1,737 | `src-tauri/src/commands/live.rs` | +| 1,185 | `crates/storage/src/migrations.rs` | +| 1,081 | `src/lib/pages/DictationPage.svelte` | +| 897 | `src/lib/pages/HistoryPage.svelte` | +| 790 | `src-tauri/src/commands/paste.rs` | +| 735 | `crates/transcription/src/streaming/rms_vad.rs` | +| 725 | `src/lib/pages/TasksPage.svelte` | +| 720 | `src-tauri/src/commands/models.rs` | +| 697 | `src/lib/stores/page.svelte.ts` | + +> **Phase 1 candidate.** `database.rs` (2.5k), `SettingsPage.svelte` (2.25k), and `live.rs` (1.7k) are each large enough to deserve a structural review in isolation. HANDOVER.md already flags `SettingsPage` as needing decomposition into 7 progressive-disclosure groups. + +--- + +## 3. Crate inventory + +| Crate | LOC | Files | `pub` items (lib.rs / total) | Tests | +|---|---:|---:|---:|---:| +| `magnotia-core` | 1,212 | 9 | 10 / 104 | 16 | +| `magnotia-audio` | 1,533 | 8 | 14 / 38 | 14 | +| `magnotia-transcription` | 2,617 | 12 | 13 / 51 | 51 | +| `magnotia-llm` | 1,330 | 6 | 27 / 56 | 17 | +| `magnotia-ai-formatting` | 1,502 | 6 | 9 / 21 | 47 | +| `magnotia-storage` | 3,771 | 4 | 6 / 69 | 60 | +| `magnotia-hotkey` | 632 | 3 | 5 / 14 | 4 | +| `magnotia-cloud-providers` | 80 | 2 | 2 / 3 | 2 | +| `magnotia-mcp` | 584 | 2 | 8 / 8 | 9 | +| `src-tauri` (`magnotia` + `magnotia_lib`) | 8,330 | 27 | n/a | 67 | +| **Total** | **21,591** | | | **287** | + +**Outliers worth a Phase-2 look:** +- `magnotia-core` exposes 104 public items — high for a "shared types" crate; likely leakage of internals. +- `magnotia-storage` exposes 69 public items across only 4 files; the file split is suspect (2.5k-line `database.rs`). +- `magnotia-cloud-providers` is 80 LOC and 3 public items — README calls it "empty scaffolding" (verified: just an in-memory keystore + env-var fallback). Either grow it or remove it; it currently earns nothing. + +--- + +## 4. Crate dependency graph + +``` +magnotia-core ──┬─→ magnotia-audio + ├─→ magnotia-transcription + ├─→ magnotia-llm ──→ magnotia-ai-formatting + ├─→ magnotia-cloud-providers + ├─→ magnotia-hotkey + └─→ magnotia-storage ──→ magnotia-mcp + +magnotia (src-tauri) + └─→ all 8 library crates (NOT magnotia-mcp — separate binary) +``` + +**Observations:** +- `magnotia-core` is the workspace floor; nothing depends on it depending on something else. Good. +- DAG is clean — no cycles, no upward dependencies. +- `magnotia-mcp` correctly depends only on `magnotia-storage` (its sole job is to read the SQLite DB). The Tauri app does **not** depend on it, confirming the "separate process" claim in the README. +- `magnotia-ai-formatting` depends on both `core` and `llm`. Reasonable. + +> **Phase 2 will verify:** every `pub` item in the leaf crates (`audio`, `transcription`, `llm`, `storage`, `hotkey`) has at least one external consumer. Internal-only items shouldn't be `pub`. + +--- + +## 5. External surfaces + +### 5.1 Tauri commands + +**102 `#[tauri::command]` attributes** across **22 of 25** modules in `src-tauri/src/commands/`. +- `power.rs` and `security.rs` are utility modules (no commands; helpers only). +- `mod.rs` is the registry. + +| Module | # commands | Module | # commands | +|---|---:|---|---:| +| `tasks` | 12 | `intentions` | 5 | +| `models` | 12 | `audio` | 4 | +| `llm` | 10 | `tts` | 3 | +| `profiles` | 9 | `transcription` | 3 | +| `transcripts` | 8 | `paste` | 3 | +| `windows` | 8 | `update` | 2 | +| `diagnostics` | 6 | `rituals` | 2 | +| `hotkey` | 5 | `live` | 2 | +| | | `hardware` | 2 | +| | | `feedback` | 2 | +| | | `nudges`, `meeting`, `fs`, `clipboard` | 1 each | + +**Every one of these is a trust boundary** — Phase 4 (security) will audit input validation per command. + +### 5.2 MCP tools (read-only stdio) + +Confirmed in `crates/mcp/src/lib.rs`: +- `list_transcripts` +- `get_transcript` +- `search_transcripts` +- `list_tasks` + +The `init_readonly` connection mode in `magnotia-storage` is opened at OS level (`SQLITE_OPEN_READONLY`), per `crates/mcp/src/main.rs:18` — Phase 4 will confirm with a write-attempt test. + +### 5.3 Frontend route surface + +| Route | Purpose | Layout | +|---|---|---| +| `/` | Main dictation shell | `+layout.svelte` (sidebar + chrome) | +| `/float` | Tasks float window | `+layout@.svelte` (chrome-free) | +| `/viewer` | Transcript editor | `+layout@.svelte` (chrome-free) | +| `/preview` | Live transcription overlay | `+layout@.svelte` (chrome-free) | + +**Pages:** `DictationPage`, `SettingsPage`, `HistoryPage`, `TasksPage`, `FilesPage`, `FirstRunPage`, `ShutdownRitualPage` (7). + +**Stores:** `page`, `preferences`, `profiles`, `toasts`, `focusTimer`, `llmStatus`, `nudgeBus`, `implementationIntentions`, `completionStats`, `speaker` (10). + +**Components:** 25 in `src/lib/components/`. + +**i18n locales:** `en`, `es`, `de` (scaffolding only — most strings are still hard-coded; the migration is incremental per README). + +### 5.4 Model registry + +7 models declared in `crates/core/src/model_registry.rs`: +- Whisper (6): `whisper-tiny-en`, `whisper-base-en`, `whisper-small-en`, `whisper-distil-small-en`, `whisper-medium-en`, `whisper-distil-large-v3` +- Parakeet (1): `parakeet-ctc-0.6b-int8` + +> Moonshine is mentioned in the README's `magnotia-core` description ("Moonshine entries") but **no Moonshine entry exists in the registry**. See §7. + +--- + +## 6. Test floor + +| Location | Count | +|---|---:| +| `crates/*/src/` (lib tests) | 217 | +| `crates/*/tests/` (integration) | 3 | +| `src-tauri/src/` + `src-tauri/tests/` | 67 | +| **Total** | **287** | + +Only 3 cross-crate integration tests is light. Per-crate lib tests dominate. Phase 5 (test integrity) will mutation-test the heavy crates (`storage`, `transcription`, `llm`) to grade whether these tests actually pin behaviour. + +--- + +## 7. README ↔ code drift + +Items where the README disagrees with the code as-of this audit: + +| README claim | Reality | Severity | +|---|---|---| +| "245 automated lib tests across 10 crates" (line 14) | **287 tests** total (220 lib + 67 src-tauri); 220 lib-only | LOW — undercount (good direction, but stale) | +| "10 crates" (line 14) | 9 library crates + 1 app crate (`src-tauri`) — depends how you count; technically the workspace has 10 packages | OK if counting `src-tauri`; misleading otherwise | +| "Commands: audio, clipboard, diagnostics, hotkey, live, llm, meeting, models, paste, power, profiles, tasks, transcription, transcripts, update, windows" (line 95-97) — 16 listed | **22 modules with commands**: README missing `feedback`, `fs`, `intentions`, `nudges`, `rituals`, `tts`. Architecture diagram and §"Tauri commands" table both stale. | **MED** — visible to anyone evaluating the codebase | +| "18 Tauri command modules" (line 117) | **25 files** in `commands/` (22 with command attrs + `mod`, `power`, `security`) | MED | +| `magnotia-core` "model registry (Whisper + Parakeet + Moonshine entries)" (line 165) | **No Moonshine entries** in `model_registry.rs`. 6 Whisper + 1 Parakeet only. | **MED** — claims an unimplemented feature | +| Stores listed: `settings, profiles, tasks, history, taskLists, templates, page, toasts, preferences` (line 202) | Actual stores: `page, preferences, profiles, toasts, focusTimer, llmStatus, nudgeBus, implementationIntentions, completionStats, speaker`. README list is **largely fictional** — there is no `tasks`, `history`, `taskLists`, `templates`, or `settings` store as a separate file. | **HIGH** — describes architecture that doesn't exist | +| `magnotia-cloud-providers` "BYOK cloud-STT provider stubs… Currently empty scaffolding. When populated: OpenAI-compatible endpoint + Anthropic" (line 172) | Crate has an in-memory API-key store with env-var fallback — not "empty scaffolding". No HTTP code, no provider implementations. | LOW — partial | +| "Every new workspace crate needs a `description` in its `Cargo.toml`" (line 362, contributing rule) | **`crates/llm/Cargo.toml` has no `description` field.** Self-violation of the contribution rule. | LOW — easy fix | +| README §"Architecture" Rust crate list spelling (line 102-104) | Correct, but the manual line-break formatting got mangled by the rebrand sweep — visible whitespace inconsistency. | TRIVIAL | + +> **Phase 0 verdict on documentation truth:** The README is **mostly right but actively misleading in two places** — the stores list and the Moonshine claim. Both will fail an acquirer's first sanity-check (`grep -r "Moonshine" crates/`) and erode trust in the rest of the doc. + +--- + +## 8. HANDOVER files + +| File | Date | Topic | Status | +|---|---|---|---| +| `HANDOVER.md` | 2026-04-25 | Latest session (Phase 9a–9d) | Active reference | +| `HANDOVER-2026-04-24.md` | 2026-04-24 | Phase 8 close | Historical | +| `HANDOVER-2026-04-19.md` | 2026-04-19 | Earlier session | Historical | +| `HANDOVER-2026-04-18.md` | 2026-04-18 | Earlier session | Historical | +| `HANDOVER-2026-04-17.md` | 2026-04-17 | Earliest in tree | Historical | + +Five handovers in the repo root is unusual — most projects keep one. Phase 8 (docs truth) will recommend either archiving them under `docs/handovers/` or rotating to a single `HANDOVER.md` with prior content moved. + +The post-rebrand state: all five handovers were rewritten by today's sweep (line counts identical, words different). They now reference `magnotia` paths but their **content** describes work done under the `kon` / `corbie` names — there's a temporal-vs-naming mismatch a reader has to mentally track. Acquirer-friendly fix: add a one-line note at the top of each historical handover saying "Originally written when the product was named X; references rewritten 2026-04-30." + +--- + +## 9. Quick wins surfaced (defer to Phase 1, but worth flagging) + +1. **Add `description` to `crates/llm/Cargo.toml`** — 1-line fix; closes a self-imposed contribution-rule violation. +2. **Update README stores list** — replace fiction with reality. See §7. +3. **Remove or implement Moonshine claim** — README, line 165. +4. **Update README Tauri commands list** — six modules undocumented. See §7. +5. **Decide on `magnotia-cloud-providers`** — currently 80 LOC of a keystore that two consumers call. Either fold into `magnotia-core::keystore` (it's not provider-specific) or actually grow it. Right now it's a crate that doesn't earn its existence. + +--- + +## 10. Phase 1 entry plan + +Based on this cartography, Phase 1 (Lean-pass) should target — in this order — the highest-value, lowest-risk wins: + +1. `cargo machete` + `cargo udeps` workspace-wide → unused deps kill list. +2. `knip` on the frontend → unused TS/Svelte modules. +3. Manual review of the **5 files >1k LOC** for duplicate logic (`SettingsPage.svelte`, `database.rs`, `live.rs`, `migrations.rs`, `DictationPage.svelte`). +4. Grep audit of `TODO` / `FIXME` / `unimplemented!` / `unwrap()` outside tests → tech-debt log. +5. Reconcile the §7 README drifts. + +Estimated time: **1 working day** to deliver Phase 1 in full. + +--- + +*End of Phase 0 cartography.*