From 18a64f5c564243c5c5d46859c4a85a1f61827cea Mon Sep 17 00:00:00 2001 From: Jake Date: Thu, 14 May 2026 07:23:02 +0100 Subject: [PATCH] =?UTF-8?q?agent:=20lumotia=20=E2=80=94=20Phase=20A.3=20re?= =?UTF-8?q?move=20dead=20migration=5Fsentinel=20method=20+=20fix=20archite?= =?UTF-8?q?cture-map=20claim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase A.3 finding: AppPaths::migration_sentinel was added with intent during the rebrand-architecture phase but never wired to any caller. Exhaustive grep across crates/ src-tauri/ src/ docs/ surfaces: - 1 definition (paths.rs) - 1 architecture-map description that ASSERTS the method is in use - 0 production callers - 0 test references Both boot-time migrations (migrate_legacy_data_dir + migrate_tauri_app_data_dir_with_paths) are idempotent by construction: each re-probes the legacy path via Path::exists() on every boot and short-circuits on the steady state. A sentinel file would optimise the probe but is not required for correctness; one syscall per legacy candidate at startup is negligible. Per the atomiser principle of removing dead surface area rather than keeping stale promises: - Delete AppPaths::migration_sentinel entirely - Update docs/architecture-map/.../core-paths.md to describe the actual idempotency model (re-probing) rather than the sentinel pattern that was never implemented - Steer future migrations toward storage/src/migrations.rs schema_version (transactional, survives backup/restore) rather than reintroducing filesystem sentinels Verification: - cargo test -p lumotia-core paths::: 17/17 (no test relied on the method) - cargo clippy -p lumotia-core --all-targets -- -D warnings: clean Phase A.4 (stray-magnotia string scan): clean. Every magnotia reference in the tree is legitimate — migration source paths, documentation, or test fixtures. The rebrand cascade was thorough. --- crates/core/src/paths.rs | 4 ---- .../core-paths.md | 21 ++++++++++++++----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/crates/core/src/paths.rs b/crates/core/src/paths.rs index 0cdbb7f..9229361 100644 --- a/crates/core/src/paths.rs +++ b/crates/core/src/paths.rs @@ -49,10 +49,6 @@ impl AppPaths { pub fn llm_models_dir(&self) -> PathBuf { self.models_dir().join("llm") } - - pub fn migration_sentinel(&self, name: &str) -> PathBuf { - self.app_data_dir.join(format!(".{name}.sentinel")) - } } pub fn app_paths() -> AppPaths { diff --git a/docs/architecture-map/05-core-storage-hotkey-build/core-paths.md b/docs/architecture-map/05-core-storage-hotkey-build/core-paths.md index ef64649..b7407ad 100644 --- a/docs/architecture-map/05-core-storage-hotkey-build/core-paths.md +++ b/docs/architecture-map/05-core-storage-hotkey-build/core-paths.md @@ -36,7 +36,6 @@ impl AppPaths { pub fn models_dir(&self) -> PathBuf; // /models pub fn speech_model_dir(&self, id: &ModelId) -> PathBuf; // /models/ pub fn llm_models_dir(&self) -> PathBuf; // /models/llm - pub fn migration_sentinel(&self, name: &str) -> PathBuf; // /..sentinel } pub fn app_paths() -> AppPaths; @@ -56,9 +55,23 @@ The `resolve_app_data_dir` function picks the root by `cfg(target_os = ...)`: The Linux legacy-path branch keeps existing users on `~/.lumotia` (early dogfooding default) without forcing a migration when the canonical XDG location is preferred. -### Sentinel files — `crates/core/src/paths.rs:53` +### Migration idempotency — no sentinel files -`migration_sentinel(name) -> /..sentinel`. Used for one-shot data migrations outside the SQLite schema (for example, a one-off file-system reorganisation). The pattern is: write the sentinel after the migration runs successfully; check for the sentinel on next startup; skip the migration if the sentinel exists. +There is no sentinel-file pattern. The two boot-time migrations +(`migrate_legacy_data_dir` for the legacy magnotia data dir, and +`migrate_tauri_app_data_dir_with_paths` for the Tauri bundle-identifier +move) are both idempotent by construction: each cheaply re-probes for +the legacy path via `Path::exists()` on every boot and short-circuits +on the steady state. A sentinel file would optimise that probe but is +not required for correctness, and the cost is one syscall per legacy +candidate — negligible at startup. + +If a future migration needs cross-restart "this ran already" state +(e.g. a destructive one-shot reorganisation that mutates the legacy +path in place), reach for `crates/storage/src/migrations.rs` +(the SQLite schema_version table) rather than reintroducing a +filesystem sentinel — schema_version is transactional and survives +backup/restore, sentinel files don't. ## Data flow / contract @@ -77,8 +90,6 @@ The Linux legacy-path branch keeps existing users on `~/.lumotia` (early dogfood - **`std::env::var(...).unwrap_or_else(|_| "/tmp".to_string())` is the fallback for missing `HOME`.** Should never trigger in practice; defensive. - **`AppPaths::current()` reads env vars at every call.** Cheap, but repeated calls are wasteful. Slice 2 caches a `OnceLock` so the value is resolved once at startup. - **No Windows fallback for missing `LOCALAPPDATA`.** Falls through to `.` (current working directory). On a misconfigured Windows host this could write the database next to the binary. Not great; the impact is limited to first-run scenarios where the env is broken. -- **Sentinel files are hidden on Unix (`..sentinel`) but visible on Windows.** Acceptable; sentinels live alongside `lumotia.db` so the user sees both. - ## See also - [Storage file paths](storage-file-paths.md) — re-exports.