fix: default DB path adopts ~/mimir.db + warns on ambiguity; codesign macOS build-from-source#423
Merged
Merged
Conversation
…build-from-source (closes #421, #422) #421 — default DB-path split-brain: - Refactor default DB resolution into a pure, unit-tested `resolve_default_db(home, exists)` returning the chosen path plus any other existing candidates. - Fallback chain now includes the legacy single-user location `~/mimir.db`, positioned among the existing-DB fallbacks so an EXISTING ~/mimir.db is adopted BEFORE a fresh ~/.mimir/data/perseus-vault.db is created. Precedence (first existing wins): perseus-vault.db > mneme.db > mimir.db(dir) > ~/mimir.db. - When >1 candidate exists and no --db/$MIMIR_DB_PATH is set, emit a stderr warning naming the chosen file and the ignored ones. Explicit --db/env is unchanged and suppresses the warning (gated in check_legacy_db). - 5 new tests cover: adopt ~/mimir.db over creating fresh; canonical precedence; fresh-install fallback; multiple-candidate reporting; full precedence order. - README documents the canonical path and full resolution order. #422 — macOS Apple silicon Killed:9: - bootstrap.sh (build-from-source installer) now ad-hoc code-signs the built binary (`codesign --force --sign -`) guarded by a uname Darwin/arm64 check. - README build-from-source note updated to use `--force` and document the post-rebuild signing step. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4d5dcc7 to
a297af1
Compare
tcconnally
added a commit
that referenced
this pull request
Jul 3, 2026
…rap.sh binary name (#425) Follow-up to #421/#423. Purely path-based default-DB precedence let a stale, empty higher-precedence DB shadow a live lower-precedence one (the exact reported case: empty ~/.mimir/data/mimir.db chosen over a live ~/mimir.db). - resolve_default_db now takes a keyless entity-count probe. Only when the highest-precedence *existing* candidate is known-empty (Some(0)) does it prefer the highest-precedence known-non-empty candidate. Unknown candidates (locked/corrupt/not-yet-a-vault -> None) are never demoted-on nor promoted-to, so it degrades to the current path order + split-brain warning. - probe_entity_count opens candidates read-only (no schema init / WAL churn, unlike Database::open) and counts entities; a row COUNT needs no key since encryption is per-field. - Resolution + warnings centralized in normalize_default_db(), run once in main() before the command match, so serve and all maintenance subcommands open the same resolved DB (replaces the scattered check_legacy_db calls). default_db_path() (clap's eager default) stays path-only and side-effect-free. - 5 new unit tests cover the emptiness cases; the 5 existing #421 precedence tests updated to the new signature (unchanged assertions via an all-unknown probe). Full bin suite: 338 passed. - scripts/bootstrap.sh looked for target/release/mimir, which the perseus-vault crate no longer emits (build succeeded then failed to find the binary). Now builds/installs perseus-vault + mimir/mneme compat symlinks, defaults to perseus-vault.db, and uses the serve subcommand — matching install.sh. Co-authored-by: tcconnally <hermes@perseus.observer> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #421
Closes #422
Two independent install/packaging fixes in one PR.
#421 — Default DB path split-brain (
~/mimir.dbomitted)Pre-fix behavior (proof, from
src/main.rsdefault_db_path()onmain):The fallback chain was
$MIMIR_DB_PATH→~/.mimir/data/perseus-vault.db→existing
~/.mimir/data/mneme.db→ existing~/.mimir/data/mimir.db→ create~/.mimir/data/perseus-vault.db.~/mimir.dbwas never in the chain, so asingle-user install with live data at
~/mimir.dbrunning without--dbsilently created/read an empty default while the real DB sat untouched — exactly
the reported split-brain (
~/mimir.db= 26 entities live;~/.mimir/data/mimir.db= 0 entities, created by a default-path invocation).
Note: an existing
check_legacy_db()warned about~/mimir.dbbut only whenthe target didn't exist, and it never selected it — so the empty DB was still
created and used.
Fix — resolution order decision:
Resolution is refactored into a pure, testable function
resolve_default_db(home, exists) -> DbResolution { chosen, other_candidates }.Precedence (first existing wins):
~/.mimir/data/perseus-vault.db— canonical (current name)~/.mimir/data/mneme.db— pre-rename~/.mimir/data/mimir.db— pre-rename~/mimir.db— legacy single-user location (added)If none exist, create the canonical
perseus-vault.db.~/mimir.dbis addedto the fallback chain (position 4), before the create-new default — so it is
adopted when it is the only existing DB, instead of creating a fresh empty
DB. This satisfies half (a) of the issue.
Scope note (precedence-only, not emptiness-aware): this fix orders by
precedence, not by row count. In the issue's actual reported scenario — a
live
~/mimir.dbAND a stale-empty~/.mimir/data/mimir.dbboth present —the higher-precedence dir DB still wins on precedence;
~/mimir.dbis surfacedvia the warning (half b), not auto-adopted. Passing
--db/$MIMIR_DB_PATHexplicitly is the deterministic remedy. Making precedence emptiness-aware (prefer
a non-empty legacy DB over a stale-empty dir DB) is a filed follow-up, kept out
of scope here.
Half (b): when more than one candidate exists and no
--db/$MIMIR_DB_PATHwas given, a stderr warning names the chosen file and the ignored candidate(s).
The warning is emitted from
check_legacy_db()(which runs only at real startup)and is gated to the implicit-default case (
!env_set && db_path == default_db_path()), so explicit--db/$MIMIR_DB_PATHalways wins andfires no warning — behavior unchanged.
default_db_path()itself is keptside-effect-free (no warnings) because clap evaluates it eagerly as
default_value_tandapply_top_level_dbcompares against it.Tests (5 new, all green):
resolve_default_db_picks_home_legacy_over_creating_fresh— only~/mimir.dbpresent → it is chosen instead of creating a fresh canonical DB (the core bug).
resolve_default_db_prefers_canonical_when_present— canonical wins; legacyreported as an other-candidate.
resolve_default_db_falls_back_to_canonical_when_none_exist— fresh install,no warning.
resolve_default_db_reports_multiple_candidates— multiple present → highestprecedence chosen, others named.
resolve_default_db_precedence_order_is_stable— full order asserted.The resolver takes
home+ an existence closure, so tests run deterministicallywithout touching real
$HOME/filesystem. README documents the canonical pathand full resolution order.
#422 — macOS Apple silicon
Killed: 9(no ad-hoc codesign)Docs + script, no Rust behavior change (no Rust test).
scripts/bootstrap.sh(the build-from-source installer: it runscargo build --releasethen installs the binary — exactly the path in theissue) now ad-hoc code-signs after install with
codesign --force --sign -, guarded byuname -s = Darwin && uname -m = arm64, so it is a no-op on Intel/Linux/Windows. (scripts/install.sh, therelease-binary downloader, already codesigned via mimir doctor/health/--version crash with SIGKILL on macOS until binary is ad-hoc signed #312 — untouched.)
codesign --force --sign -(the issue's workaround;
--forceis required to re-sign after each rebuild —the previous
codesign --sign -fails on an already-signed binary) and tospell out the
cargo build → cp → codesignworkflow.Both scripts pass
bash -nsyntax check.Testing
Rebased onto current
main(past #419/#420) as a clean single commit; nosemantic conflict, CHANGELOG merged with all Unreleased entries kept.
cargo +stable-x86_64-pc-windows-msvc test: 333 passed, 0 failed, 11 ignored(ignored = explicit load tests). No
cargo fmtrun; diff is intentional only.🤖 Generated with Claude Code