docs: architecture map (initial 5-slice generation, 105 pages)

Five-slice navigable map of the entire codebase under
docs/architecture-map/. Each slice is a self-contained
breadcrumbed sub-tree:

  01-frontend (16)              Svelte/SvelteKit UI
  02-tauri-runtime (26)         src-tauri commands + lifecycle
  03-audio-transcription (16)   audio + transcription crates
  04-llm-formatting-mcp (19)    llm, ai-formatting, mcp, cloud
  05-core-storage-hotkey-build  core, storage, hotkey, workspace,
                          (26) CI, dev glue

Plus master README.md and data-flow-end-to-end.md tracing
audio bytes from microphone to FTS5 search to MCP read.

Generated by 5 parallel subagents on 2026/05/09 against
HEAD 3c47000. Each page has YAML frontmatter, file:line code
refs, sibling cross-links, plain-English summaries.

Aggregated debt surfaced (full lists in master README):
RB-08 macOS power assertion, schema head drift v14 vs v15,
VAD blocked on ort version conflict, streaming primitives
not wired into live.rs, no prompt versioning, MCP has no
auth, cloud-providers in-memory keystore, SettingsPage
2 484 LOC, commands/live.rs 1 737 LOC, dual theme system,
brand rename to Lumenote pending across the codebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
jars
2026-05-09 14:04:13 +01:00
parent 3c47000ea9
commit a1f3f3f134
105 changed files with 11266 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
---
name: Slice 5 — Core, Storage, Hotkey, Build
type: architecture-map-page
slice: 05-core-storage-hotkey-build
last_verified: 2026/05/09
---
# Slice 5: Core, Storage, Hotkey, Build / CI
> **Where you are:** [Architecture map](../README.md) → Core, Storage, Hotkey, Build
**Plain English summary.** This slice is Magnotia's foundations. Three Rust crates the rest of the workspace builds on top of: `magnotia-core` (shared types, hardware probes, model registry, thread tuning), `magnotia-storage` (the SQLite database, FTS5 search, file-system paths), and `magnotia-hotkey` (a Wayland-friendly evdev hotkey listener for Linux). Plus the workspace-level glue that wires the Rust workspace together with the SvelteKit frontend: `Cargo.toml`, the GitHub Actions pipelines, the dev launcher, the static asset folder, and the package configuration files.
If a new engineer wants to know where a public type comes from, where a setting is persisted, or how a release artefact gets built, the answer is somewhere in this slice.
## At a glance
- **Crates:** three. `magnotia-core` (1,805 LOC), `magnotia-storage` (3,771 LOC), `magnotia-hotkey` (632 LOC). Total ~6,200 LOC.
- **Workspace glue:** `Cargo.toml` (161 bytes), `package.json`, `vite.config.js`, `svelte.config.js`, `jsconfig.json`, `run.sh`, `static/`, `.gitignore`.
- **CI:** three workflows — `check.yml` (per-push compile + lint + libs tests + frontend), `build.yml` (release-bundle build for tags + manual dispatch), `audit.yml` (weekly Mondays cargo-audit + npm-audit).
- **Database head:** schema version **15** (commit on disk, supersedes the v14 figure quoted in `HANDOVER.md` 2026/04/25).
- **Key external deps:** `sysinfo 0.35` (hardware), `libloading 0.8` (Vulkan loader probe), `sqlx 0.8` (no default features, runtime-tokio + sqlite only), `evdev 0.12` (Linux hotkeys), `notify 7` (device hotplug), `uuid 1` (v4, random).
- **Targets:** Linux (primary, evdev backend), Windows, macOS. Hotkey crate is no-op on non-Linux platforms — Tauri's global-shortcut plugin handles those targets.
- **Default profile UUID:** `00000000-0000-0000-0000-000000000001`. Created by migration v6, protected by SQL triggers from rename or delete.
## Map of this slice
`magnotia-core`:
- [Public types and enums (Segment, Transcript, Megabytes, ModelId, EngineName)](core-types-and-enums.md)
- [Constants module (sample rate, VAD, RAM thresholds, chunk timing)](core-constants.md)
- [Error type and Result alias](core-error.md)
- [Hardware probe (sysinfo + CpuFeatures + Vulkan loader)](core-hardware-probe.md)
- [Power-state probe (sysfs, 10s TTL cache, test override)](core-power.md)
- [Inference thread tuning (Workload, battery halve, GPU clamp)](core-tuning.md)
- [Model registry (Whisper + Parakeet entries with pinned SHA256)](core-model-registry.md)
- [Recommendation scoring (rank_recommendations)](core-recommendation.md)
- [Process-watch (meeting detection by process name)](core-process-watch.md)
- [App paths (database, recordings, models, logs)](core-paths.md)
`magnotia-storage`:
- [Storage overview (sqlx config, init flow, default features rationale)](storage-overview.md)
- [Schema and migrations (v1-v15 catalogue)](storage-schema-and-migrations.md)
- [FTS5 transcript search](storage-fts5-search.md)
- [Transcripts CRUD](storage-crud-transcripts.md)
- [Tasks and subtasks CRUD](storage-crud-tasks.md)
- [Profiles and profile_terms CRUD](storage-crud-profiles.md)
- [Settings, error log, feedback, implementation rules](storage-crud-settings-and-misc.md)
- [File storage paths (database, recordings, crashes, logs)](storage-file-paths.md)
`magnotia-hotkey`:
- [Linux evdev listener (devices, hotplug, modifiers, Pressed/Released)](hotkey-linux-evdev.md)
Workspace and build glue:
- [Workspace `Cargo.toml` (members, release profile)](workspace-cargo.md)
- [CI: `check.yml`, `build.yml`, `audit.yml`](ci-pipeline.md)
- [Dev launcher (`run.sh`) and root `package.json`](dev-launcher-and-scripts.md)
- [Vite, SvelteKit, jsconfig](frontend-build-config.md)
- [Static assets and `pcm-processor.js` worklet](static-assets.md)
- [`HANDOVER.md` and root `README.md` pointer](dev-handover-pointer.md)
## How this slice connects to others
- **`magnotia-core` is the universal lower bound.** Every other crate in the workspace depends on it. The shape contract is: `Segment`, `Transcript`, `ModelId`, `EngineName`, `Megabytes`, `AudioSamples`, `MagnotiaError`, `Result`, plus `paths::AppPaths`. See [`core-types-and-enums.md`](core-types-and-enums.md).
- **Slice 1 (frontend)** never imports any of these crates directly. It reaches them through Tauri commands (slice 2). The single setting key the frontend cares about is `magnotia_preferences` (a JSON blob), persisted via `magnotia_storage::get_setting` / `set_setting` (slice 5) called from the Tauri preferences command (slice 2).
- **Slice 2 (Tauri runtime)** is the heaviest consumer. It calls `magnotia_storage::init` at startup, registers the SQLite pool as Tauri-managed state, and every command in `src-tauri/src/commands/*.rs` reaches into `magnotia_storage` for persistence and `magnotia_core::paths` for filesystem locations. The hotkey command at `src-tauri/src/commands/hotkey.rs` is the sole consumer of `magnotia_hotkey::EvdevHotkeyListener`.
- **Slice 3 (audio + transcription)** consumes `magnotia_core::types::{AudioSamples, Segment, Transcript}` and `magnotia_core::constants::{WHISPER_SAMPLE_RATE, WHISPER_CHANNELS, PARAKEET_*, CHUNK_INTERVAL_MS}`. The transcription engines also consume `magnotia_core::tuning::inference_thread_count(Workload::Whisper, gpu_offloaded)` for thread sizing.
- **Slice 4 (LLM + formatting + MCP)** consumes `magnotia_core::tuning::{inference_thread_count, Workload::Llm}`, `magnotia_core::paths::AppPaths::llm_models_dir()`, `magnotia_core::types::Segment` (formatting), and `magnotia_core::constants::SMART_PARAGRAPH_GAP_SECS` (formatting). The MCP server is the only consumer of `magnotia_storage::init_readonly` — it opens the DB read-only so no MCP tool can mutate user data even if the dispatcher misroutes a request.
## Existing in-repo docs
These are the critical-issue write-ups from the 2026-04-22 review that overlap with slice 5. Cross-referenced from the relevant per-page file. **Not duplicated here.**
- [`docs/issues/c3-migrations-atomicity.md`](../../issues/c3-migrations-atomicity.md) — drove the v9-onwards transactional migration design. See [`storage-schema-and-migrations.md`](storage-schema-and-migrations.md).
- [`docs/issues/c4-transcript-profile-fk.md`](../../issues/c4-transcript-profile-fk.md) — drove migration v9, the table rebuild that landed `transcripts.profile_id` with a real foreign key. See [`storage-schema-and-migrations.md`](storage-schema-and-migrations.md).
- [`docs/issues/keystore-thread-safety.md`](../../issues/keystore-thread-safety.md) — keystore lives in `crates/cloud-providers/` (slice 4) but the lesson generalises to every shared mutable state in `magnotia-core`. Cross-referenced from the tuning page.
- [`docs/issues/hotkey-linux-device-filter.md`](../../issues/hotkey-linux-device-filter.md) — the RB-12 hard-coded `KEY_A` / `KEY_R` filter that the current `device_supports_combo` replaced. See [`hotkey-linux-evdev.md`](hotkey-linux-evdev.md).
- [`docs/issues/power-assertion-macos-objc2.md`](../../issues/power-assertion-macos-objc2.md) — RB-08, the only open MAJOR per `HANDOVER.md`. The implementation lives in slice 2 (`src-tauri`) but the API design lives near `magnotia-core` conceptually. Linked from the slice debt section.
- [`docs/audit/phase0-cartography.md`](../../audit/phase0-cartography.md) — phase-0 codebase cartography, predates this map but covers crate-graph topology in summary form.
- [`docs/code-review-2026-04-22.md`](../../code-review-2026-04-22.md) — full audit. Slice 5 work items: RB-08 (macOS power assertion), RB-12 (hotkey filter, fixed), C3 (migrations atomicity, fixed), C4 (transcript profile FK, fixed). Several MAJORs across the slice 2 / 3 / 4 surface area too — see the document.
## Open questions, debt, drift
- **RB-08 still open.** macOS power assertion (`crates/.../power_assertion.rs` — surface lives in slice 2) is a non-functional stub awaiting the `objc2` rewrite plus runtime verification on Apple silicon. Per `HANDOVER.md`, gates v0.1 tagging. Tracked in [`docs/issues/power-assertion-macos-objc2.md`](../../issues/power-assertion-macos-objc2.md).
- **Schema head drift in human-facing docs.** `HANDOVER.md` (2026/04/25) says v14; the migration registry on disk is v15 (commit 2026/05/09 added `idx_transcripts_profile_created`). Worth a single sweep of human-facing handovers when the next session opens.
- **Hotkey is Linux-only at runtime.** macOS and Windows fall back to Tauri's global-shortcut plugin (slice 2). The crate compiles cleanly on all three OSes (the stub module is a no-op), but feature parity across platforms is provided by two different mechanisms. A single user-visible inconsistency: per-device hotplug. The Tauri plugin doesn't have it.
- **Power probe is Linux-only.** macOS / Windows return `PowerState::Unknown`, which callers treat as `OnAc`. Native probes (`IOPSGetProvidingPowerSourceType`, `GetSystemPowerStatus`) are noted-deferred in [`core-power.md`](core-power.md).
- **GPU probe is a stub.** `magnotia_core::hardware::probe_gpu()` returns `None`. CPU probe is wired (sysinfo + CPUID), Vulkan loader is probed via `libloading`, but the actual GPU vendor / VRAM are never populated. Recommendation scoring still works because it inspects `Some(gpu).acceleration` and gracefully scores zero-bonus when `None`. See [`core-hardware-probe.md`](core-hardware-probe.md).
- **`migration_v15` test exists but no migration v15 reverse path.** Migrations are append-only; the registry's contract is forward-only and idempotent. Reverting requires a fresh DB or a `DROP INDEX` migration v16. The contract is documented in [`storage-schema-and-migrations.md`](storage-schema-and-migrations.md).
- **Default profile is enforced by SQL triggers, not by code.** `00000000-0000-0000-0000-000000000001` cannot be deleted or renamed, but if a future migration drops or alters the trigger names (`trg_protect_default_profile_delete`, `trg_protect_default_profile_rename`), the protection silently disappears. No regression test asserts the triggers still exist on the head schema; today the integration tests only assert the protection at DML time.
- **Code-signing not configured.** Both macOS (Apple Developer ID) and Windows (code-signing certificate) are commented out in `build.yml`. Users hit Gatekeeper / SmartScreen on first run. Documented in [`ci-pipeline.md`](ci-pipeline.md).
- **`run.sh` hard-codes a Fedora-style `LIBCLANG_PATH`.** The launcher exports `/usr/lib64/llvm21/lib64`, which is correct on Jake's Monolith but breaks on a Debian/Ubuntu dev box. Worth softening to a `LIBCLANG_PATH=${LIBCLANG_PATH:-/usr/lib64/llvm21/lib64}` form.
## See also
- [Slice 1 — Frontend](../01-frontend/README.md)
- [Slice 2 — Tauri runtime](../02-tauri-runtime/README.md)
- [Slice 3 — Audio + transcription](../03-audio-transcription/README.md)
- [Slice 4 — LLM, formatting, MCP](../04-llm-formatting-mcp/README.md)