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,95 @@
|
||||
---
|
||||
name: Core power-state probe
|
||||
type: architecture-map-page
|
||||
slice: 05-core-storage-hotkey-build
|
||||
last_verified: 2026/05/09
|
||||
---
|
||||
|
||||
# Core power-state probe
|
||||
|
||||
> **Where you are:** [Architecture map](../README.md) → [Core, Storage, Hotkey, Build](README.md) → Core power-state probe
|
||||
|
||||
**Plain English summary.** Reports whether the machine is on AC or battery so callers can drop thread counts and skip GPU offload when energy matters more than throughput. Linux uses the documented `/sys/class/power_supply/` ABI. macOS and Windows return `Unknown` for now.
|
||||
|
||||
## At a glance
|
||||
|
||||
- File: `crates/core/src/power.rs` (328 LOC, 124 of which are tests).
|
||||
- External deps: standard library only (sysfs is plain text). Tests use `tempfile` (dev-dep).
|
||||
- Public surface: `PowerState`, `parse_power_state_from_dir`, `probe_power_state`. Plus `with_override` and `force_clear_cache` / `force_set_cache` as `pub(crate)` test helpers.
|
||||
- Consumers: [`core-tuning.md`](core-tuning.md). The runtime-capabilities banner in slice 2 may also surface the state.
|
||||
|
||||
## What's in here
|
||||
|
||||
### `PowerState` — `crates/core/src/power.rs:15`
|
||||
|
||||
```rust
|
||||
pub enum PowerState { OnAc, OnBattery, Unknown }
|
||||
```
|
||||
|
||||
`Unknown` is treated as `OnAc` by callers, preserving today's pre-clamp behaviour on platforms where the probe cannot fire.
|
||||
|
||||
### `parse_power_state_from_dir` — `crates/core/src/power.rs:40`
|
||||
|
||||
Pure function. Walks a `/sys/class/power_supply/`-style directory and applies these rules (matching the kernel's documented sysfs ABI):
|
||||
|
||||
1. Any entry with `type` in {`Mains`, `USB`} and `online == 1` → `OnAc`.
|
||||
2. Else any entry with `type == Battery` → `OnBattery`.
|
||||
3. Else → `Unknown`.
|
||||
|
||||
Top-level failures (missing dir, unreadable supply_dir) return `Unknown` without panicking. Per-entry failures are silently skipped.
|
||||
|
||||
### `probe_power_state()` — `crates/core/src/power.rs:115`
|
||||
|
||||
Resolution order, highest to lowest priority:
|
||||
|
||||
1. **In-process test override** (set via `with_override`). Test-only, never compiled into release builds.
|
||||
2. **`MAGNOTIA_POWER_STATE_OVERRIDE` env var** — `ac` | `battery` | `unknown`, case-insensitive. Used by the `thread_sweep.rs` integration tests.
|
||||
3. **Linux:** `parse_power_state_from_dir("/sys/class/power_supply")`.
|
||||
4. **macOS / Windows / other:** `Unknown`.
|
||||
|
||||
Both override paths bypass the cache so tests always see the value they set.
|
||||
|
||||
### TTL cache — `crates/core/src/power.rs:75-99, 124-136`
|
||||
|
||||
```rust
|
||||
const POWER_STATE_TTL: Duration = Duration::from_secs(10);
|
||||
```
|
||||
|
||||
Result is cached in a `Mutex<Option<CachedState>>` for 10 seconds. Caching prevents the inference thread-tuning helper from calling sysfs on every inference call (~10 syscalls per probe; called every chunk).
|
||||
|
||||
### Test helpers — `crates/core/src/power.rs:88, 93, 188`
|
||||
|
||||
- `force_clear_cache()` — `pub(crate)` — drops the cache slot.
|
||||
- `force_set_cache(state)` — `pub(crate)` — pre-populates the cache slot.
|
||||
- `with_override<R>(state, body) -> R` — `pub(crate)` — sets `TEST_OVERRIDE` for the duration of `body`. Holds a dedicated `TEST_LOCK` so override-using unit tests run serially even when cargo runs the test binary multi-threaded. `OverrideGuard` resets the override on drop, so a panicking test body cannot leak stale state.
|
||||
|
||||
All three helpers are `#[cfg(test)]`-gated and never compiled into release.
|
||||
|
||||
## Data flow / contract
|
||||
|
||||
- `probe_power_state` is the only public entry point production callers use.
|
||||
- The cache TTL means a power-source change takes up to 10 s to take effect. Acceptable for thread tuning; not adequate for a UI battery indicator.
|
||||
- Cache mutex poisoning is treated as a panic via `.expect("power cache mutex poisoned")`. A panicking holder of this mutex is already a bug; the loud failure mode is on purpose.
|
||||
|
||||
## Tests
|
||||
|
||||
11 tests in `crates/core/src/power.rs:202-327`:
|
||||
|
||||
- `power_state_variants_are_distinct` — sanity.
|
||||
- `parses_mains_online_as_on_ac` / `parses_battery_only_as_on_battery` / `parses_usb_pd_online_as_on_ac` — happy paths.
|
||||
- `parses_empty_dir_as_unknown` / `parses_missing_dir_as_unknown` / `parses_malformed_files_as_unknown_gracefully` — failure paths.
|
||||
- `override_drives_battery` / `override_drives_ac` / `override_drives_unknown` — in-process override.
|
||||
- `env_var_override_battery_via_set_var` — env-var override under the same `TEST_LOCK`.
|
||||
- `env_var_override_garbage_falls_through` — invalid env values fall through to the platform probe.
|
||||
- `ttl_cache_returns_cached_value_within_window` / `ttl_cache_clears_via_force_clear` — cache invariants.
|
||||
|
||||
## Watch-outs
|
||||
|
||||
- **macOS and Windows return `Unknown` always.** Native probes (`IOPSGetProvidingPowerSourceType` on macOS, `GetSystemPowerStatus` on Windows) are deferred. Consumers must treat `Unknown` as `OnAc` or behaviour will silently halve thread counts on every non-Linux machine.
|
||||
- **Per-entry sysfs read failures are silent.** The `read_trimmed().unwrap_or_default()` pattern means a permission-denied `online` file in a `Mains` entry would read as the empty string and the supply would be skipped. On a stuck-AC laptop where Mains was the unreadable entry, the function would return `OnBattery`. Documented in the function's doc comment at `power.rs:31`. Sysfs entries are world-readable in practice.
|
||||
- **`TEST_OVERRIDE` is `static Mutex<Option<PowerState>>`.** Process-global, test-only. Production builds do not compile it because of `#[cfg(test)]`.
|
||||
|
||||
## See also
|
||||
|
||||
- [Inference thread tuning](core-tuning.md) — the only production caller.
|
||||
- [Hardware probe](core-hardware-probe.md) — sibling.
|
||||
Reference in New Issue
Block a user