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,125 @@
---
name: Cloud providers (stub crate)
type: architecture-map-page
slice: 04-llm-formatting-mcp
last_verified: 2026/05/09
---
# Cloud providers (stub crate)
> **Where you are:** [Architecture map](../README.md) → [LLM, Formatting, MCP](README.md) → Cloud providers
**Plain English summary.** `magnotia-cloud-providers` is reserved scaffolding for future bring-your-own-key cloud STT integrations. Today, only an in-memory API key store is wired. No HTTP transports, no OpenAI client, no Anthropic client, no STT calls. The crate exists so the workspace shape is right when those features land.
## At a glance
- Crate: `magnotia-cloud-providers`
- Paths:
- `crates/cloud-providers/Cargo.toml` — 9 lines
- `crates/cloud-providers/src/lib.rs` — 3 lines (re-exports)
- `crates/cloud-providers/src/keystore.rs` — 77 LOC (the only real code)
- LOC total: ~80
- Public surface:
- `pub fn store_api_key(provider: &str, key: &str)` (`crates/cloud-providers/src/keystore.rs:15`)
- `pub fn retrieve_api_key(provider: &str) -> Option<String>` (`crates/cloud-providers/src/keystore.rs:27`)
- Both re-exported at crate root via `pub use keystore::{retrieve_api_key, store_api_key}` (`crates/cloud-providers/src/lib.rs:3`).
- External deps that matter: only `magnotia-core` (declared, not currently used by the keystore — reserved for the future provider implementations). `std::env` for the env-var fallback.
- Tauri command that calls this (slice 2, best guess): no current call sites observed in `src-tauri/src`. The intended call sites are `commands::cloud::store_api_key_cmd` / `_retrieve` for any future provider configuration UI, but neither exists today.
## What's in here
### `lib.rs` (`crates/cloud-providers/src/lib.rs:1`)
Three lines:
```rust
pub mod keystore;
pub use keystore::{retrieve_api_key, store_api_key};
```
That is the entire public surface. Anything else is an implementation detail of the keystore.
### `keystore.rs` — process-local API key store
`store_api_key(provider, key)` (`crates/cloud-providers/src/keystore.rs:15`):
- Acquires the global `Mutex<HashMap<String, String>>` (`api_key_store` static, `:37`).
- Inserts under the key `provider_env_key(provider)` which formats as `MAGNOTIA_API_KEY_{PROVIDER_UPPERCASED}`.
- Returns nothing — last-write-wins.
`retrieve_api_key(provider)` (`crates/cloud-providers/src/keystore.rs:27`):
- Looks up the in-memory key first.
- Falls back to `std::env::var(env_key)` if not present in memory.
- Returns `Option<String>`.
The fallback is the why behind the `MAGNOTIA_API_KEY_<PROVIDER>` naming convention: an operator can inject a key via the environment without going through the in-memory store, which is useful for headless / CI runs.
### Documented TODO
`crates/cloud-providers/src/keystore.rs:13`:
> TODO: Replace with the `keyring` crate (or platform-native credential storage) so keys persist across sessions and are accessed safely.
In-memory keys vanish on process exit — the user has to re-enter every key after every restart. The `keyring` crate (Linux: Secret Service / KWallet, macOS: Keychain, Windows: Credential Manager) is the clear next step. Not yet picked up.
### Tests (`crates/cloud-providers/src/keystore.rs:46`)
- `stored_key_is_retrievable_without_env_mutation` (`:55`) — store then retrieve.
- `providers_do_not_overlap` (`:65`) — two providers stored independently.
A static atomic counter generates unique provider names per test so concurrent runs do not see each other's keys (`unique_provider`, `:51`).
### What is *not* here
The crate's name and Cargo description ("BYOK cloud STT provider stubs and API key storage for Magnotia") imply a much larger surface. None of this exists yet:
- **No HTTP client.** No `reqwest` dependency, no transport layer.
- **No OpenAI / Anthropic / Whisper API clients.** No request/response types, no streaming code.
- **No STT request type.** Nothing that converts a `Vec<f32>` of audio samples into a transcript via a remote provider.
- **No provider trait.** No `trait CloudProvider { async fn transcribe(...) }` shape.
- **No persistent key storage.** Documented as TODO.
- **No rate-limiting, retry, backoff.** Reasonable for a stub crate.
- **No usage logging.** Hard requirement for a feature that costs the user money — must come with the first real transport.
## Data flow
Today:
```
caller (currently no in-tree caller)
→ store_api_key(provider, key)
→ api_key_store().lock().insert("MAGNOTIA_API_KEY_{PROVIDER}", key)
→ retrieve_api_key(provider)
→ check in-memory map
→ fall back to std::env::var
→ return Option<String>
```
Intended (future):
```
Tauri command (commands::cloud::transcribe_cmd, hypothetical)
→ retrieve_api_key("openai") → Option<String>
→ reqwest POST to provider transcribe endpoint
→ parse provider response → magnotia_core::types::Segment list
→ return to caller, who feeds it into the formatting pipeline
```
The formatting pipeline does not need to change to consume cloud-transcribed segments — `Segment` is already the contract.
## Watch-outs
- **Empty crate is intentional.** Removing it would be premature; the workspace shape and the BYOK plan are both implied by its presence. But anyone doing slice analysis ("what does this crate do?") needs to know it does almost nothing today.
- **API keys vanish on restart.** The TODO is explicit. Until `keyring` integration lands, every cloud-provider feature using these helpers will need to re-prompt the user on every startup or break for headless deployments. Acceptable for a stub; not acceptable for a shipped feature.
- **Env-var fallback is `MAGNOTIA_API_KEY_<PROVIDER>`.** Provider names are uppercased in the env-key construction. A provider name with hyphens or underscores will produce a slightly weird-looking env var; not broken, but worth knowing. `provider = "open-ai"` becomes `MAGNOTIA_API_KEY_OPEN-AI`.
- **No threading concerns beyond the mutex.** `Mutex<HashMap>` is fine here because keys are written rarely and read on the path of a network call that dwarfs any contention. The previous note in the doc-comment about "undefined behaviour of mutating process environment variables from arbitrary threads" refers to a discarded design that used `std::env::set_var` — that approach is unsound under the modern Rust memory model. The current in-memory map is the safe replacement.
- **`magnotia-core` dependency is declared but not currently used in this file.** It is reserved for when the providers themselves arrive (they will likely consume `Segment` and tuning helpers).
- **Security of the in-memory map is process-lifetime only.** A core dump or a memory-inspection attack reveals the keys. The `keyring`-backed replacement will inherit OS-level protections; until then the threat model is "user trusts their own machine".
- **No call sites in the Tauri binary today.** Searching `src-tauri/src` for `cloud_providers`, `store_api_key`, or `retrieve_api_key` returns nothing. The crate is purely speculative scaffolding right now. Confirmed: the only references in the workspace are within the crate itself.
## See also
- [Slice README — cloud-providers debt entry](README.md)
- Slice 3 (forthcoming) — local STT engines (whisper.cpp, Parakeet) that the BYOK providers will eventually parallel