agent: lumotia-rebrand — fix QC blockers for phase 5
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled

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:
2026-05-13 09:43:45 +01:00
parent 86f83b7a45
commit 9336286e3c
3 changed files with 247 additions and 95 deletions

View File

@@ -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",