# Phase 0 — Cartography *Acquisition-grade audit, Phase 0 deliverable. Date: 2026-04-30. Branch: `claude/rebrand-to-lumotia-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 `lumotia_lib` + binary `lumotia` | | Library crates | `crates/*` (×9) | See §3 | | MCP standalone binary | `crates/mcp/` | Bin `lumotia-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):** `lumotia` (Tauri app), `lumotia-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 | |---|---:|---:|---:|---:| | `lumotia-core` | 1,212 | 9 | 10 / 104 | 16 | | `lumotia-audio` | 1,533 | 8 | 14 / 38 | 14 | | `lumotia-transcription` | 2,617 | 12 | 13 / 51 | 51 | | `lumotia-llm` | 1,330 | 6 | 27 / 56 | 17 | | `lumotia-ai-formatting` | 1,502 | 6 | 9 / 21 | 47 | | `lumotia-storage` | 3,771 | 4 | 6 / 69 | 60 | | `lumotia-hotkey` | 632 | 3 | 5 / 14 | 4 | | `lumotia-cloud-providers` | 80 | 2 | 2 / 3 | 2 | | `lumotia-mcp` | 584 | 2 | 8 / 8 | 9 | | `src-tauri` (`lumotia` + `lumotia_lib`) | 8,330 | 27 | n/a | 67 | | **Total** | **21,591** | | | **287** | **Outliers worth a Phase-2 look:** - `lumotia-core` exposes 104 public items — high for a "shared types" crate; likely leakage of internals. - `lumotia-storage` exposes 69 public items across only 4 files; the file split is suspect (2.5k-line `database.rs`). - `lumotia-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 ``` lumotia-core ──┬─→ lumotia-audio ├─→ lumotia-transcription ├─→ lumotia-llm ──→ lumotia-ai-formatting ├─→ lumotia-cloud-providers ├─→ lumotia-hotkey └─→ lumotia-storage ──→ lumotia-mcp lumotia (src-tauri) └─→ all 8 library crates (NOT lumotia-mcp — separate binary) ``` **Observations:** - `lumotia-core` is the workspace floor; nothing depends on it depending on something else. Good. - DAG is clean — no cycles, no upward dependencies. - `lumotia-mcp` correctly depends only on `lumotia-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. - `lumotia-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 `lumotia-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 `lumotia-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 | | `lumotia-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 | | `lumotia-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 `lumotia` 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.ts` file under `src/lib/stores/`. - **Fix:** rewrite the bullet to enumerate the actual ten store files, and clarify that `page.svelte.ts` is 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 (`lumotia-core` row in the crate table) - **Current:** `model registry (Whisper + Parakeet + Moonshine entries)` - **Reality:** `crates/core/src/model_registry.rs` has 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 wired` constant in `model_registry.rs` and 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 | sort` matches the README table 1:1 (excluding `mod`, `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 has `name`, `version`, `edition` only. - **Reality:** README §Contributing line 362 declares this a hard rule. Self-violation. - **Fix:** add `description = "Local LLM engine for Lumotia (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"; done` returns 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 say `comprehensive automated test floor — see CI for current count`. - **Verify:** `grep -rE '#\[(test|tokio::test)\]' crates/*/src/ | wc -l` matches 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. `lumotia-core` over-exports - **File(s):** `crates/core/src/lib.rs` and 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 `pub` item; demote anything not used outside the crate to `pub(crate)`. The expected outcome is a 30–60% reduction in public surface. - **Verify:** after the demotion pass, `cargo +nightly rustdoc` should still succeed and downstream crates should still compile without changes. - **Effort:** ~½ day (Phase 2 scope). #### C2. `lumotia-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 lumotia-storage` still 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.svelte` was 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. `lumotia-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 `lumotia-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-stt` feature flag. Earn the boundary. - **Verify (option a):** workspace builds with `cloud-providers` removed from `Cargo.toml` members; the two consumers (`commands/llm.rs` and wherever else) re-import from `lumotia-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`/`corbie` work but read as `lumotia`. - **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.md` in root, or also move under `docs/handovers/HANDOVER-latest.md` with a symlink — pick one. - **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`](phases-1-8-playbook.md) — should then target, in order: 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. 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.*