Skip to content

fix: default DB path adopts ~/mimir.db + warns on ambiguity; codesign macOS build-from-source#423

Merged
tcconnally merged 1 commit into
mainfrom
fix/db-path-and-macos-codesign
Jul 2, 2026
Merged

fix: default DB path adopts ~/mimir.db + warns on ambiguity; codesign macOS build-from-source#423
tcconnally merged 1 commit into
mainfrom
fix/db-path-and-macos-codesign

Conversation

@tcconnally

@tcconnally tcconnally commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Closes #421
Closes #422

Two independent install/packaging fixes in one PR.


#421 — Default DB path split-brain (~/mimir.db omitted)

Pre-fix behavior (proof, from src/main.rs default_db_path() on main):
The fallback chain was $MIMIR_DB_PATH~/.mimir/data/perseus-vault.db
existing ~/.mimir/data/mneme.db → existing ~/.mimir/data/mimir.dbcreate
~/.mimir/data/perseus-vault.db. ~/mimir.db was never in the chain, so a
single-user install with live data at ~/mimir.db running without --db
silently 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.db but only when
the 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):

  1. ~/.mimir/data/perseus-vault.db — canonical (current name)
  2. ~/.mimir/data/mneme.db — pre-rename
  3. ~/.mimir/data/mimir.db — pre-rename
  4. ~/mimir.dblegacy single-user location (added)

If none exist, create the canonical perseus-vault.db. ~/mimir.db is added
to 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.db AND a stale-empty ~/.mimir/data/mimir.db both present
the higher-precedence dir DB still wins on precedence; ~/mimir.db is surfaced
via the warning (half b), not auto-adopted
. Passing --db/$MIMIR_DB_PATH
explicitly 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_PATH
was 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_PATH always wins and
fires no warning
— behavior unchanged. default_db_path() itself is kept
side-effect-free (no warnings) because clap evaluates it eagerly as
default_value_t and apply_top_level_db compares against it.

Tests (5 new, all green):

  • resolve_default_db_picks_home_legacy_over_creating_fresh — only ~/mimir.db
    present → it is chosen instead of creating a fresh canonical DB (the core bug).
  • resolve_default_db_prefers_canonical_when_present — canonical wins; legacy
    reported 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 → highest
    precedence chosen, others named.
  • resolve_default_db_precedence_order_is_stable — full order asserted.

The resolver takes home + an existence closure, so tests run deterministically
without touching real $HOME/filesystem. README documents the canonical path
and 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 runs
    cargo build --release then installs the binary — exactly the path in the
    issue) now ad-hoc code-signs after install with
    codesign --force --sign -, guarded by uname -s = Darwin && uname -m = arm64, so it is a no-op on Intel/Linux/Windows. (scripts/install.sh, the
    release-binary downloader, already codesigned via mimir doctor/health/--version crash with SIGKILL on macOS until binary is ad-hoc signed #312 — untouched.)
  • README build-from-source note updated to codesign --force --sign -
    (the issue's workaround; --force is required to re-sign after each rebuild —
    the previous codesign --sign - fails on an already-signed binary) and to
    spell out the cargo build → cp → codesign workflow.

Both scripts pass bash -n syntax check.


Testing

Rebased onto current main (past #419/#420) as a clean single commit; no
semantic 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 fmt run; diff is intentional only.

🤖 Generated with Claude Code

…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>
@tcconnally tcconnally force-pushed the fix/db-path-and-macos-codesign branch from 4d5dcc7 to a297af1 Compare July 2, 2026 23:48
@tcconnally tcconnally merged commit 52a9a6a into main Jul 2, 2026
11 checks passed
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>
@tcconnally tcconnally deleted the fix/db-path-and-macos-codesign branch July 3, 2026 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant