Critical bug surfaced by the dogfood drill: every upgrading Magnotia user
would silently keep a fresh empty Lumotia install while their Magnotia
data sat orphaned next to it. Drill caught it on the first real run
under sandboxed HOME.
ROOT CAUSE
src-tauri/src/lib.rs::run() previously called the migrations from inside
the Tauri setup hook (post `tauri::Builder::default()`). But three
sequential actions BEFORE the setup hook had already created the
destination directories:
1. init_tracing() -> logs_dir() -> create_dir_all(app_data_dir/logs)
creates the lumotia/ root.
2. install_panic_hook() -> crashes_dir() -> create_dir_all() ditto.
3. Tauri's WebKitGTK runtime / plugin chain creates the bundle-id-keyed
consulting.corbel.lumotia/ dir eagerly when the WebContext spins up
(mediakeys, storage, WebKitCache subdirs appeared even without our
hook explicitly creating them).
By the time the setup-hook migrations fired, every legacy candidate
returned `TargetAlreadyExists` (paths.rs) or `BothExistLegacyPreserved`
(tauri_app_data_migration.rs) — both silent no-op codepaths. Legacy
data was left untouched, fresh Lumotia install gained no transcripts,
settings, or window state.
FIX
Migrate BEFORE any other code touches app_data_dir().
src-tauri/src/tauri_app_data_migration.rs:
- NEW_BUNDLE_ID const ("consulting.corbel.lumotia"). MUST agree with
tauri.conf.json#identifier; reviewer-enforced invariant.
- Renamed private `legacy_tauri_app_data_dir_for` -> public
`tauri_app_data_dir_for(identifier)`. Function is parameterised by
bundle id; the "legacy" name was misleading after this change.
- New `current_tauri_app_data_dir()` resolves the NEW bundle path
from platform env vars (same convention Tauri 2 uses), so the
pre-runtime migration can address its destination without
needing an AppHandle.
src-tauri/src/lib.rs:
- New `migrate_user_data_pre_runtime()` orchestrates the two
migrations + ambiguity guard. Uses `eprintln!` for surface events
(tracing not yet initialised at this stage; stderr lands in
journald / foreground terminal which is the right transport for
boot-phase output). FATAL errors call process::exit(1) — the
setup-hook version returned Err from the closure, equivalent
effect.
- run() now calls migrate_user_data_pre_runtime() as its first line,
BEFORE init_tracing(), install_panic_hook(), and the Tauri
builder.
- Setup-hook migration blocks deleted (~90 lines). Setup hook now
starts with a one-line comment pointing at the pre-runtime fn.
VERIFICATION
Re-ran the dogfood drill (scripts/dogfood-rebrand-drill.sh) — 8/8 probes
pass after the fix (was 4/8). Both stderr lines fire:
[lumotia-startup] migrated legacy magnotia data dir to lumotia:
.../magnotia -> .../lumotia (renamed_db=true, elapsed_ms=0)
[lumotia-startup] migrated Tauri app_data_dir from legacy bundle
identifier: .../uk.co.corbel.magnotia ->
.../consulting.corbel.lumotia (elapsed_ms=0)
On-disk post-state confirms: magnotia/ gone, lumotia/ has migrated db
+ recordings, uk.co.corbel.magnotia/ preserved as backup,
consulting.corbel.lumotia/localStorage/leveldb/ has migrated data.
- cargo fmt --check: clean
- cargo clippy --workspace --all-targets -- -D warnings: clean
- cargo test --workspace: 409/0 (no regression)