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"