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:
@@ -0,0 +1,90 @@
|
||||
---
|
||||
name: Core recommendation scoring
|
||||
type: architecture-map-page
|
||||
slice: 05-core-storage-hotkey-build
|
||||
last_verified: 2026/05/09
|
||||
---
|
||||
|
||||
# Core recommendation scoring
|
||||
|
||||
> **Where you are:** [Architecture map](../README.md) → [Core, Storage, Hotkey, Build](README.md) → Core recommendation scoring
|
||||
|
||||
**Plain English summary.** Given a `SystemProfile` (RAM, CPU, GPU, OS), score every model in the registry and rank them. The top entry is what Magnotia recommends. No boolean flags or scattered "is recommended" markers — position in the ranked list **is** the recommendation.
|
||||
|
||||
## At a glance
|
||||
|
||||
- File: `crates/core/src/recommendation.rs` (197 LOC, 113 of which are tests).
|
||||
- External deps: standard library only.
|
||||
- Public surface: `ScoredModel`, `score_model`, `rank_recommendations`.
|
||||
- Consumers: slice 2 model commands (frontend exposes the ranked list), the model picker UI (slice 1).
|
||||
|
||||
## What's in here
|
||||
|
||||
### `ScoredModel` — `crates/core/src/recommendation.rs:7`
|
||||
|
||||
```rust
|
||||
pub struct ScoredModel {
|
||||
pub entry: &'static ModelEntry,
|
||||
pub score: f64,
|
||||
pub reason: String,
|
||||
}
|
||||
```
|
||||
|
||||
Borrows the registry entry by `'static` reference (no allocation per call). `reason` is a user-facing explanatory string, prefilled with `model.description` if no override applied.
|
||||
|
||||
### `score_model(model, profile) -> Option<ScoredModel>` — `crates/core/src/recommendation.rs:15`
|
||||
|
||||
Pure function. Returns `None` when the model exceeds the system's RAM budget. Otherwise computes:
|
||||
|
||||
| Component | Score |
|
||||
|---|---|
|
||||
| `SpeedTier::Instant` | +40 |
|
||||
| `SpeedTier::Fast` | +30 |
|
||||
| `SpeedTier::Moderate` | +20 |
|
||||
| `SpeedTier::Slow` | +10 |
|
||||
| `AccuracyTier::Excellent` | +30 |
|
||||
| `AccuracyTier::Great` | +20 |
|
||||
| `AccuracyTier::Good` | +10 |
|
||||
| GPU acceleration available for this model's engine | +15 |
|
||||
| Headroom > 4 GB above `model.ram_required` | +10 |
|
||||
|
||||
GPU acceleration matrix (`recommendation.rs:36-49`):
|
||||
|
||||
- **Whisper**: any of `metal`, `vulkan`, `cuda`.
|
||||
- **Parakeet** / **Moonshine**: `cuda` or `vulkan`.
|
||||
|
||||
When GPU acceleration applies, `reasons.push("GPU accelerated on your system")`. Otherwise `reason = model.description.to_string()`.
|
||||
|
||||
### `rank_recommendations(profile) -> Vec<ScoredModel>` — `crates/core/src/recommendation.rs:71`
|
||||
|
||||
Filters out registry entries that exceed RAM, scores the rest, sorts descending by score, returns the vector. `partial_cmp` falls through to `Ordering::Equal` if NaN appears (defensive; the scoring path can't produce NaN today).
|
||||
|
||||
## Data flow / contract
|
||||
|
||||
- Pure function over `&SystemProfile` and the `&'static [ModelEntry]` from the registry.
|
||||
- Order is fully determined by score, with ties broken by registry order (which is what `sort_by` preserves).
|
||||
- The "Parakeet first when fits" expectation is asserted by a test at `recommendation.rs:184`: any machine with enough RAM for Parakeet sees Parakeet at index 0.
|
||||
|
||||
## Tests
|
||||
|
||||
6 tests in `crates/core/src/recommendation.rs:85-197`. Test fixtures `profile_with_ram` and `profile_with_gpu` build minimal `SystemProfile`s.
|
||||
|
||||
- `score_model_excludes_models_exceeding_available_ram` — RAM budget guard.
|
||||
- `score_model_includes_models_fitting_in_ram` — happy path.
|
||||
- `score_model_boosts_gpu_accelerated_models` — GPU bonus is real.
|
||||
- `rank_recommendations_places_highest_score_first` — sort invariant.
|
||||
- `rank_recommendations_returns_empty_for_very_low_ram` — degenerate case.
|
||||
- `parakeet_is_top_recommendation_when_hardware_supports_it` — asserts the implicit policy that English-speaking users on capable hardware see Parakeet first because it beats Whisper on English at lower latency.
|
||||
|
||||
## Watch-outs
|
||||
|
||||
- **No CPU-feature gate.** A pre-AVX2 CPU does not down-rank Whisper or Parakeet entries. The runtime-capabilities banner (slice 2) handles that user-facing warning. Worth considering whether a hard down-rank ought to live here too.
|
||||
- **Recommendation ignores download cost.** A user on a slow connection still sees `whisper-distil-large-v3` ranked first because it scores 30+30+10 = 70 against Parakeet's 40+20+10 = 70 (tie, registry order picks Parakeet). On a 4 GB-RAM machine, only `whisper-base-en` and `whisper-tiny-en` survive RAM filtering, so the ordering is well-behaved on low-end hardware.
|
||||
- **GPU scoring keys off the `Engine` variant, not the model size.** A 75 MB Whisper Tiny on a Vulkan GPU still gets the +15 bonus, which is technically correct (the inference does run on GPU) but is a marginal preference signal at that size.
|
||||
- **`reason` is `String`, not a structured enum.** UI that wants to badge the reason ("GPU accelerated", "Best for your RAM") needs to parse the string today. Worth pivoting to a discriminated union when more reasons land.
|
||||
|
||||
## See also
|
||||
|
||||
- [Hardware probe (`SystemProfile`)](core-hardware-probe.md)
|
||||
- [Model registry](core-model-registry.md)
|
||||
- [Constants module (RAM thresholds)](core-constants.md)
|
||||
Reference in New Issue
Block a user