Phase 0 update: replaces the loose "quick wins" list with a structured Fix Areas section organised into impact tiers (A: high-impact README truth fixes, B: low-effort self-violation fixes, C: structural smells deferred to Phase 2, D: hygiene). Each task names the file, the change, the verification command, and the effort estimate. New playbook: docs/audit/phases-1-8-playbook.md — step-by-step acquisition-grade audit procedure for the remaining seven phases. Each phase has goal, inputs, procedure (with concrete commands), deliverable, acceptance criteria, and time estimate. Designed to be picked up independently from any phase.
19 KiB
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), andlive.rs(1.7k) are each large enough to deserve a structural review in isolation. HANDOVER.md already flagsSettingsPageas 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-coreexposes 104 public items — high for a "shared types" crate; likely leakage of internals.magnotia-storageexposes 69 public items across only 4 files; the file split is suspect (2.5k-linedatabase.rs).magnotia-cloud-providersis 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-coreis the workspace floor; nothing depends on it depending on something else. Good.- DAG is clean — no cycles, no upward dependencies.
magnotia-mcpcorrectly depends only onmagnotia-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-formattingdepends on bothcoreandllm. Reasonable.
Phase 2 will verify: every
pubitem in the leaf crates (audio,transcription,llm,storage,hotkey) has at least one external consumer. Internal-only items shouldn't bepub.
5. External surfaces
5.1 Tauri commands
102 #[tauri::command] attributes across 22 of 25 modules in src-tauri/src/commands/.
power.rsandsecurity.rsare utility modules (no commands; helpers only).mod.rsis 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_transcriptsget_transcriptsearch_transcriptslist_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-coredescription ("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. Fix areas — actionable tasks
Each task below is concrete: file, change, verification, effort. Pick any in any order; they don't depend on later phases. Items are grouped by impact tier.
Tier A — High impact, do first
A1. README stores list is fiction
- File:
README.md, line 202 - Current:
Reactive stores (src/lib/stores/page.svelte.ts): settings, profiles, tasks, history, taskLists, templates, page, toasts, preferences. - Reality: stores are
page,preferences,profiles,toasts,focusTimer,llmStatus,nudgeBus,implementationIntentions,completionStats,speaker— each in its own*.svelte.tsfile undersrc/lib/stores/. - Fix: rewrite the bullet to enumerate the actual ten store files, and clarify that
page.svelte.tsis the central app-state store (transcripts, profiles, taskLists, etc. live as fields on it). - Verify:
ls src/lib/stores/matches the README list 1:1. - Effort: 10 min.
A2. Moonshine claim has no implementation
- File:
README.md, line 165 (magnotia-corerow in the crate table) - Current:
model registry (Whisper + Parakeet + Moonshine entries) - Reality:
crates/core/src/model_registry.rshas 6 Whisper + 1 Parakeet entries. Zero Moonshine. - Fix (pick one):
- (a) Remove the Moonshine reference from the README. Cheapest.
- (b) Add a
// TODO(moonshine): not yet wiredconstant inmodel_registry.rsand a roadmap entry under §Roadmap, so the claim is at least flagged as forthcoming.
- Verify:
grep -ri moonshine crates/ src-tauri/ src/returns no orphan references. - Effort: 5 min (option a) / 30 min (option b).
A3. Six Tauri command modules undocumented
- File:
README.md, lines 95-97 (Architecture diagram) and 175-195 (Tauri commands table) - Missing:
feedback,fs,intentions,nudges,rituals,tts - Fix: add a one-line description for each in the §Tauri commands table; add the names to the Architecture-diagram bullet list.
- Verify:
ls src-tauri/src/commands/*.rs | xargs basename -s .rs | sortmatches the README table 1:1 (excludingmod,power,security, which are utility modules — note that explicitly). - Effort: 20 min.
Tier B — Low effort, removes self-violations
B1. crates/llm/Cargo.toml missing description
- File:
crates/llm/Cargo.toml - Current:
[package]block hasname,version,editiononly. - Reality: README §Contributing line 362 declares this a hard rule. Self-violation.
- Fix: add
description = "Local LLM engine for Magnotia (Qwen3 via llama-cpp-2). Cleanup, task extraction, content tags."(or similar). Match the prose style of the other 8 crates' descriptions. - Verify:
for d in crates/*/Cargo.toml src-tauri/Cargo.toml; do grep -L "^description" "$d"; donereturns empty. - Effort: 2 min.
B2. Stale test-count claim
- File:
README.md, line 14 - Current:
245 automated lib tests across 10 crates, all passing - Reality: 287 tests total (220 lib + 67 src-tauri); 220 lib-only.
- Fix: decide on a number that's automatable, not a snapshot. Either: (a) replace with
220+ lib tests across 9 library crates plus 67 Tauri-app tests, or (b) drop the absolute number and saycomprehensive automated test floor — see CI for current count. - Verify:
grep -rE '#\[(test|tokio::test)\]' crates/*/src/ | wc -lmatches whatever number you ship. - Effort: 5 min.
B3. Crate count claim ambiguity
- File:
README.md, line 14 ("10 crates") - Reality: 9 library crates + 1 Tauri app crate. The README's own crate table only documents 9.
- Fix: say "9 library crates plus the Tauri app crate" — or just "9 library crates" and let the Tauri app stand separately, which matches the existing prose.
- Effort: 2 min.
Tier C — Structural smells (defer to Phase 2 but flag now)
C1. magnotia-core over-exports
- File(s):
crates/core/src/lib.rsand the modules it re-exports - Symptom: 104 public items in a "shared types" crate. High blast radius for any change.
- Fix (Phase 2 work, do not touch yet): audit every
pubitem; demote anything not used outside the crate topub(crate). The expected outcome is a 30–60% reduction in public surface. - Verify: after the demotion pass,
cargo +nightly rustdocshould still succeed and downstream crates should still compile without changes. - Effort: ~½ day (Phase 2 scope).
C2. magnotia-storage::database.rs is 2,534 lines
- File:
crates/storage/src/database.rs - Symptom: single file holds CRUD for transcripts, tasks, subtasks, profiles, profile-terms, settings, error log, FTS5. No internal module boundaries.
- Fix (Phase 2): split by domain —
database/transcripts.rs,database/tasks.rs,database/profiles.rs, etc. Keep the public re-export shape unchanged so callers don't move. - Verify:
cargo test -p magnotia-storagestill passes; no public-API changes. - Effort: ~2-4 hours.
C3. SettingsPage.svelte is 2,250 lines
- File:
src/lib/pages/SettingsPage.svelte - Symptom: HANDOVER.md already flags this;
SettingsGroup.sveltewas prepared but the seven-group split was deferred. - Fix (Phase 2): complete the planned restructure. Pick this up from HANDOVER.md §"9c — Settings (scaled down)".
- Effort: ~½ day.
C4. magnotia-cloud-providers does not earn its existence
- Files:
crates/cloud-providers/(80 LOC across 2 files) - Symptom: crate contains an in-memory keystore with env-var fallback. Not "empty scaffolding" as the README says — but also not provider-specific. No HTTP code, no providers.
- Fix (decide, then act):
- (a) Fold into
magnotia-core::keystore(preferred — it's a generic key store, nothing cloud-specific). Drop the crate. README §Architecture and the dependency graph simplify. - (b) Grow it: actually implement an OpenAI-compatible STT client and an Anthropic STT client, gated behind a
cloud-sttfeature flag. Earn the boundary.
- (a) Fold into
- Verify (option a): workspace builds with
cloud-providersremoved fromCargo.tomlmembers; the two consumers (commands/llm.rsand wherever else) re-import frommagnotia-core::keystore. - Effort: ~1 hour (option a) / multi-day (option b).
Tier D — Hygiene (Phase 1 / Phase 8)
D1. Five HANDOVER files in repo root
- Files:
HANDOVER.md,HANDOVER-2026-04-{17,18,19,24}.md - Symptom: root noise; rebrand also rewrote their content so they describe
kon/corbiework but read asmagnotia. - Fix:
- Move the four dated files under
docs/handovers/. - Add a one-line italic note at the top of each historical file: "Originally written when the product was named Kon (and briefly Corbie); references rewritten in the 2026-04-30 rebrand sweep."
- Keep the latest as
HANDOVER.mdin root, or also move underdocs/handovers/HANDOVER-latest.mdwith a symlink — pick one.
- Move the four dated files under
- Effort: 15 min.
D2. Tauri command total count drift
- README says "18 Tauri command modules" (line 117); actual is 22 modules with commands (plus 3 utility modules in the same dir).
- Fix: update line 117 to "22 Tauri command modules + 3 utility modules (
mod,power,security)". - Effort: 1 min — usually folded into A3.
10. Phase 1 entry plan
Tier A and Tier B fixes above (≈45 min total) bring the README back into truth and close the self-imposed Cargo.toml rule. Do these as a warm-up before Phase 1 proper; they make every subsequent phase' "what does the README say?" comparison cheaper.
Phase 1 (Lean-pass) — see phases-1-8-playbook.md — should then target, in order:
cargo machete+cargo udepsworkspace-wide → unused deps kill list.knipon the frontend → unused TS/Svelte modules.- Manual review of the 5 files >1k LOC for duplicate logic (
SettingsPage.svelte,database.rs,live.rs,migrations.rs,DictationPage.svelte). - Grep audit of
TODO/FIXME/unimplemented!/unwrap()outside tests → tech-debt log. - Apply the Tier C structural smells if Phase 2 is being done immediately afterwards.
Estimated time: 1 working day for Phase 1 in full, plus ~45 min of Tier A/B fixes.
End of Phase 0 cartography.