Skip to content

Fix Windows startup recovery and SurrealDB boot path#213

Merged
jbcupps merged 1 commit intomainfrom
fix/windows-startup-recovery
Mar 20, 2026
Merged

Fix Windows startup recovery and SurrealDB boot path#213
jbcupps merged 1 commit intomainfrom
fix/windows-startup-recovery

Conversation

@jbcupps
Copy link
Copy Markdown
Owner

@jbcupps jbcupps commented Mar 20, 2026

Summary

  • reuse one embedded Surreal engine per store path and switch the file-backed local store path away from the failing Windows SurrealKv flow
  • remove active legacy DB path compatibility from startup, add startup-cycle logging, and log the real store path used during reopen/stats
  • recover disposable bootstrap profiles automatically and persist a Windows DPAPI fallback KEK so relaunches work even when keyring lookup fails

Verification

  • cargo test -p abigail-persistence file_backed_handles_can_share_one_embedded_store_across_scopes -- --nocapture
  • cargo test -p abigail-memory test_open_with_config_uses_configured_db_path -- --nocapture
  • cargo test -p abigail-app disposable_bootstrap_profile_detects_unborn_hive_only_state -- --nocapture
  • cargo test -p abigail-app disposable_bootstrap_profile_rejects_existing_vault_payloads -- --nocapture
  • cargo test -p abigail-core windows_kek_fallback_roundtrips -- --nocapture
  • cargo check -p abigail-app
  • rebuilt arget/debug/abigail-app.exe and verified two clean Windows launches: first launch auto-archived the disposable broken bootstrap profile and second launch recovered from �ault.kek.dpapi without reopening the clean-start dialog

Notes

  • the working tree still has an unrelated unstaged change in auri-app/Cargo.toml, which is intentionally excluded from this PR
  • startup still logs missing instruction files for �uiltin.queue_management and forge skill instructions; those warnings are non-blocking and are not part of this fix

@jbcupps jbcupps merged commit b1b4681 into main Mar 20, 2026
5 of 9 checks passed
@jbcupps jbcupps deleted the fix/windows-startup-recovery branch March 20, 2026 02:45
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0ffb51e8a6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +357 to +360
// Persist the embedded store with the local Mem engine. This keeps the
// runtime single-host and avoids SurrealKV's Windows write failures.
Surreal::new::<Mem>(endpoint_path)
.sync("never")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore a durable backend for file-backed persistence

PersistenceHandle::open() now routes every on-disk store through Surreal::new::<Mem>(endpoint_path). SurrealDB's Rust embedding docs describe Mem as the in-memory backend and use a file engine such as RocksDB/SurrealKV for persistence (https://surrealdb.com/docs/sdk/rust/embedding), so this cache only preserves state for the lifetime of the current process. After a full Abigail restart, the same memory.db path can come back empty, which would wipe persisted memories and the job queue even though the same path is reused.

Useful? React with 👍 / 👎.

Comment on lines 198 to 202
pub fn open_with_config(config: &AppConfig) -> Result<Self> {
if uses_legacy_layout(config) {
migrate_legacy_layout(config)
.map_err(|error| StoreError::Migration(error.to_string()))?;
}

let shared_path = shared_db_path(config);
if let Some(parent) = shared_path.parent() {
let db_path = config.db_path.clone();
if let Some(parent) = db_path.parent() {
std::fs::create_dir_all(parent)
.map_err(|error| StoreError::Migration(error.to_string()))?;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve legacy SQLite import on first open_with_config

This change removes the migration step before opening the new Surreal store. IdentityManager::migrate_legacy_identity() still copies legacy abigail_memory.db / jobs.db files into the agent directory (crates/abigail-identity/src/lib.rs:738-755), and a repo-wide search now shows no remaining caller of migrate_legacy_layout(). For users upgrading from that layout, open_with_config() will skip the import entirely, so existing conversations, jobs, calendar, and KB rows stay stranded in the copied SQLite files and appear to disappear on first launch.

Useful? React with 👍 / 👎.

Comment on lines +112 to +116
if let Some(kek) = load_windows_kek_fallback_optional(&data_root)? {
tracing::warn!(
"Stable KEK recovered from DPAPI fallback file because OS keyring lookup failed"
);
if let Err(error) = os_keyring_store_verified(&kek) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate the DPAPI fallback before repairing the keyring

In the fallback-recovery path, the KEK loaded from vault.kek.dpapi is written back into the OS keyring before verify_or_create_sentinel() proves that it can actually decrypt the existing vault. If that fallback file is corrupted or stale, startup not only fails, it also overwrites the previously-good keyring entry with the bad key, leaving later launches stuck on the same recovery error until the user manually repairs the keyring. The keyring repair needs to happen only after sentinel validation succeeds.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant