Prompt for local profile during quick onboarding#2389
Conversation
There was a problem hiding this comment.
Code Review
This pull request enables background tasks (heartbeat, routines, and hygiene) by default in the 'local' and 'local-sandbox' profiles. It also enhances the setup wizard's quick mode to prompt users for a deployment profile on their first run and ensures this selection is persisted to the bootstrap environment file. Feedback was provided to improve the maintainability of the profile application logic by encapsulating the backup and restoration of database settings into helper functions.
| let prior_database_backend = self.settings.database_backend.clone(); | ||
| let prior_database_url = self.settings.database_url.clone(); | ||
| let prior_database_pool_size = self.settings.database_pool_size; | ||
| let prior_libsql_path = self.settings.libsql_path.clone(); | ||
| let prior_libsql_url = self.settings.libsql_url.clone(); | ||
|
|
||
| crate::config::set_runtime_env("IRONCLAW_PROFILE", profile); | ||
| crate::config::profile::apply_profile(&mut self.settings) | ||
| .map_err(|e| SetupError::Config(e.to_string()))?; | ||
|
|
||
| if prior_database_backend.is_some() | ||
| || prior_database_url.is_some() | ||
| || prior_database_pool_size.is_some() | ||
| || prior_libsql_path.is_some() | ||
| || prior_libsql_url.is_some() | ||
| { | ||
| self.settings.database_backend = prior_database_backend; | ||
| self.settings.database_url = prior_database_url; | ||
| self.settings.database_pool_size = prior_database_pool_size; | ||
| self.settings.libsql_path = prior_libsql_path; | ||
| self.settings.libsql_url = prior_libsql_url; | ||
| } |
There was a problem hiding this comment.
To improve maintainability and adhere to the project's encapsulation standards, the logic for saving and restoring database settings should be moved into helper functions. This avoids exposing complex internal state transitions and provides a cleaner interface for the caller, consistent with the rule to encapsulate complex data structures and logic within helper functions.
| let prior_database_backend = self.settings.database_backend.clone(); | |
| let prior_database_url = self.settings.database_url.clone(); | |
| let prior_database_pool_size = self.settings.database_pool_size; | |
| let prior_libsql_path = self.settings.libsql_path.clone(); | |
| let prior_libsql_url = self.settings.libsql_url.clone(); | |
| crate::config::set_runtime_env("IRONCLAW_PROFILE", profile); | |
| crate::config::profile::apply_profile(&mut self.settings) | |
| .map_err(|e| SetupError::Config(e.to_string()))?; | |
| if prior_database_backend.is_some() | |
| || prior_database_url.is_some() | |
| || prior_database_pool_size.is_some() | |
| || prior_libsql_path.is_some() | |
| || prior_libsql_url.is_some() | |
| { | |
| self.settings.database_backend = prior_database_backend; | |
| self.settings.database_url = prior_database_url; | |
| self.settings.database_pool_size = prior_database_pool_size; | |
| self.settings.libsql_path = prior_libsql_path; | |
| self.settings.libsql_url = prior_libsql_url; | |
| } | |
| let prior_db_settings = self.settings.backup_database_config(); | |
| crate::config::set_runtime_env("IRONCLAW_PROFILE", profile); | |
| crate::config::profile::apply_profile(&mut self.settings) | |
| .map_err(|e| SetupError::Config(e.to_string()))?; | |
| self.settings.restore_database_config(prior_db_settings); |
References
- Encapsulate complex data structures and logic within a helper function, and expose a simpler interface or data structure tailored to the caller's needs.
Extract backup_database_config() and restore_database_config() on Settings to replace inline field-by-field save/restore in the setup wizard. Cleaner interface, consistent with project encapsulation standards. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
henrypark133
left a comment
There was a problem hiding this comment.
Review: Local profile prompt during quick onboarding (Risk: High)
Good UX improvement — first-run users get a clear choice between local and local-sandbox. The profile persistence to ~/.ironclaw/.env is correct (needed before DB connection). However, the profile TOML changes have broader implications.
Positives:
step_quick_local_profilecorrectly skips whenIRONCLAW_PROFILEis already set- Profile name validated against a fixed allowlist (local, local-sandbox)
bootstrap_env_vars()extraction fromwrite_bootstrap_env()is clean- README spec updated with the new flow
Concerning: Profile TOML changes silently enable background tasks for existing users [Architecture]
Files: profiles/local.toml, profiles/local-sandbox.toml
Both profiles flip heartbeat, routines, and hygiene from enabled = false to enabled = true. Existing users with IRONCLAW_PROFILE=local get background agent runs on next startup without opt-in. The profile comment previously said it "disables server-oriented features (gateway, heartbeat, routines, sandbox)" — this is a semantic contract change.
Suggestion: Consider documenting this as a breaking change in the PR description, or mentioning it in release notes so existing local-profile users are aware.
Concerning: DatabaseConfigBackup adds unnecessary complexity [Architecture]
File: src/settings.rs (new struct), src/setup/wizard.rs
The quick-mode flow already does step1_settings = self.settings.clone() then self.settings.merge_from(&step1_settings) after try_load_existing_settings(), which preserves wizard-chosen values over DB/profile values. The backup/restore pattern on top of this is redundant.
Suggestion: Consider reordering profile selection before auto_setup_database() instead — the existing merge_from pattern handles the rest.
Minor: Missing caller-level tests [Testing]
The two tests (test_bootstrap_env_vars_include_selected_deployment_profile, test_bootstrap_env_vars_do_not_persist_unselected_profile) cover the env var accessor but don't verify the DB-config preservation invariant through apply_quick_local_profile.
Convention notes:
- Profile comment headers in the TOMLs are updated to reflect the new defaults
try_load_existing_settingsreturningboolis a clean change
zmanian
left a comment
There was a problem hiding this comment.
Review: Prompt for local profile during quick onboarding
+202/-28, 6 files. Adds first-run profile selection (local vs local-sandbox) and enables heartbeat/routines/hygiene by default.
Items to address
-
try_load_existing_settingscfg-gated return value is fragile. Theloadedvariable is initializedfalseand only mutated inside#[cfg(feature = "postgres")]and#[cfg(feature = "libsql")]blocks. If neither feature is enabled, it always returnsfalse, triggering the profile prompt unconditionally. The variable shadowing makes this easy to break. Add a comment or make the logic more explicit. -
Behavior change for existing
localprofile users. Enabling heartbeat/routines/hygiene by default inlocal.tomlmeans existing users who upgrade suddenly get background tasks. Worth a changelog note or migration comment.
Minor
-
apply_quick_local_profilematch arm_ => QUICK_PROFILE_LOCAL_SANDBOXsilently maps any non-zero index to sandbox. Sinceselect_oneonly returns 0 or 1 here, it's safe, but1 => ... _ => unreachable!()is clearer about intent. -
bootstrap_env_varsextraction is clean — good refactor for testability.
Overall solid. Address or acknowledge the two items above before merging.
…ove backup/restore (#2389) - Remove `DatabaseConfigBackup` struct and backup/restore methods; reorder quick-mode flow so profile selection runs before `auto_setup_database()`, letting the existing clone→try_load→merge_from pattern preserve wizard-chosen DB settings naturally (henrypark133). - Add comment explaining the cfg-gated `loaded` variable shadowing in `try_load_existing_settings` (zmanian #1). - Change catch-all `_ =>` to explicit `1 => ... _ => unreachable!()` in profile match arm (zmanian #3). - Add caller-level test verifying profile application preserves DB config through the merge_from cycle (henrypark133 testing feedback). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addressed review feedback
Both reviewers:
|
henrypark133
left a comment
There was a problem hiding this comment.
Review: Local profile prompt during quick onboarding
No verified findings in the current diff. The flow now applies the selected local profile before quick database setup, persists the bootstrap profile choice explicitly, and re-merges fresh step-1 settings after loading prior DB state so stale partial-onboarding data no longer wins.
Summary
localandlocal-sandbox.envasIRONCLAW_PROFILElocal/local-sandboxusersBoth
profiles/local.tomlandprofiles/local-sandbox.tomlnow setheartbeat.enabled = true,routines.enabled = true, andhygiene.enabled = true. Existing users withIRONCLAW_PROFILE=local(or
local-sandbox) will get background tasks on next startup withoutexplicit opt-in. Previously the profile comment described these as
"disabled server-oriented features".
Migration: Users who want the old behavior can add
heartbeat.enabled = false,routines.enabled = false, andhygiene.enabled = falseto~/.ironclaw/config.toml.Tests
RUSTFLAGS=-Cdebuginfo=0 cargo test --no-default-features --features libsql local_profile --libRUSTFLAGS=-Cdebuginfo=0 cargo test --no-default-features --features libsql local_sandbox_enables_sandbox --libRUSTFLAGS=-Cdebuginfo=0 cargo test --no-default-features --features libsql test_bootstrap_env_vars_ --libRUSTFLAGS=-Cdebuginfo=0 cargo test --no-default-features --features libsql test_apply_quick_local_profile_ --libgit diff --check