agent: lumotia-rebrand — fix QC blockers for phase 5
Phase 5 QC found two blockers + four advisories. All addressed: B1 (FATAL) — Migration error now aborts startup instead of silently continuing past it. Without this fix a transient EACCES / EXDEV / ENOSPC would log a warning, init_db would create a fresh empty lumotia dir, and the user would appear to lose their transcripts. B2 (FATAL) — Linux dot-home vs XDG mismatch. The old probe returned ~/.magnotia as legacy but the caller passed app_data_dir() as the new path — which could be $XDG_DATA_HOME/lumotia. fs::rename across filesystems would EXDEV-fail; even when it succeeded the user's storage convention silently changed. Refactored: legacy_and_target_paths() returns the (legacy, target) pair together. Dot-home legacy lands in ~/.lumotia; XDG-set legacy lands in $XDG_DATA_HOME/lumotia; XDG-default legacy lands in ~/.local/share/lumotia. macOS / Windows / non-tier-1 unchanged. migrate_legacy_data_dir() now takes no argument; src-tauri caller updated. A1 — Removed dead new_db.exists() check inside rename_db_file_if_present (unreachable: rename_db is called only AFTER the legacy dir was just renamed to the new path, so a stray lumotia.db there is impossible). A2 — Added 4 unit tests for migrate_legacy_setting_keys: lone-magnotia, both-present (orphan delete), no-magnotia, idempotent. A3 — migrate_legacy_setting_keys now returns (renamed, orphans_deleted). When both keys exist, the legacy magnotia row is DELETED in the same transaction (lumotia row is authoritative). A4 — Added dot-home convention regression test in paths::tests. cargo build --workspace passes. cargo test --workspace: 339 pass, 0 fail (up from 334 in the original Phase 5 commit; +5 new tests). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,8 +16,8 @@ use lumotia_core::paths::{migrate_legacy_data_dir, MigrationStatus};
|
||||
use lumotia_core::types::EngineName;
|
||||
use lumotia_llm::LlmEngine;
|
||||
use lumotia_storage::{
|
||||
app_data_dir, database_path, get_setting, init as init_db, migrate_legacy_setting_keys,
|
||||
prune_error_log, set_setting,
|
||||
database_path, get_setting, init as init_db, migrate_legacy_setting_keys, prune_error_log,
|
||||
set_setting,
|
||||
};
|
||||
|
||||
/// How long to retain `error_log` rows. Pruned once on startup.
|
||||
@@ -225,11 +225,13 @@ pub fn run() {
|
||||
builder
|
||||
.setup(|app| {
|
||||
// One-shot legacy data-dir migration: rename ~/.local/share/magnotia
|
||||
// (and macOS/Windows equivalents) to the lumotia path on first
|
||||
// launch after the rebrand. Safe to call every boot — idempotent.
|
||||
// (and macOS/Windows equivalents) to the convention-preserving
|
||||
// lumotia path on first launch after the rebrand. Idempotent —
|
||||
// safe to call on every boot. A migration error is fatal: silently
|
||||
// continuing past it would orphan the user's transcripts and
|
||||
// settings behind a fresh empty lumotia dir.
|
||||
let t_migrate = Instant::now();
|
||||
let new_data_dir = app_data_dir();
|
||||
match migrate_legacy_data_dir(&new_data_dir) {
|
||||
match migrate_legacy_data_dir() {
|
||||
Ok(MigrationStatus::Migrated { from, to, renamed_db }) => tracing::info!(
|
||||
target: "lumotia_startup",
|
||||
elapsed_ms = t_migrate.elapsed().as_millis(),
|
||||
@@ -240,11 +242,14 @@ pub fn run() {
|
||||
),
|
||||
Ok(MigrationStatus::TargetAlreadyExists { .. }) => {}
|
||||
Ok(MigrationStatus::NoLegacyFound) => {}
|
||||
Err(e) => tracing::warn!(
|
||||
target: "lumotia_startup",
|
||||
error = %e,
|
||||
"legacy data dir migration failed — continuing with new path"
|
||||
),
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
target: "lumotia_startup",
|
||||
error = %e,
|
||||
"legacy data dir migration failed — refusing to start (would orphan user data)"
|
||||
);
|
||||
return Err(Box::new(e) as Box<dyn std::error::Error>);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise database and startup settings in one runtime entry.
|
||||
@@ -258,15 +263,17 @@ pub fn run() {
|
||||
|
||||
// One-shot settings-key migration: rename any leftover
|
||||
// `magnotia_*` rows from the magnotia era to `lumotia_*`.
|
||||
// Idempotent; logs only when rows are actually renamed.
|
||||
// Deletes any magnotia_ rows that are orphans of an existing
|
||||
// lumotia_ row. Idempotent; logs only when rows actually move.
|
||||
let t_keys = Instant::now();
|
||||
match migrate_legacy_setting_keys(&db).await {
|
||||
Ok(0) => {}
|
||||
Ok(n) => tracing::info!(
|
||||
Ok((0, 0)) => {}
|
||||
Ok((renamed, orphans_deleted)) => tracing::info!(
|
||||
target: "lumotia_startup",
|
||||
rows_renamed = n,
|
||||
rows_renamed = renamed,
|
||||
orphans_deleted = orphans_deleted,
|
||||
elapsed_ms = t_keys.elapsed().as_millis(),
|
||||
"renamed legacy magnotia_* settings keys to lumotia_*"
|
||||
"migrated legacy magnotia_* settings keys to lumotia_*"
|
||||
),
|
||||
Err(e) => tracing::warn!(
|
||||
target: "lumotia_startup",
|
||||
|
||||
Reference in New Issue
Block a user