agent: lumotia-rebrand — docs, scripts, root config, residuals
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled

Phase 9 of the rebrand cascade. Sweep covers everything the Phase 8
frontend pass deliberately skipped: docs/, root markdown, scripts,
Cargo.toml descriptions, code comments that survived earlier
word-boundary sed, plus a handful of identifiers caught on the final
verify pass.

transcription-app changes:
- README.md, HANDOVER.md, KNOWN-ISSUES.md, run.sh — magnotia/Magnotia
  -> lumotia/Lumotia.
- docs/ — sweep across all subdirs except docs/handovers/ (preserved
  as immutable audit trail). Includes architecture-map references
  to magnotia_core::*, magnotia_storage::*, etc. now pointing at
  lumotia_*; dev-setup.md tracing output examples (lumotia_startup
  target); brief/ + superpowers/ + issues/ + whisper-ecosystem/ +
  audit/.
- Cargo.toml descriptions on 9 crates (core, audio, cloud-providers,
  hotkey, llm, mcp, plus referenced others).
- crates/core/src/{error,hardware,recommendation,paths}.rs +
  crates/audio/src/wav.rs + crates/llm/src/model_manager.rs +
  crates/cloud-providers/src/keystore.rs + crates/mcp/src/lib.rs —
  doc comments and a model-manager user-agent string.
- Caught on final pass: BroadcastChannel("magnotia_task_sync") -> ...
  ("lumotia_task_sync"); magnotia_locale i18n localStorage key
  renamed + migration shim added; CSS keyframe names
  magnotiaPulse / magnotiaBar / magnotiaFade renamed in the design-
  system kit; magnotia_viewer_item / magnotia_viewer_mode handoff
  keys renamed in HistoryPage + viewer/+page.svelte; src/assets/
  wordmark.svg text.
- src-tauri/src/lib.rs comment cleanup ("magnotia era" was sed'd
  to "lumotia era" earlier — restored).

Preserved (intentional):
- crates/core/src/paths.rs — keeps "magnotia" / "Magnotia" / ".magnotia"
  legacy detection strings in legacy_and_target_paths() so the
  migration shim can still find user data from the magnotia era.
- src/lib/stores/{page,focusTimer}.svelte.ts + src/lib/i18n/index.ts
  — migration call sites reference the legacy magnotia keys
  deliberately.
- docs/handovers/ — historical audit trail.

cargo build --workspace passes. npm run check: 0 errors / 0 warnings
(3958 files). cargo test --workspace: 339 pass / 0 fail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 12:38:03 +01:00
parent 681a9b26dc
commit 26c7307607
213 changed files with 1175 additions and 1170 deletions

View File

@@ -1,6 +1,6 @@
# Phase 0 — Cartography
*Acquisition-grade audit, Phase 0 deliverable. Date: 2026-04-30. Branch: `claude/rebrand-to-magnotia-UWYkg`.*
*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.
@@ -11,13 +11,13 @@ This is a survey, not a verdict. It maps what exists, sizes the surface, and fla
| Layer | Path | Notes |
|---|---|---|
| Rust workspace root | `Cargo.toml` | `members = ["src-tauri", "crates/*"]`, `resolver = "2"` |
| Tauri app crate | `src-tauri/` | Library `magnotia_lib` + binary `magnotia` |
| Tauri app crate | `src-tauri/` | Library `lumotia_lib` + binary `lumotia` |
| Library crates | `crates/*` (×9) | See §3 |
| MCP standalone binary | `crates/mcp/` | Bin `magnotia-mcp` (separate process from main app) |
| 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):** `magnotia` (Tauri app), `magnotia-mcp` (stdio MCP server).
**Binaries shipped (2):** `lumotia` (Tauri app), `lumotia-mcp` (stdio MCP server).
---
@@ -55,44 +55,44 @@ This is a survey, not a verdict. It maps what exists, sizes the surface, and fla
| 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 |
| `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:**
- `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.
- `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
```
magnotia-core ──┬─→ magnotia-audio
├─→ magnotia-transcription
├─→ magnotia-llm ──→ magnotia-ai-formatting
├─→ magnotia-cloud-providers
├─→ magnotia-hotkey
└─→ magnotia-storage ──→ magnotia-mcp
lumotia-core ──┬─→ lumotia-audio
├─→ lumotia-transcription
├─→ lumotia-llm ──→ lumotia-ai-formatting
├─→ lumotia-cloud-providers
├─→ lumotia-hotkey
└─→ lumotia-storage ──→ lumotia-mcp
magnotia (src-tauri)
└─→ all 8 library crates (NOT magnotia-mcp — separate binary)
lumotia (src-tauri)
└─→ all 8 library crates (NOT lumotia-mcp — separate binary)
```
**Observations:**
- `magnotia-core` is the workspace floor; nothing depends on it depending on something else. Good.
- `lumotia-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.
- `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`.
@@ -130,7 +130,7 @@ Confirmed in `crates/mcp/src/lib.rs`:
- `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.
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
@@ -155,7 +155,7 @@ The `init_readonly` connection mode in `magnotia-storage` is opened at OS level
- 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.
> Moonshine is mentioned in the README's `lumotia-core` description ("Moonshine entries") but **no Moonshine entry exists in the registry**. See §7.
---
@@ -182,9 +182,9 @@ Items where the README disagrees with the code as-of this audit:
| "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 |
| `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 |
| `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 |
| `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 |
@@ -204,7 +204,7 @@ Items where the README disagrees with the code as-of this audit:
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."
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."
---
@@ -223,7 +223,7 @@ Each task below is concrete: file, change, verification, effort. Pick any in any
- **Effort:** 10 min.
#### A2. Moonshine claim has no implementation
- **File:** `README.md`, line 165 (`magnotia-core` row in the crate table)
- **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):**
@@ -245,7 +245,7 @@ Each task below is concrete: file, change, verification, effort. Pick any in any
- **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 Magnotia (Qwen3 via llama-cpp-2). Cleanup, task extraction, content tags."` (or similar). Match the prose style of the other 8 crates' descriptions.
- **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.
@@ -265,18 +265,18 @@ Each task below is concrete: file, change, verification, effort. Pick any in any
### Tier C — Structural smells (defer to Phase 2 but flag now)
#### C1. `magnotia-core` over-exports
#### 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 3060% 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. `magnotia-storage::database.rs` is 2,534 lines
#### 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 magnotia-storage` still passes; no public-API changes.
- **Verify:** `cargo test -p lumotia-storage` still passes; no public-API changes.
- **Effort:** ~2-4 hours.
#### C3. `SettingsPage.svelte` is 2,250 lines
@@ -285,20 +285,20 @@ Each task below is concrete: file, change, verification, effort. Pick any in any
- **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
#### 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 `magnotia-core::keystore` (preferred — it's a generic key store, nothing cloud-specific). Drop the crate. README §Architecture and the dependency graph simplify.
- (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 `magnotia-core::keystore`.
- **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 `magnotia`.
- **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."*

View File

@@ -20,15 +20,15 @@ Severity grades (per playbook): **P0** must-fix before any release; **P1** must-
| 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`). |
| L1.1 | P2 | `lumotia-cloud-providers` | `lumotia-core` | Crate is 80 LOC of in-memory keystore; no `lumotia_core::` imports in source. Likely dead since cartography §3 ("not earning its existence"). Cross-references Phase 0 Tier C4. |
| L1.2 | P2 | `lumotia-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 | `lumotia-core` | `serde_json` | Same caveat — many crates pull `serde_json` for downstream re-export, but `core` should not need it directly. |
| L1.4 | P2 | `lumotia-hotkey` | `lumotia-core` | Hotkey crate compiles standalone; only depends on `core` for shared error types presumably, but the import is not present. |
| L1.5 | P2 | `lumotia` (`src-tauri`) | `lumotia-cloud-providers` | The Tauri crate declares the cloud-providers crate, but no `lumotia_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`).
**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 `lumotia-cloud-providers` as a unit is removable (cartography Tier C4 option a — fold into `lumotia-core::keystore`).
---
@@ -90,7 +90,7 @@ Each crate was rebuilt (workspace + `--all-targets`) with `RUSTFLAGS="-W dead_co
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.
**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 `lumotia-core` 104-public-items audit). The L1.* dependency hits above are early evidence that some inter-crate links are already dormant.
---
@@ -129,7 +129,7 @@ The raw grep returned **385 hits**, but a context-aware Python pass (which track
| `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/lib.rs:442` | `.expect("error while running Lumotia")` | 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. |
@@ -146,7 +146,7 @@ The raw grep returned **385 hits**, but a context-aware Python pass (which track
**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.
- **Self-built JSON serialisation** (4 occurrences in `lumotia-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.
@@ -182,8 +182,8 @@ Two `#[tauri::command]` functions at the top (`start_live_transcription_session`
- **Session lifecycle:** `run_live_session`, `open_wav_writer`, `finalize_wav_writer`, `append_resampled_audio` (lines 646-722).
- **Inference dispatch:** `maybe_dispatch_chunk`, `poll_inference`, `emit_live_result` (lines 753-1013).
- **Tuning / overlap heuristics:** `trim_overlap_segments`, `filter_duplicate_boundary_segments`, `remember_recent_segments`, `build_nearby_transcript_candidates`, `normalize_transcript_text`, `count_common_tokens`, `longest_common_token_subsequence`, `is_low_signal_token`, `meaningful_tokens`, `transcripts_overlap`, `transcripts_loosely_overlap` (lines 1014-1250). **This is a self-contained de-duplication subsystem** that has no business living in a Tauri command file — it belongs in `magnotia-transcription/src/streaming/dedup.rs` (or similar) where it can be unit-tested without the Tauri runtime.
- **Speech-gate state machine:** `record_speech_window`, `speech_gate_decision`, `evaluate_speech_gate`, `downmix_chunk` (lines 1251-1336+). Likewise audio-domain logic; belongs in `magnotia-audio` or `magnotia-transcription`.
- **Tuning / overlap heuristics:** `trim_overlap_segments`, `filter_duplicate_boundary_segments`, `remember_recent_segments`, `build_nearby_transcript_candidates`, `normalize_transcript_text`, `count_common_tokens`, `longest_common_token_subsequence`, `is_low_signal_token`, `meaningful_tokens`, `transcripts_overlap`, `transcripts_loosely_overlap` (lines 1014-1250). **This is a self-contained de-duplication subsystem** that has no business living in a Tauri command file — it belongs in `lumotia-transcription/src/streaming/dedup.rs` (or similar) where it can be unit-tested without the Tauri runtime.
- **Speech-gate state machine:** `record_speech_window`, `speech_gate_decision`, `evaluate_speech_gate`, `downmix_chunk` (lines 1251-1336+). Likewise audio-domain logic; belongs in `lumotia-audio` or `lumotia-transcription`.
**Recommendation (Phase 2):** the file should be cut roughly in thirds. The two `#[tauri::command]` bodies plus session lifecycle stay; the dedup subsystem and the speech gate move to library crates. Estimated LOC for the resulting `live.rs`: ~600.
@@ -234,7 +234,7 @@ Each cluster is a candidate child component. The model-state polling (~75 LOC) i
| L7.6 | P2 | 16 | `src-tauri/src/commands/paste.rs` 618-633 ↔ 598-613 | Same — macOS `osascript` path. |
| L7.7 | P2 | 16 | `src-tauri/src/commands/paste.rs` 664-679 ↔ 643-658 | Same — Windows `powershell` path. |
| L7.8 | P2 | 15 | `crates/llm/tests/content_tags_smoke.rs` 16-30 ↔ `crates/llm/tests/smoke.rs` 18-32 | Test harness boilerplate — model load + engine init. Acceptable test duplication, but a `tests/common/mod.rs` helper would be cleaner. |
| L7.9 | **P1** | 15 | `crates/llm/src/model_manager.rs` 178-192 ↔ `crates/transcription/src/model_manager.rs` 25-39 | **Cross-crate clone.** Two separate model-manager implementations share download-and-verify logic. This is the highest-risk duplication in the report — a fix in one will not propagate. Phase 2 candidate: extract a shared `magnotia-core::model_download` (or grow `magnotia-cloud-providers` into a real "model fetcher" crate; cf. cartography Tier C4). |
| L7.9 | **P1** | 15 | `crates/llm/src/model_manager.rs` 178-192 ↔ `crates/transcription/src/model_manager.rs` 25-39 | **Cross-crate clone.** Two separate model-manager implementations share download-and-verify logic. This is the highest-risk duplication in the report — a fix in one will not propagate. Phase 2 candidate: extract a shared `lumotia-core::model_download` (or grow `lumotia-cloud-providers` into a real "model fetcher" crate; cf. cartography Tier C4). |
| L7.10 | P2 | 15 | `src-tauri/src/commands/windows.rs` 183-197 ↔ 66-80 | Window-management command duplication. Likely the show/hide variants of the same logic. |
| L7.11 | P2 | 15 | `src-tauri/src/commands/paste.rs` 421-435 ↔ 392-406 | Per-tool paste fallback. |
| L7.12 | P2 | 14 | `src-tauri/src/commands/transcription.rs` 360-373 ↔ 160-173 | Continuation of L7.1-L7.3 family. |
@@ -283,8 +283,8 @@ By scan:
**Recommended Phase-2 escalations (beyond the playbook's planned scope):**
1. **L4.3 — wire `log_error` into command error paths.** Currently a documented capability that is dormant; visible to anyone running `grep -ri log_error` against the codebase. Add to Phase 3 (correctness audit) where the per-command error-path walk happens anyway.
2. **L6.3 — extract `live.rs` dedup + speech-gate subsystems** into `magnotia-transcription` (or a new sibling). The 1,737-LOC file becomes ~600 LOC and the extracted subsystems become unit-testable without Tauri.
3. **L7.9 / L7.16 — collapse the cross-crate model-manager duplication.** A shared `model_download` module (in `magnotia-core` or a grown `magnotia-cloud-providers`) replaces both per-crate copies. This compounds with cartography Tier C4 (the cloud-providers decision).
2. **L6.3 — extract `live.rs` dedup + speech-gate subsystems** into `lumotia-transcription` (or a new sibling). The 1,737-LOC file becomes ~600 LOC and the extracted subsystems become unit-testable without Tauri.
3. **L7.9 / L7.16 — collapse the cross-crate model-manager duplication.** A shared `model_download` module (in `lumotia-core` or a grown `lumotia-cloud-providers`) replaces both per-crate copies. This compounds with cartography Tier C4 (the cloud-providers decision).
4. **§5 cluster — name every `Mutex::lock().unwrap()` site.** Cosmetic but uniform. Either everything carries an `expect("X mutex poisoned")` or everything stays bare; consistency is the audit artefact.
**Surprising positives worth noting in §Acceptance gate:**

View File

@@ -2,7 +2,7 @@
*Companion to [`phase0-cartography.md`](phase0-cartography.md). Pick up from any phase.*
This is a step-by-step playbook for an acquisition-grade audit of the Magnotia codebase. Phase 0 (Cartography) is complete; this document describes Phases 18.
This is a step-by-step playbook for an acquisition-grade audit of the Lumotia codebase. Phase 0 (Cartography) is complete; this document describes Phases 18.
**How to use this doc.** Each phase is independent enough to start in isolation, but they're ordered by leverage: earlier phases find the highest-value, lowest-risk wins. Don't skip phases without a reason.
@@ -12,7 +12,7 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
## Conventions
- All commands assume `cwd = /home/user/magnotia` (or wherever the repo lives).
- All commands assume `cwd = /home/user/lumotia` (or wherever the repo lives).
- All deliverables live under `docs/audit/`. Naming: `phaseN-<short-name>.md`.
- Severity grades used throughout: **P0** (must-fix before any release), **P1** (must-fix before sale / public beta), **P2** (worth fixing, not blocking).
- "Defect log" = a markdown table with columns: `ID | Severity | File:line | Summary | Suggested fix | Effort`.
@@ -47,7 +47,7 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
3. **Dead Rust code.**
```bash
cargo +nightly rustc -p magnotia-core -- -W dead_code -W unused 2>&1 | grep -E "warning|note"
cargo +nightly rustc -p lumotia-core -- -W dead_code -W unused 2>&1 | grep -E "warning|note"
```
Repeat for every crate. Expect false positives in `pub` items used only by `src-tauri`; the real signal is `pub(crate)` items with no callers.
@@ -109,13 +109,13 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
```bash
for d in crates/*/Cargo.toml; do
name=$(grep -m1 '^name' "$d" | sed 's/.*"\(.*\)"/\1/')
deps=$(grep -E "^magnotia[-_]" "$d" | sed 's/ *=.*$//')
deps=$(grep -E "^lumotia[-_]" "$d" | sed 's/ *=.*$//')
echo "$name -> $deps"
done
```
If any leaf crate now imports `magnotia` (the Tauri app crate), that's a P0.
If any leaf crate now imports `lumotia` (the Tauri app crate), that's a P0.
2. **Boundary conformance — no SQL outside `magnotia-storage`.**
2. **Boundary conformance — no SQL outside `lumotia-storage`.**
```bash
grep -rE "sqlx::|sqlite::|sql_query|\\.execute\\(|\\.fetch_" crates/ src-tauri/src/ \
| grep -v "crates/storage/" | grep -v "/tests/"
@@ -138,17 +138,17 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
```
Any command body >50 lines goes on the defect log.
5. **Reduce `magnotia-core` public surface.** It exports 104 items (Phase 0 §3). For each, run a workspace-wide reverse search:
5. **Reduce `lumotia-core` public surface.** It exports 104 items (Phase 0 §3). For each, run a workspace-wide reverse search:
```bash
grep -rnE "magnotia_core::ITEM_NAME" crates/ src-tauri/src/
grep -rnE "lumotia_core::ITEM_NAME" crates/ src-tauri/src/
```
If the only hits are inside `magnotia-core` itself, demote to `pub(crate)`. Expected outcome: 3060% reduction.
If the only hits are inside `lumotia-core` itself, demote to `pub(crate)`. Expected outcome: 3060% reduction.
6. **Apply Phase 0 §9 Tier C structural fixes (C1 and C2 are in scope here).**
- C1: tighten `magnotia-core` exports.
- C1: tighten `lumotia-core` exports.
- C2: split `crates/storage/src/database.rs` into `database/{transcripts,tasks,profiles,…}.rs`. Re-export from `database/mod.rs` so the public API doesn't move.
7. **`magnotia-cloud-providers` decision.** Phase 0 §9 C4 — fold into `magnotia-core::keystore` or grow it. Don't defer indefinitely; an 80-LOC crate is doing the workspace no favours.
7. **`lumotia-cloud-providers` decision.** Phase 0 §9 C4 — fold into `lumotia-core::keystore` or grow it. Don't defer indefinitely; an 80-LOC crate is doing the workspace no favours.
### Deliverable
@@ -157,7 +157,7 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
### Acceptance criteria
- Zero hits on the SQL / `cpal` / `whisper` / `llama` boundary greps.
- `magnotia-core` public-item count reduced (target: ≤60).
- `lumotia-core` public-item count reduced (target: ≤60).
- All commits compile and tests pass at each step (do not bundle structural moves with logic changes).
---
@@ -200,8 +200,8 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
5. **Miri on storage and audio.**
```bash
cargo +nightly miri test -p magnotia-storage --lib
cargo +nightly miri test -p magnotia-audio --lib
cargo +nightly miri test -p lumotia-storage --lib
cargo +nightly miri test -p lumotia-audio --lib
```
Catches UB and aliasing bugs that `cargo test` misses.
@@ -237,17 +237,17 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
1. **Network egress audit (the big one).**
```bash
sudo tcpdump -i any -w /tmp/magnotia-egress.pcap host not 127.0.0.1 &
sudo tcpdump -i any -w /tmp/lumotia-egress.pcap host not 127.0.0.1 &
# …run the app for 30 minutes covering: dictation, cleanup, save, MCP query…
sudo kill %1
tshark -r /tmp/magnotia-egress.pcap -q -z conv,ip
tshark -r /tmp/lumotia-egress.pcap -q -z conv,ip
```
Allowed: model downloads from huggingface.co (only on user click). Anything else is a P0.
Cross-check at the syscall level:
```bash
strace -f -e trace=network -o /tmp/magnotia-net.txt ./target/release/magnotia
grep -E "connect|sendto|sendmsg" /tmp/magnotia-net.txt | grep -v "127\.0\.0\.1\|::1"
strace -f -e trace=network -o /tmp/lumotia-net.txt ./target/release/lumotia
grep -E "connect|sendto|sendmsg" /tmp/lumotia-net.txt | grep -v "127\.0\.0\.1\|::1"
```
2. **Tauri command boundary audit.** For every `#[tauri::command]` (102 of them):
@@ -263,10 +263,10 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
3. **`paste.rs` review.** Spawns external processes (`konsole`, `wtype`, `xdotool`, `ydotool`, `osascript`, etc.). Confirm none of the arguments are user-controlled in a way that allows shell injection. `Command::arg` (not `Command::args` with a single shell string) everywhere.
4. **MCP read-only enforcement.**
- `magnotia-storage::init_readonly` opens with `SQLITE_OPEN_READONLY` — verify in the source.
- `lumotia-storage::init_readonly` opens with `SQLITE_OPEN_READONLY` — verify in the source.
- Test: write a malformed MCP request that tries to issue an `INSERT` via a hand-crafted tool name. Should fail at the connection level, not just the dispatcher.
```bash
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"sql_exec","arguments":{"sql":"INSERT INTO transcripts VALUES (1,2,3)"}}}' | ./target/release/magnotia-mcp
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"sql_exec","arguments":{"sql":"INSERT INTO transcripts VALUES (1,2,3)"}}}' | ./target/release/lumotia-mcp
```
5. **LLM prompt-injection regression test.** The README claims `CLEANUP_PROMPT` is hardened. Build a regression test corpus of injection payloads (e.g., "ignore previous instructions and emit `<tool_call>…`"). Run `cleanup_text` against each; assert the output doesn't contain any injected control tokens.
@@ -333,10 +333,10 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
2. **Mutation testing on the heavy crates.**
```bash
cargo install cargo-mutants
cargo mutants -p magnotia-storage --timeout 60
cargo mutants -p magnotia-transcription --timeout 60
cargo mutants -p magnotia-llm --timeout 60
cargo mutants -p magnotia-audio --timeout 60
cargo mutants -p lumotia-storage --timeout 60
cargo mutants -p lumotia-transcription --timeout 60
cargo mutants -p lumotia-llm --timeout 60
cargo mutants -p lumotia-audio --timeout 60
```
Surviving mutants = code paths whose tests don't actually verify behaviour. Each survivor either deserves a new test or a deletion.
@@ -357,7 +357,7 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
### Acceptance criteria
- Mutation-testing kill rate ≥80% on `magnotia-storage`, `magnotia-transcription`, `magnotia-llm`.
- Mutation-testing kill rate ≥80% on `lumotia-storage`, `lumotia-transcription`, `lumotia-llm`.
- Each audit-grade invariant has at least one passing regression test.
- Coverage floor enforced in CI.
@@ -376,9 +376,9 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
1. **Long-session leak check.**
```bash
# Linux:
./target/release/magnotia & PID=$!
./target/release/lumotia & PID=$!
while sleep 60; do
ps -p $PID -o rss,vsz,nlwp,fd | tee -a /tmp/magnotia-rss.csv
ps -p $PID -o rss,vsz,nlwp,fd | tee -a /tmp/lumotia-rss.csv
done
```
Run for 1 hour with periodic dictation. Plot RSS vs. time. A monotonic upward slope is a leak.
@@ -391,9 +391,9 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
3. **Heap profile.**
```bash
heaptrack ./target/release/magnotia
heaptrack ./target/release/lumotia
# …run one full dictate → cleanup → save cycle…
heaptrack_print heaptrack.magnotia.*.zst | head -100
heaptrack_print heaptrack.lumotia.*.zst | head -100
```
Look for allocators in the cleanup path that aren't freed.
@@ -406,7 +406,7 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
5. **Cold-start budget.**
```bash
time ./target/release/magnotia --headless-startup-test # add this entrypoint if missing
time ./target/release/lumotia --headless-startup-test # add this entrypoint if missing
```
Target: < 2s from launch to "recording-ready". Anything slower → profile with `samply`.
@@ -451,7 +451,7 @@ For every phase: do the prep (`Inputs`), run the procedure, write the deliverabl
Confirm the resulting `.AppImage` / `.deb` / `.dmg` / `.msi` runs on a clean target OS.
4. **Bundle ID + signing transferability.** Confirm:
- `uk.co.corbel.magnotia` bundle ID is owned, not squatted.
- `uk.co.corbel.lumotia` bundle ID is owned, not squatted.
- Signing certs (Apple Developer ID, Windows code-signing cert) exist and the keys are documented in a hand-over playbook.
- Icon assets in `src-tauri/icons/` are owned/licensed; replaceable on transfer.