7b3fcaf466
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 19s
CI / helm (pull_request) Successful in 20s
CI / lint (pull_request) Successful in 3m19s
CI / quality (pull_request) Successful in 3m49s
CI / typecheck (pull_request) Successful in 3m57s
CI / integration_tests (pull_request) Successful in 3m57s
CI / security (pull_request) Successful in 4m6s
CI / unit_tests (pull_request) Successful in 7m19s
CI / docker (pull_request) Successful in 1m18s
CI / coverage (pull_request) Successful in 11m53s
CI / e2e_tests (pull_request) Successful in 21m25s
CI / status-check (pull_request) Successful in 1s
CI / build (push) Successful in 18s
CI / helm (push) Successful in 22s
CI / lint (push) Successful in 3m16s
CI / quality (push) Successful in 3m41s
CI / integration_tests (push) Successful in 3m48s
CI / typecheck (push) Successful in 3m54s
CI / unit_tests (push) Successful in 3m54s
CI / security (push) Successful in 4m4s
CI / docker (push) Successful in 1m19s
CI / benchmark-regression (push) Has been skipped
CI / e2e_tests (push) Successful in 14m58s
CI / coverage (push) Successful in 11m55s
CI / status-check (push) Successful in 1s
CI / benchmark-publish (push) Successful in 28m23s
CI / benchmark-regression (pull_request) Successful in 54m47s
Implement three-scope configuration resolution (local > project > global) with deep merge. Add ConfigScope enum, project-root discovery, and config.local.toml file support. Changes: - Add LOCAL to ConfigLevel enum and new ConfigScope enum (GLOBAL, PROJECT, LOCAL) - Implement discover_project_root() walking up from CWD for cleveragents.toml/.cleveragents - Implement config.local.toml file loading in ConfigService - Implement three-scope deep merge via _deep_merge() helper - Add read_project_config(), read_local_config(), read_merged_config() methods - Add write_scoped_config() for writing to any scope file - Update set_value() to accept optional scope parameter - Update resolve() with six-level precedence chain (CLI > env > local > project > global > default) - Update CLI config set with --scope flag (global/project/local) - Add config.local.toml to .gitignore and DEFAULT_IGNORE_PATTERNS - Add Behave BDD scenarios for three-scope resolution, deep merge, and project-root discovery ISSUES CLOSED: #937
120 lines
6.6 KiB
Gherkin
120 lines
6.6 KiB
Gherkin
Feature: Three-scope configuration resolution
|
|
As a developer working on a CleverAgents project
|
|
I want configuration to resolve across global, project, and local scopes
|
|
So that I can have developer-specific overrides without affecting shared config
|
|
|
|
Background:
|
|
Given a clean three-scope config environment
|
|
|
|
# ── Scope precedence ──────────────────────────────────────────────────
|
|
|
|
Scenario: Local scope overrides project scope
|
|
Given a project config value "core.automation-profile" = "supervised"
|
|
And a local config value "core.automation-profile" = "manual"
|
|
When I resolve three-scope key "core.automation-profile"
|
|
Then the three-scope resolved value should be "manual"
|
|
And the three-scope resolved source should be "local"
|
|
|
|
Scenario: Project scope overrides global scope
|
|
Given a global config value for three-scope "core.automation-profile" = "full-auto"
|
|
And a project config value "core.automation-profile" = "supervised"
|
|
When I resolve three-scope key "core.automation-profile"
|
|
Then the three-scope resolved value should be "supervised"
|
|
And the three-scope resolved source should be "project"
|
|
|
|
Scenario: Local scope overrides both project and global scopes
|
|
Given a global config value for three-scope "core.automation-profile" = "full-auto"
|
|
And a project config value "core.automation-profile" = "supervised"
|
|
And a local config value "core.automation-profile" = "manual"
|
|
When I resolve three-scope key "core.automation-profile"
|
|
Then the three-scope resolved value should be "manual"
|
|
And the three-scope resolved source should be "local"
|
|
|
|
Scenario: Global scope used when no project or local override exists
|
|
Given a global config value for three-scope "core.automation-profile" = "supervised"
|
|
When I resolve three-scope key "core.automation-profile"
|
|
Then the three-scope resolved value should be "supervised"
|
|
And the three-scope resolved source should be "global"
|
|
|
|
Scenario: Default used when no scope provides a value
|
|
When I resolve three-scope key "core.automation-profile"
|
|
Then the three-scope resolved source should be "default"
|
|
|
|
# ── Deep merge ────────────────────────────────────────────────────────
|
|
|
|
Scenario: Deep merge combines nested keys from all scopes
|
|
Given a global config with nested data "section_a.key1" = "global_val1"
|
|
And a project config with nested data "section_a.key2" = "project_val2"
|
|
And a local config with nested data "section_a.key3" = "local_val3"
|
|
When I read the three-scope merged config
|
|
Then the merged config "section_a" should contain key "key1" with value "global_val1"
|
|
And the merged config "section_a" should contain key "key2" with value "project_val2"
|
|
And the merged config "section_a" should contain key "key3" with value "local_val3"
|
|
|
|
Scenario: Deep merge local overrides project on conflict
|
|
Given a project config with nested data "section_a.key1" = "project_val"
|
|
And a local config with nested data "section_a.key1" = "local_val"
|
|
When I read the three-scope merged config
|
|
Then the merged config "section_a" should contain key "key1" with value "local_val"
|
|
|
|
# ── Project root discovery ────────────────────────────────────────────
|
|
|
|
Scenario: Project root discovered via cleveragents.toml marker
|
|
Given a directory tree with "cleveragents.toml" marker at the root
|
|
When I discover the project root from a subdirectory
|
|
Then the discovered project root should match the marker directory
|
|
|
|
Scenario: Project root discovered via .cleveragents directory marker
|
|
Given a directory tree with ".cleveragents" directory marker at the root
|
|
When I discover the project root from a subdirectory
|
|
Then the discovered project root should match the marker directory
|
|
|
|
Scenario: No project root returns None when no markers found
|
|
Given a directory tree with no project markers
|
|
When I discover the project root
|
|
Then the discovered project root should be None
|
|
|
|
# ── config.local.toml file loading ────────────────────────────────────
|
|
|
|
Scenario: Local config file is loaded when present
|
|
Given a local config file with "plan.concurrency" = "16"
|
|
When I resolve three-scope key "plan.concurrency"
|
|
Then the three-scope resolved value should be "16"
|
|
And the three-scope resolved source should be "local"
|
|
|
|
Scenario: Missing local config file is handled gracefully
|
|
When I read the local config
|
|
Then the local config should be an empty dict
|
|
|
|
# ── Scoped write ──────────────────────────────────────────────────────
|
|
|
|
Scenario: Set value with local scope writes to config.local.toml
|
|
When I set three-scope value "core.automation-profile" to "manual" with scope "local"
|
|
Then the local config file should contain "core.automation-profile" = "manual"
|
|
|
|
Scenario: Set value with project scope writes to project config.toml
|
|
When I set three-scope value "core.automation-profile" to "supervised" with scope "project"
|
|
Then the project config file should contain "core.automation-profile" = "supervised"
|
|
|
|
Scenario: Set value with global scope writes to global config.toml
|
|
When I set three-scope value "core.automation-profile" to "full-auto" with scope "global"
|
|
Then the global config file should contain "core.automation-profile" = "full-auto"
|
|
|
|
# ── ConfigScope enum ──────────────────────────────────────────────────
|
|
|
|
Scenario: ConfigScope enum has all three values
|
|
Then ConfigScope should have value "global"
|
|
And ConfigScope should have value "project"
|
|
And ConfigScope should have value "local"
|
|
|
|
# ── ConfigLevel enum includes LOCAL ───────────────────────────────────
|
|
|
|
Scenario: ConfigLevel enum includes LOCAL between ENV_VAR and PROJECT
|
|
Then ConfigLevel should have value "local"
|
|
And ConfigLevel "local" should exist between "env_var" and "project"
|
|
|
|
# ── .gitignore template includes config.local.toml ────────────────────
|
|
|
|
Scenario: Default ignore patterns include config.local.toml
|
|
Then the default ignore patterns should include "config.local.toml"
|