Phase 9 of the rebrand cascade. Sweep covers everything the Phase 8
frontend pass deliberately skipped: docs/, root markdown, scripts,
Cargo.toml descriptions, code comments that survived earlier
word-boundary sed, plus a handful of identifiers caught on the final
verify pass.
transcription-app changes:
- README.md, HANDOVER.md, KNOWN-ISSUES.md, run.sh — magnotia/Magnotia
-> lumotia/Lumotia.
- docs/ — sweep across all subdirs except docs/handovers/ (preserved
as immutable audit trail). Includes architecture-map references
to magnotia_core::*, magnotia_storage::*, etc. now pointing at
lumotia_*; dev-setup.md tracing output examples (lumotia_startup
target); brief/ + superpowers/ + issues/ + whisper-ecosystem/ +
audit/.
- Cargo.toml descriptions on 9 crates (core, audio, cloud-providers,
hotkey, llm, mcp, plus referenced others).
- crates/core/src/{error,hardware,recommendation,paths}.rs +
crates/audio/src/wav.rs + crates/llm/src/model_manager.rs +
crates/cloud-providers/src/keystore.rs + crates/mcp/src/lib.rs —
doc comments and a model-manager user-agent string.
- Caught on final pass: BroadcastChannel("magnotia_task_sync") -> ...
("lumotia_task_sync"); magnotia_locale i18n localStorage key
renamed + migration shim added; CSS keyframe names
magnotiaPulse / magnotiaBar / magnotiaFade renamed in the design-
system kit; magnotia_viewer_item / magnotia_viewer_mode handoff
keys renamed in HistoryPage + viewer/+page.svelte; src/assets/
wordmark.svg text.
- src-tauri/src/lib.rs comment cleanup ("magnotia era" was sed'd
to "lumotia era" earlier — restored).
Preserved (intentional):
- crates/core/src/paths.rs — keeps "magnotia" / "Magnotia" / ".magnotia"
legacy detection strings in legacy_and_target_paths() so the
migration shim can still find user data from the magnotia era.
- src/lib/stores/{page,focusTimer}.svelte.ts + src/lib/i18n/index.ts
— migration call sites reference the legacy magnotia keys
deliberately.
- docs/handovers/ — historical audit trail.
cargo build --workspace passes. npm run check: 0 errors / 0 warnings
(3958 files). cargo test --workspace: 339 pass / 0 fail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.6 KiB
name, type, slice, last_verified
| name | type | slice | last_verified |
|---|---|---|---|
| Storage settings, error log, feedback, implementation rules | architecture-map-page | 05-core-storage-hotkey-build | 2026/05/09 |
Storage settings, error log, feedback, implementation rules
Where you are: Architecture map → Core, Storage, Hotkey, Build → Settings and miscellaneous CRUD
Plain English summary. The smaller persistence surfaces. Settings is a key-value store. Error log captures structured errors. Feedback captures HITL thumbs and corrections so the LLM prompt builder can inject few-shot examples. Implementation rules persist the if-then automation rules from Phase 12.
Settings (key-value)
Functions — crates/storage/src/database.rs:754
pub async fn set_setting(pool: &SqlitePool, key: &str, value: &str) -> Result<()>;
pub async fn get_setting(pool: &SqlitePool, key: &str) -> Result<Option<String>>;
set_setting is INSERT OR REPLACE INTO settings, so it is idempotent. get_setting returns Ok(None) for a missing key (not Err).
Known keys
The settings table is keyed TEXT PRIMARY KEY, value TEXT NOT NULL. The conventions are:
lumotia_preferences— JSON blob. The frontend's full preferences object. Read at boot, written on every preference change. This is the bridge between the frontend's reactive preferences store (slice 1) and persistence (slice 5). See Slice 1 preferences store and Slice 2 preferences command.active_profile_id— string. The profile id the user is actively transcribing into.- Other keys are added ad-hoc per feature; no enumeration in code today.
Error log
Schema (migration v1)
CREATE TABLE error_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL DEFAULT (datetime('now')),
context TEXT NOT NULL,
error_code TEXT,
message TEXT NOT NULL,
metadata TEXT
);
CREATE INDEX idx_error_log_context ON error_log(context);
Public type — crates/storage/src/database.rs:1149
pub struct ErrorLogRow {
pub id: i64,
pub timestamp: String,
pub context: String,
pub error_code: Option<String>,
pub message: String,
pub metadata: Option<String>,
}
Functions
log_error(pool, context, error_code, message, metadata)—crates/storage/src/database.rs:1126. Append-only insert. Called from anywhere a meaningful structured error happens (audio capture failure, model download failure, transcription engine error, etc).prune_error_log(pool, keep_days) -> Result<u64>—crates/storage/src/database.rs:1166.DELETE FROM error_log WHERE timestamp < datetime('now', '-{keep_days} days'). Called once on app startup. 90 days is the default (slice 2). Returns the affected row count for logging.list_recent_errors(pool, limit)—crates/storage/src/database.rs:1178. Used by the diagnostic-report bundler in Settings → About to capture recent errors into the export.
Feedback (HITL)
Phase 2 of the feature-complete roadmap. Captures thumbs + corrections on AI-generated output so the prompt builder can inject recent examples as few-shot exemplars. Storage-only here; the prompt-conditioning logic lives in lumotia-llm (slice 4).
Schema (migration v10)
CREATE TABLE feedback (
id INTEGER PRIMARY KEY AUTOINCREMENT,
target_type TEXT NOT NULL,
target_id TEXT,
rating INTEGER NOT NULL, -- -1 thumbs down, 0 correction (neutral), +1 thumbs up
original_text TEXT,
corrected_text TEXT,
context_json TEXT,
profile_id TEXT NOT NULL DEFAULT '<DEFAULT_PROFILE_ID>',
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_feedback_target_type_rating ON feedback(target_type, rating);
CREATE INDEX idx_feedback_profile ON feedback(profile_id);
Public types — crates/storage/src/database.rs:1210, 1241, 1253
pub enum FeedbackTargetType { MicroStep, TaskExtraction, Cleanup }
impl FeedbackTargetType {
pub fn as_str(self) -> &'static str; // "microstep" | "task_extraction" | "cleanup"
pub fn parse(s: &str) -> Option<Self>; // (named to avoid the FromStr trait)
}
pub struct RecordFeedbackParams {
pub target_type: FeedbackTargetType,
pub target_id: Option<String>,
pub rating: i8, // -1, 0, or +1
pub original_text: Option<String>,
pub corrected_text: Option<String>,
pub context_json: Option<String>,
pub profile_id: Option<String>, // None falls back to DEFAULT_PROFILE_ID
}
pub struct FeedbackRow {
pub id: i64,
pub target_type: String,
pub target_id: Option<String>,
pub rating: i64,
pub original_text: Option<String>,
pub corrected_text: Option<String>,
pub context_json: Option<String>,
pub profile_id: String,
pub created_at: String,
}
Functions
record_feedback(pool, params) -> Result<i64>—crates/storage/src/database.rs:1265. Validatesrating ∈ -1..=1; fallsprofile_idback toDEFAULT_PROFILE_ID; returns the inserted row id.list_feedback_examples(pool, target_type, limit, min_rating, profile_id)—crates/storage/src/database.rs:1303. Returns the most recent rows scoped to the active profile, orderedcreated_at DESC, id DESC(recency wins ties).min_ratingfilters out thumbs-down examples when the caller wants positive reinforcement only; pass-1to include everything.
The "scoped to the active profile" behaviour exists so feedback does not cross profiles — corrections you made while transcribing for Work do not leak into Personal.
Implementation rules (Phase 12)
If-then automation rules. Each rule has a trigger kind and value (eg "phrase contains 'remind me'"), a JSON-encoded list of actions, and a last_fired_key so a rule does not double-fire on the same trigger.
Schema (migration v12)
CREATE TABLE implementation_rules (
id TEXT PRIMARY KEY,
enabled INTEGER NOT NULL,
trigger_kind TEXT NOT NULL,
trigger_value TEXT NOT NULL,
actions_json TEXT NOT NULL,
last_fired_key TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_implementation_rules_enabled_trigger
ON implementation_rules(enabled, trigger_kind);
Public type — crates/storage/src/database.rs:845
pub struct ImplementationRuleRow {
pub id: String,
pub enabled: bool,
pub trigger_kind: String,
pub trigger_value: String,
pub actions_json: String,
pub last_fired_key: Option<String>,
pub created_at: String,
pub updated_at: String,
}
Functions
insert_implementation_rule(pool, id, enabled, trigger_kind, trigger_value, actions_json, last_fired_key)—crates/storage/src/database.rs:636.list_implementation_rules(pool)—crates/storage/src/database.rs:667.get_implementation_rule(pool, id)—crates/storage/src/database.rs:680.set_implementation_rule_enabled(pool, id, enabled)—crates/storage/src/database.rs:697. Bumpsupdated_at.mark_implementation_rule_fired(pool, id, fired_key)—crates/storage/src/database.rs:720. Setslast_fired_key = ?so the dispatcher knows not to fire again on the same trigger.delete_implementation_rule(pool, id)—crates/storage/src/database.rs:743.
Watch-outs
lumotia_preferencesis a JSON blob in TEXT. Schema-on-read. A typo in the frontend store can land in the database and silently round-trip through future loads. A periodic schema-validation pass would catch it.error_loghas no severity column. Every error is created equal. Worth a future migration if the diagnostic-report bundler needs to highlight critical errors.feedback.profile_iddefaults toDEFAULT_PROFILE_IDat the column level. Combined with therecord_feedbackfallback, this means feedback can never end up profile-orphaned. Good.implementation_rules.actions_jsonis unschematised TEXT. The dispatcher logic owns the parsing. A future schema for actions would catch malformed JSON at the storage layer.set_settingis unbounded. A user with a hugelumotia_preferencesblob (which has happened in dogfooding) drags every read of that key. Today the preferences blob is small (KB-scale).
See also
- Schema and migrations — v1, v10, v12.
- Storage overview
- Slice 4 LLM prompt builder — caller of
list_feedback_examples. - Slice 2 preferences command — caller of
set_setting("lumotia_preferences", ...).