feat: provider fallback + per-project config (0.7.0)#20
Merged
Conversation
- Move config.rs → config/mod.rs and add config/project.rs module - project_config_path_with_stop: walk up from CWD to home boundary, skipping directories outside the home tree (prevents cross-user leaks) - filter_inert_only: strips providers.*, logging.file, validator.enabled from project YAML before merging (security gate) - figment-layered Config::load: global → project (filtered) → env vars - Stop boundary derived from config_dir().parent() for consistency when HOME is overridden (e.g. in integration tests with temp home dirs) - 6 new unit tests in project::tests, 2 integration tests in schema_tests
blackaxgit
added a commit
that referenced
this pull request
May 2, 2026
PR #20 burned 6h on a hung instrumented coverage step; PR #21 hung 58 min on the same pattern. Three mitigations: 1. `timeout-minutes: 30` at job level + `timeout-minutes: 20` on the LCOV step. Hangs fail in 20-30 min instead of 6h. 2. `RUST_TEST_THREADS: 1` to serialize under instrumentation. Likely cause of the hang is wiremock + serial_test + tokio + llvm-cov parallelism deadlock. 3. `continue-on-error: true` so coverage flakes do not block PRs from merging while we investigate the root cause separately. Coverage stays informational. Quality gates (clippy, tests, build, audit) still block merges. --------- Co-authored-by: blackax <blackaxgit@users.noreply.github.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
CLX 0.7.0 — automatic primary→secondary LLM provider fallback with per-capability cooldown, plus per-project config overrides via figment-layered loading.
Reverses the 0.6.x design's explicit "no automatic fallback" decision based on user feedback that
default_decision: allow-style silent degradation under Azure outage is unsafe for a risk-scoring CLI.What's new
llm.chat.fallbackandllm.embeddings.fallbackconfig blocks. Fall back on transient errors (Connection, Timeout, RateLimit, 5xx, 408); fail-fast on terminal errors (Auth, DeploymentNotFound, ContentFilter). Fallback'smodeloverrides the caller's model name (providers don't share identifiers).<repo>/.clx/config.yaml, walk-up discovery from CWD to$HOME. Env-var escape:CLX_CONFIG_PROJECT=/pathorCLX_CONFIG_PROJECT=none.figment(defaults → global → project → env vars).providers.*,logging.file,validator.enabled) are silently dropped with aWARN.Architecture
LlmClient::Fallback(FallbackClient)enum variant.FallbackClient { primary: Box<LlmClient>, fallback: Box<LlmClient>, fallback_model, last_primary_failure }. ImplementsLlmBackenditself; single insertion point at the factory; zero production call sites changed.is_transientpromoted toLlmError::is_transientmethod (was a free function inazure.rs). Backends and the new fallback wrapper share one predicate.crates/clx-core/src/config/project.rsfor walk-up + allowlist filter.Config::loadswitched from rawserde_yml::from_strtofigment::FigmentwithYaml::file+Yaml::string(filtered project) +Env::prefixed("CLX_").Backwards compatibility
fallback:field anywhere → behavior bit-for-bit unchanged.serde_yml::from_str).ollama:block auto-translation (0.6.0) preserved.CLX_LLM_CHAT_*env-var shortcuts still work.Tests
llm/fallback.rs: fallback-on-503, no-fallback-on-401, cooldown-skips-primary.project_config_path+filter_inert_onlyinconfig/project.rs.config::schema_tests.Deferred to v0.7.x (not in this PR)
clx trust <repo>UX command for promoting non-inert project keys past the allowlist.fallback: [a, b, c]).Test plan
cargo build --release --workspace— cleancargo clippy --workspace --all-targets --all-features -- -D warnings— cleancargo test --workspace— 884+ passcargo fmt --all -- --check— cleancargo audit— exit 0CONTRIBUTING.mdafter mergeSpec & plan
specs/2026-04-30-provider-fallback-design.mdspecs/plans/2026-04-30-provider-fallback.md