The 2026-05-12 engine-slop pass removed runtime std::env::set_var mutation from src-tauri/src/lib.rs and replaced it with warn_if_x11_env_unset_on_wayland. With no launcher owning the contract, Linux Wayland dogfood was about to regress. run.sh: - now owns Linux launcher env defaults via case "$(uname -s)" LIBCLANG_PATH=/usr/lib64/llvm21/lib64 (user-set wins) WEBKIT_DISABLE_DMABUF_RENDERER=1 (always on Linux; user-set wins) GDK_BACKEND=x11, WINIT_UNIX_BACKEND=x11 (Wayland only; user-set wins) - 60s Vite readiness timeout - detects early Vite exit (kill -0 + wait) instead of hanging forever - trap installed before wait so Ctrl-C cleans up - args forwarded: ./run.sh --release etc. - non-exec final Tauri launch preserved so cleanup trap fires package.json: - "dev:tauri": "./run.sh" — canonical discoverable dev command Docs: - README, dev-setup, architecture-map runtime + launcher pages updated with the new contract; canonical command is npm run dev:tauri (./run.sh as direct equivalent) - dev-launcher-and-scripts.md replaces the incorrect "kills process group" claim with honest "kills the spawned npm process" - dev-setup.md path /CORBEL-Projects/magnotia → /CORBEL-Projects/transcription-app - gpu-tuning/plan.md gets a superseded note rather than rewriting the original rationale - engine-slop-residuals.md gains Area F (packaged-binary launcher contract) with honest wrapper-vs-.desktop trade-off documented Verification: bash -n run.sh; shellcheck clean; cargo check -p magnotia green; npm pkg get 'scripts.dev:tauri' returns "./run.sh"; stale-ref sweep clean across living docs.
name, type, slice, last_verified
| name | type | slice | last_verified |
|---|---|---|---|
| Slice 5 — Core, Storage, Hotkey, Build | architecture-map-page | 05-core-storage-hotkey-build | 2026/05/09 |
Slice 5: Core, Storage, Hotkey, Build / CI
Where you are: Architecture map → 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.md2026/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)
- Constants module (sample rate, VAD, RAM thresholds, chunk timing)
- Error type and Result alias
- Hardware probe (sysinfo + CpuFeatures + Vulkan loader)
- Power-state probe (sysfs, 10s TTL cache, test override)
- Inference thread tuning (Workload, battery halve, GPU clamp)
- Model registry (Whisper + Parakeet entries with pinned SHA256)
- Recommendation scoring (rank_recommendations)
- Process-watch (meeting detection by process name)
- App paths (database, recordings, models, logs)
magnotia-storage:
- Storage overview (sqlx config, init flow, default features rationale)
- Schema and migrations (v1-v15 catalogue)
- FTS5 transcript search
- Transcripts CRUD
- Tasks and subtasks CRUD
- Profiles and profile_terms CRUD
- Settings, error log, feedback, implementation rules
- File storage paths (database, recordings, crashes, logs)
magnotia-hotkey:
Workspace and build glue:
- Workspace
Cargo.toml(members, release profile) - CI:
check.yml,build.yml,audit.yml - Dev launcher (
run.sh) and rootpackage.json - Vite, SvelteKit, jsconfig
- Static assets and
pcm-processor.jsworklet HANDOVER.mdand rootREADME.mdpointer
How this slice connects to others
magnotia-coreis 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, pluspaths::AppPaths. Seecore-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 viamagnotia_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::initat startup, registers the SQLite pool as Tauri-managed state, and every command insrc-tauri/src/commands/*.rsreaches intomagnotia_storagefor persistence andmagnotia_core::pathsfor filesystem locations. The hotkey command atsrc-tauri/src/commands/hotkey.rsis the sole consumer ofmagnotia_hotkey::EvdevHotkeyListener. - Slice 3 (audio + transcription) consumes
magnotia_core::types::{AudioSamples, Segment, Transcript}andmagnotia_core::constants::{WHISPER_SAMPLE_RATE, WHISPER_CHANNELS, PARAKEET_*, CHUNK_INTERVAL_MS}. The transcription engines also consumemagnotia_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), andmagnotia_core::constants::SMART_PARAGRAPH_GAP_SECS(formatting). The MCP server is the only consumer ofmagnotia_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— drove the v9-onwards transactional migration design. Seestorage-schema-and-migrations.md.docs/issues/c4-transcript-profile-fk.md— drove migration v9, the table rebuild that landedtranscripts.profile_idwith a real foreign key. Seestorage-schema-and-migrations.md.docs/issues/keystore-thread-safety.md— keystore lives incrates/cloud-providers/(slice 4) but the lesson generalises to every shared mutable state inmagnotia-core. Cross-referenced from the tuning page.docs/issues/hotkey-linux-device-filter.md— the RB-12 hard-codedKEY_A/KEY_Rfilter that the currentdevice_supports_comboreplaced. Seehotkey-linux-evdev.md.docs/issues/power-assertion-macos-objc2.md— RB-08, the only open MAJOR perHANDOVER.md. The implementation lives in slice 2 (src-tauri) but the API design lives nearmagnotia-coreconceptually. Linked from the slice debt section.docs/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— 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 theobjc2rewrite plus runtime verification on Apple silicon. PerHANDOVER.md, gates v0.1 tagging. Tracked indocs/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 addedidx_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 asOnAc. Native probes (IOPSGetProvidingPowerSourceType,GetSystemPowerStatus) are noted-deferred incore-power.md. - GPU probe is a stub.
magnotia_core::hardware::probe_gpu()returnsNone. CPU probe is wired (sysinfo + CPUID), Vulkan loader is probed vialibloading, but the actual GPU vendor / VRAM are never populated. Recommendation scoring still works because it inspectsSome(gpu).accelerationand gracefully scores zero-bonus whenNone. Seecore-hardware-probe.md. migration_v15test 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 aDROP INDEXmigration v16. The contract is documented instorage-schema-and-migrations.md.- Default profile is enforced by SQL triggers, not by code.
00000000-0000-0000-0000-000000000001cannot 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 inci-pipeline.md. run.shhard-codes a Fedora-styleLIBCLANG_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 aLIBCLANG_PATH=${LIBCLANG_PATH:-/usr/lib64/llvm21/lib64}form.