refactor(core): async ConfigLoader (config.rs cluster from #62)#63
Merged
Conversation
…fig, ...) Convert the ConfigLoader public API and its `enumerate_named_configs` helper to async tokio I/O so config resolution stops blocking the runtime. Bills: - `enumerate_named_configs` uses `tokio::fs::read_dir` + `next_entry()` loop - `load_from_path` reads via `tokio::fs::read_to_string` - `discover_config`, `load_with_extends`, `load_with_extends_and_metadata`, `load_with_full_resolution`, `load_with_overrides_and_substitution`, `load_with_substitution` become `async` - Private `resolve_extends_chain[_with_paths]` boxed for async recursion - All in-module `#[test]` callers switched to `#[tokio::test]` with `.await` - Doctests updated to `async fn example()` with `.await` Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Propagate the async ConfigLoader API through every consumer: CLI commands (all async): up, down, exec, build, run-user-commands, read-configuration, upgrade, outdated, config, set-up (load_optional_config). Shared `commands::shared::config_loader::load_config` is now async; its unit tests use `#[tokio::test]`. `outdated::resolve_config_path` and its sibling `load_config` become async. Integration test suites updated to `#[tokio::test]` where they invoke the converted ConfigLoader methods: - crates/core/tests: integration_config, integration_compose, integration_extends, integration_layered_merge, integration_logging, integration_mount, integration_override_secrets, integration_security, integration_user_mapping, integration_variable_substitution, integration_worktree - crates/deacon/tests: integration_compose_enhancements clippy::type_complexity is silenced on `resolve_extends_chain_with_paths` where the boxed-future return signature is unavoidable for async recursion. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3 tasks
pofallon
added a commit
that referenced
this pull request
May 27, 2026
…ing (#64) The recently landed audit follow-ups in closed #52 (PRs #58/#59/#60/#61/#62/#63) shipped one user-facing surface that needs README coverage — the workspace-trust gate for host-side lifecycle hooks (`--trust-workspace`, `--trust-workspace-persist`, `DEACON_NO_PROMPT=1`). Add a concise "Workspace Trust" section linking to SECURITY.md for the full threat model, and update the post-1.0 hardening sentence from "is tracked in #52" to past tense since the issue is now closed. Co-authored-by: Claude Opus 4.7 <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.
Summary
config.rsasync cluster that PR refactor(async): replace blocking IO in async paths with tokio (#52 task 3) #62 intentionally deferred to keep its diff reviewable.ConfigLoader::load_from_path,discover_config,load_with_extends,load_with_extends_and_metadata,load_with_full_resolution,load_with_overrides_and_substitution,load_with_substitution, and the privateenumerate_named_configsare nowasync. Recursive private helpers (resolve_extends_chain,resolve_extends_chain_with_paths) usePin<Box<dyn Future>>for async recursion..awaitpropagated through every command entrypoint that calls these —up,down,exec,build,run-user-commands,read-configuration,upgrade,outdated,config,set-up, plus the sharedcommands::shared::config_loader::load_confighelper.What changed (24 files, +502/-458)
Core (1 file):
crates/core/src/config.rs— 7 public methods + 3 private helpers converted toasync. All inline#[test]cases converted to#[tokio::test](19 cases).Deacon commands (10 files):
up/mod.rs,down.rs,exec.rs,build/mod.rs,run_user_commands.rs,read_configuration.rs,upgrade.rs,outdated.rs,config.rs,set_up.rs, plusshared/config_loader.rs(with its 5 unit tests converted to#[tokio::test]).Integration tests (12 files): ~13 cases across
integration_compose.rs,integration_config.rs,integration_extends.rs,integration_layered_merge.rs,integration_logging.rs,integration_mount.rs,integration_override_secrets.rs,integration_security.rs,integration_user_mapping.rs,integration_variable_substitution.rs,integration_worktree.rs, andintegration_compose_enhancements.rsconverted to#[tokio::test].Approach notes
async_*variants) — only consumer is this workspace, so no external API constraint.tokiowas already incrates/core/Cargo.tomlwith thefsfeature.#[allow(clippy::type_complexity)]added toresolve_extends_chain_with_pathsbecause the boxed-future return type with lifetime is irreducible for async recursion. No external API constraints.Test plan
cargo fmt --all -- --check— clean.cargo clippy --all-targets -- -D warnings— clean (full rebuild aftercargo clean).cargo test --doc -p deacon-core— 130 passed, 0 failed.make test-nextest-fast— 2089 passed, 30 skipped (per agent report).test_extends_chain_deep_under_limit_succeeds) verified under#[tokio::test(flavor = "current_thread")]— deadlocks on residual blocking IO, so a pass confirms the converted path is genuinely non-blocking. Flavor reverted afterward.🤖 Generated with Claude Code