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,90 @@
---
name: Implementation intentions
type: architecture-map-page
slice: 02-tauri-runtime
last_verified: 2026/05/09
---
# `commands::intentions`
> **Where you are:** [Architecture map](../../README.md) → [Tauri runtime](../README.md) → [Commands](README.md) → Implementation intentions
**Plain English summary.** Phase 7. Tiny "if-then" automation rules: "at 09:00 each day, surface my Inbox", "when the morning triage finishes, start a 5-minute timer", "when task X is completed, speak 'Nice'". Frontend owns scheduling and execution because v1 triggers are app-local events plus a local clock check; Rust owns durable storage, validation, and a main-window-only firewall.
## At a glance
- Path: `src-tauri/src/commands/intentions.rs`.
- LOC: 308.
- Tauri commands exposed (5 total), all main-window only:
- `list_implementation_rules(window, state) -> Result<Vec<ImplementationRuleDto>, String>`.
- `create_implementation_rule(window, state, request: CreateImplementationRuleRequest) -> Result<ImplementationRuleDto, String>`.
- `set_implementation_rule_enabled(window, state, id, enabled) -> Result<ImplementationRuleDto, String>`.
- `mark_implementation_rule_fired(window, state, id, fired_key) -> Result<ImplementationRuleDto, String>`.
- `delete_implementation_rule(window, state, id) -> Result<(), String>`.
- Events emitted: none.
- Depends on: `magnotia_storage::{insert_implementation_rule, list_implementation_rules, set_implementation_rule_enabled, mark_implementation_rule_fired, delete_implementation_rule, get_task_by_id, ImplementationRuleRow}`, `uuid::Uuid`, `serde_json`. Plus `commands::security::ensure_main_window`.
- Called from frontend at: Settings → Implementation intentions (CRUD); the rule-runner module (`mark_implementation_rule_fired` after firing).
## What's in here
### Trigger and action enums (`src-tauri/src/commands/intentions.rs:21`)
- `RuleTriggerKind`: `TimeOfDay`, `TaskCompleted`, `MorningTriageFinished`. Serialises as `"time_of_day"`, `"task_completed"`, `"morning_triage_finished"`.
- `SurfaceTarget`: `Inbox`, `Today`, `Tasks`, `Task`. The `Task` variant requires a `taskId`.
- `RuleAction` (tagged enum, `kind` discriminator): `Surface { target, taskId, label }`, `StartTimer { seconds, taskId, label }`, `SpeakLine { text }`.
### `CreateImplementationRuleRequest` (`:72`)
`triggerKind`, `triggerValue: String`, `actions: Vec<RuleAction>`, `enabled` (default true), `lastFiredKey: Option<String>`.
### `ImplementationRuleDto` (`:88`) and `TryFrom` (`:100`)
The DTO unpacks the storage row's `actions_json` back into typed `Vec<RuleAction>`. Returns Err on unknown `trigger_kind` strings or invalid JSON — surfaces drift instead of silently swallowing.
### Validators
- `validate_hhmm(value)` (`:125`) — strict HH:MM, two digits each, hours 0..=23, minutes 0..=59. Tested.
- `validate_actions(state, actions)` (`:144`):
- At least one action.
- `Surface { target: Task }` requires a `taskId` and the task must exist (via `get_task_by_id`).
- `StartTimer` rejects anything other than 300 seconds (v1 fixed at 5 minutes).
- `SpeakLine` requires non-empty text and ≤ 240 chars.
- `validate_request(state, request)` (`:192`) — checks the trigger value matches the trigger kind (`TimeOfDay` requires HH:MM, the others reject any non-empty trigger_value).
### Commands (`:207` onwards)
All five commands `ensure_main_window`. CRUD is otherwise straight wrapping. `create_implementation_rule` generates a UUIDv4, serialises actions to JSON, normalises `trigger_value` (empty for non-time triggers), inserts, and returns the freshly-fetched DTO. `mark_implementation_rule_fired` requires a non-empty `fired_key` (the frontend uses ISO date strings to dedupe daily fires).
### Tests (`:296`)
`hhmm_validation_accepts_and_rejects_expected_shapes` covers a handful of valid and invalid clock strings.
## Data flow
```
Settings -> create_implementation_rule(req)
-> ensure_main_window
-> validate_request (HH:MM if applicable, action shape, task existence for surface-task)
-> uuid::v4 for id
-> serde_json serialise actions
-> magnotia_storage::insert_implementation_rule
-> list/return DTO
frontend rule-runner cron -> evaluates triggers in JS
-> when a rule fires: invoke('mark_implementation_rule_fired', id, "2026-05-09")
-> stamp the dedupe key in DB
```
## Watch-outs
- **Action timer is hard-capped to 300 seconds.** The frontend has to surface this constraint. Future versions will need to widen the validator to accept arbitrary durations.
- **Rule execution lives entirely in the frontend.** If the user closes Magnotia at 08:55 with a 09:00 rule, the rule does not fire. There is no daemon. This is documented in the module header.
- **Validation is sync against the DB.** `validate_actions` calls `get_task_by_id` for every surface-task action. Multiple actions in one rule = multiple round-trips. Acceptable today; consider batching if a rule grows huge.
- **`mark_implementation_rule_fired` requires a non-empty `fired_key`.** The frontend should always pass an ISO date for daily rules and a per-event key for task-completed rules. Empty key = command rejection.
- **No `PowerAssertion`.** None of these actions run inference. No need.
## See also
- [Tasks](tasks.md) — `Surface { target: Task }` and `StartTimer { taskId }` reference task ids.
- [TTS](tts.md) — `SpeakLine` actions are dispatched by the frontend through `tts_speak`.
- [Capabilities and ACL](../capabilities-and-acl.md) — main-window-only is the firewall here.