Feature: Consolidated Config
  Combined scenarios from: config_parser_coverage, config_resolution, config_service_coverage, coverage_threshold_config

  # ============================================================
  # Originally from: config_parser_coverage.feature
  # Feature: Reactive config parser coverage
  # ============================================================

  Scenario: Parse combined configs with merges, routes, and pipelines
    Given a temporary directory for reactive config parsing
    Given reactive config files covering merges, routes, and pipelines
    When I parse the reactive config files
    Then the merged reactive config should preserve agents and replacements
    And stream and graph routes should be built with defaults and bridges
    And reactive config should include merges splits pipelines and templates


  Scenario: Interpolate environment variables with defaults
    Given a temporary directory for reactive config parsing
    Given a reactive config file with environment placeholders
    And environment variables are set for interpolation
    When I parse the reactive config files
    Then environment placeholders should resolve using values and defaults


  Scenario: Raise error for missing required environment variable
    Given a temporary directory for reactive config parsing
    Given a reactive config file with a required environment placeholder
    When I parse the reactive config files expecting failure
    Then a configuration error should be raised for the missing variable


  # ============================================================
  # Originally from: config_resolution.feature
  # Feature: Config service with multi-level resolution
  # ============================================================

  Scenario: Default value is returned when nothing else is set
    Given a clean config service test environment
    When I resolve config key "core.log.level"
    Then the resolved value should be "FATAL"
    And the resolved source should be "default"


  Scenario: Global config file overrides default
    Given a clean config service test environment
    Given I have written global config key "core.log.level" with value "DEBUG"
    When I resolve config key "core.log.level"
    Then the resolved value should be "DEBUG"
    And the resolved source should be "global"


  Scenario: Environment variable overrides global config
    Given a clean config service test environment
    Given I have written global config key "core.log.level" with value "DEBUG"
    And the environment variable "CLEVERAGENTS_LOG_LEVEL" is set to "WARNING"
    When I resolve config key "core.log.level"
    Then the resolved value should be "WARNING"
    And the resolved source should be "env_var"


  Scenario: CLI flag overrides environment variable
    Given a clean config service test environment
    Given the environment variable "CLEVERAGENTS_LOG_LEVEL" is set to "WARNING"
    When I resolve config key "core.log.level" with CLI value "ERROR"
    Then the resolved value should be "ERROR"
    And the resolved source should be "cli_flag"


  Scenario: Project-scoped value overrides global config
    Given a clean config service test environment
    Given I have written global config key "core.automation-profile" with value "review"
    And I have written project "myproj" config key "core.automation-profile" with value "trusted"
    When I resolve config key "core.automation-profile" for project "myproj"
    Then the resolved value should be "trusted"
    And the resolved source should be "project"


  Scenario: Env var still overrides project-scoped value
    Given a clean config service test environment
    Given I have written project "myproj" config key "core.automation-profile" with value "trusted"
    And the environment variable "CLEVERAGENTS_AUTOMATION_PROFILE" is set to "manual"
    When I resolve config key "core.automation-profile" for project "myproj"
    Then the resolved value should be "manual"
    And the resolved source should be "env_var"

    # --- Env var interpolation ---


  Scenario: Env var name matches CLEVERAGENTS convention
    Given a clean config service test environment
    When I look up the env var for key "core.log.level"
    Then the env var name should be "CLEVERAGENTS_LOG_LEVEL"


  Scenario: Env var interpolation for plan keys
    Given a clean config service test environment
    When I look up the env var for key "plan.concurrency"
    Then the env var name should be "CLEVERAGENTS_PLAN_CONCURRENCY"


  Scenario: Env var interpolation for plan budget keys
    Given a clean config service test environment
    When I look up the env var for key "plan.budget.warn-threshold"
    Then the env var name should be "CLEVERAGENTS_PLAN_BUDGET_WARN"


  Scenario: Provider keys use custom env var names
    Given a clean config service test environment
    When I look up the env var for key "provider.openai.api-key"
    Then the env var name should be "OPENAI_API_KEY"

    # --- Unknown key rejection ---


  Scenario: Resolving an unknown key raises an error
    Given a clean config service test environment
    When I attempt to resolve unknown key "bogus.nonexistent"
    Then the config ValueError message should contain "Unknown configuration key"


  Scenario: Validating an unknown key raises an error
    Given a clean config service test environment
    When I attempt to validate unknown key "invalid.key"
    Then the config ValueError message should contain "Unknown configuration key"

    # --- Type validation ---


  Scenario: Integer value is coerced from string
    Given a clean config service test environment
    Given the environment variable "CLEVERAGENTS_PLAN_CONCURRENCY" is set to "9090"
    When I resolve config key "plan.concurrency"
    Then the resolved value should be integer 9090


  Scenario: Boolean value true is coerced from string
    Given a clean config service test environment
    Given the environment variable "CLEVERAGENTS_LOG_FILE_ENABLED" is set to "true"
    When I resolve config key "core.log.file-enabled"
    Then the resolved value should be boolean true


  Scenario: Boolean value false is coerced from string
    Given a clean config service test environment
    Given the environment variable "CLEVERAGENTS_LOG_FILE_ENABLED" is set to "false"
    When I resolve config key "core.log.file-enabled"
    Then the resolved value should be boolean false


  Scenario: Float value is coerced from string
    Given a clean config service test environment
    Given the environment variable "CLEVERAGENTS_PLAN_BUDGET_WARN" is set to "0.9"
    When I resolve config key "plan.budget.warn-threshold"
    Then the resolved value should be float 0.9


  Scenario: Invalid boolean string raises TypeError
    Given a clean config service test environment
    When I attempt to validate type for key "core.log.file-enabled" with value "notabool"
    Then the config TypeError message should contain "Cannot convert"


  Scenario: Invalid integer string raises TypeError
    Given a clean config service test environment
    When I attempt to validate type for key "plan.concurrency" with value "notanumber"
    Then the config TypeError message should contain "Type mismatch"

    # --- Verbose resolution chain ---


  Scenario: Verbose mode returns full resolution chain
    Given a clean config service test environment
    When I resolve config key "core.log.level" with verbose mode
    Then the resolution chain should have 6 entries
    And the chain should include source "cli_flag"
    And the chain should include source "env_var"
    And the chain should include source "local"
    And the chain should include source "project"
    And the chain should include source "global"
    And the chain should include source "default"

    # --- Key registry ---


  Scenario: Registry contains core keys
    Given a clean config service test environment
    Then the registry should contain key "core.log.level"
    And the registry should contain key "core.log.file-enabled"
    And the registry should contain key "core.data-dir"


  Scenario: Registry contains plan keys
    Given a clean config service test environment
    Then the registry should contain key "plan.concurrency"
    And the registry should contain key "plan.max-child-depth"
    And the registry should contain key "plan.budget.per-plan"


  Scenario: Registry contains provider keys
    Given a clean config service test environment
    Then the registry should contain key "provider.openai.api-key"
    And the registry should contain key "provider.anthropic.api-key"


  Scenario: Registry contains sandbox keys
    Given a clean config service test environment
    Then the registry should contain key "sandbox.strategy"
    And the registry should contain key "sandbox.cleanup"
    And the registry should contain key "sandbox.checkpoint.enabled"


  Scenario: Registry contains context keys
    Given a clean config service test environment
    Then the registry should contain key "context.hot.max-tokens"
    And the registry should contain key "context.warm.max-decisions"


  Scenario: Registry contains index keys
    Given a clean config service test environment
    Then the registry should contain key "index.auto-reindex"
    And the registry should contain key "index.text.backend"


  Scenario: Registry contains server keys
    Given a clean config service test environment
    Then the registry should contain key "server.url"
    And the registry should contain key "server.token"
    And the registry should contain key "server.sync.auto"


  Scenario: Registry contains actor keys
    Given a clean config service test environment
    Then the registry should contain key "actor.default.strategy"
    And the registry should contain key "actor.default.execution"

    # --- TOML file management ---


  Scenario: Writing and reading TOML config roundtrips
    Given a clean config service test environment
    Given I write config data with key "core.log.level" and value "TRACE"
    When I read the config file
    Then the config data should contain key "core.log.level" with value "TRACE"


  Scenario: Config directory is auto-created
    Given a clean config service test environment
    When I write config data to a new directory
    Then the config directory should exist


  Scenario: Non-project-scopable keys ignore project scope
    Given a clean config service test environment
    Given I have written project "proj" config key "core.data-dir" with value "/tmp/other"
    When I resolve config key "core.data-dir" for project "proj"
    Then the resolved source should be "default"

    # --- Resolve all ---


  Scenario: Resolve all returns all registered keys
    Given a clean config service test environment
    When I resolve all keys
    Then the result should contain all registered keys

    # --- Set value ---


  Scenario: Set value persists to TOML file
    Given a clean config service test environment
    When I set config value "core.log.level" to "CRITICAL"
    And I read the config file
    Then the config data should contain key "core.log.level" with value "CRITICAL"

    # --- Entry lookup ---


  Scenario: Get entry returns ConfigEntry for valid key
    Given a clean config service test environment
    When I get entry for key "core.log.level"
    Then the entry should have section "core"
    And the entry should have python type "str"


  Scenario: Get entry returns None for unknown key
    Given a clean config service test environment
    When I get entry for key "nonexistent.key"
    Then the entry should be None


  # ============================================================
  # Originally from: config_service_coverage.feature
  # Feature: ConfigService full coverage
  # ============================================================

  Scenario: ConfigLevel enum has six precedence levels
    Then ConfigLevel should have values CLI_FLAG ENV_VAR LOCAL PROJECT GLOBAL DEFAULT

    # ---------- ConfigEntry and ResolvedValue dataclasses ----------


  Scenario: ConfigEntry dataclass stores all metadata fields
    Given a ConfigEntry with key "test.key" and type str
    Then the ConfigEntry fields should match the provided values


  Scenario: ResolvedValue dataclass stores resolution result
    Given a ResolvedValue with key "test.key" and source DEFAULT
    Then the ResolvedValue fields should match including an empty chain by default

    # ---------- _env_name helper ----------


  Scenario: _env_name builds uppercase CLEVERAGENTS env var name
    When I call _env_name with section "core" and key "log_level"
    Then the env name should be "CLEVERAGENTS_CORE_LOG_LEVEL"

    # ---------- _register and _build_catalog ----------


  Scenario: _register adds an entry to the global registry
    When I register a custom key "custom.test_key" with type int and default 42
    Then the registry should contain "custom.test_key" with default 42


  Scenario: _register uses explicit env_var when provided
    When I register a key "custom.explicit_env" with explicit env_var "MY_CUSTOM_VAR"
    Then the entry "custom.explicit_env" should have env_var "MY_CUSTOM_VAR"


  Scenario: _build_catalog populates all expected config sections
    Then the registry should contain keys from sections core plan provider sandbox context index


  Scenario: _build_catalog registers the expected number of keys
    Then the registry should contain at least 20 keys

    # ---------- ConfigService instantiation ----------


  Scenario: ConfigService uses custom config_dir and config_path
    Given a temporary directory for config service
    When I create a ConfigService with custom paths
    Then the service should use the custom config directory and path


  Scenario: ConfigService uses defaults when no paths provided
    When I create a ConfigService with default paths
    Then the service config path should end with ".cleveragents/config.toml"

    # ---------- registry(), get_entry(), registered_keys() ----------


  Scenario: registry returns a copy of all registered entries
    When I call ConfigService.registry
    Then it should return a dict with the same keys as the internal registry


  Scenario: get_entry returns the entry for a known key
    When I call ConfigService.get_entry with "core.log.level"
    Then it should return a ConfigEntry with key "core.log.level"


  Scenario: get_entry returns None for an unknown key
    When I call ConfigService.get_entry with "nonexistent.key"
    Then it should return None


  Scenario: registered_keys returns a sorted list of all keys
    When I call ConfigService.registered_keys
    Then it should return a sorted list containing "core.log.level"

    # ---------- read_config ----------


  Scenario: read_config returns empty dict when file does not exist
    Given a temporary directory for config service
    When I create a ConfigService pointing to a missing config file
    Then read_config should return an empty dict


  Scenario: read_config parses an existing TOML file
    Given a temporary directory for config service
    And a TOML config file with key "core.log.level" set to "DEBUG"
    When I create a ConfigService pointing to that TOML file
    Then read_config should return a dict with "core.log.level" equal to "DEBUG"

    # ---------- write_config ----------


  Scenario: write_config creates directories and writes a new TOML file
    Given a temporary directory for config service
    When I create a ConfigService with a nested non-existent config directory
    And I call write_config with key "greeting" value "hello"
    Then the TOML file should exist and contain key "greeting" with value "hello"


  Scenario: write_config merges data into an existing TOML file
    Given a temporary directory for config service
    And a TOML config file with key "existing" set to "value1"
    When I create a ConfigService pointing to that TOML file
    And I call write_config with key "new_key" value "value2"
    Then read_config should return a dict containing both "existing" and "new_key"

    # ---------- set_value ----------


  Scenario: set_value persists a single key-value pair
    Given a temporary directory for config service
    When I create a ConfigService with custom paths
    And I call set_value with key "mykey" and value "myval"
    Then read_config should return a dict with "mykey" equal to "myval"

    # ---------- validate_key ----------


  Scenario: validate_key returns entry for a known key
    When I call validate_key with "core.log.level"
    Then it should return the ConfigEntry for "core.log.level" without error


  Scenario: validate_key raises ValueError for an unknown key
    When I call validate_key with "totally.unknown"
    Then a ValueError should be raised mentioning "Unknown configuration key"

    # ---------- validate_type ----------


  Scenario: validate_type returns value unchanged when type already matches
    When I call validate_type with key "core.log.level" and value "INFO"
    Then it should return "INFO" unchanged


  Scenario: validate_type coerces a string to int
    When I call validate_type with key "plan.concurrency" and string value "9090"
    Then it should return the integer 9090


  Scenario: validate_type coerces a string to float
    When I call validate_type with key "plan.budget.warn-threshold" and string value "0.5"
    Then it should return the float 0.5


  Scenario: validate_type coerces non-string to str
    When I call validate_type with key "core.log.level" and integer value 123
    Then it should return the string "123"


  Scenario: validate_type coerces "true" string to bool True
    When I call validate_type with key "core.log.file-enabled" and string value "true"
    Then it should return boolean True


  Scenario: validate_type coerces "1" string to bool True
    When I call validate_type with key "core.log.file-enabled" and string value "1"
    Then it should return boolean True


  Scenario: validate_type coerces "yes" string to bool True
    When I call validate_type with key "core.log.file-enabled" and string value "yes"
    Then it should return boolean True


  Scenario: validate_type coerces "false" string to bool False
    When I call validate_type with key "core.log.file-enabled" and string value "false"
    Then it should return boolean False


  Scenario: validate_type coerces "0" string to bool False
    When I call validate_type with key "core.log.file-enabled" and string value "0"
    Then it should return boolean False


  Scenario: validate_type coerces "no" string to bool False
    When I call validate_type with key "core.log.file-enabled" and string value "no"
    Then it should return boolean False


  Scenario: validate_type raises TypeError for invalid bool string
    When I call validate_type with key "core.log.file-enabled" and string value "maybe"
    Then a TypeError should be raised mentioning "Cannot convert"


  Scenario: validate_type raises TypeError for non-coercible int value
    When I call validate_type with key "plan.concurrency" and string value "not_a_number"
    Then a TypeError should be raised mentioning "Type mismatch"


  Scenario: validate_type raises TypeError for non-bool non-string to bool key
    When I call validate_type with key "core.log.file-enabled" and a list value
    Then a TypeError should be raised mentioning "Type mismatch"


  Scenario: validate_type raises ValueError for completely unknown key
    When I call validate_type with unknown key "fake.unknown" and value "x"
    Then the raised ValueError should mention "Cannot validate type for unknown key"

    # ---------- resolve: six-level chain ----------


  Scenario: resolve returns default value when no overrides exist
    Given a temporary directory for config service
    And a ConfigService with empty config for resolve tests
    When I resolve key "core.log.level" with no overrides
    Then the resolved value should be "FATAL" from source DEFAULT


  Scenario: resolve returns CLI flag value when provided
    Given a temporary directory for config service
    And a ConfigService with empty config for resolve tests
    When I resolve key "core.log.level" with cli_value "TRACE"
    Then the resolved value should be "TRACE" from source CLI_FLAG


  Scenario: resolve returns environment variable when no CLI flag
    Given a temporary directory for config service
    And a ConfigService with empty config for resolve tests
    And the env var "CLEVERAGENTS_LOG_LEVEL" is injected with "WARNING"
    When I resolve key "core.log.level" with no overrides
    Then the resolved value should be "WARNING" from source ENV_VAR


  Scenario: CLI flag takes precedence over environment variable
    Given a temporary directory for config service
    And a ConfigService with empty config for resolve tests
    And the env var "CLEVERAGENTS_LOG_LEVEL" is injected with "WARNING"
    When I resolve key "core.log.level" with cli_value "TRACE"
    Then the resolved value should be "TRACE" from source CLI_FLAG


  Scenario: resolve returns project-scoped value when set
    Given a temporary directory for config service
    And a ConfigService with project-scoped config for key "core.automation-profile" value "PROJECT_DEBUG" under project "myproj"
    When I resolve key "core.automation-profile" with project_name "myproj"
    Then the resolved value should be "PROJECT_DEBUG" from source PROJECT


  Scenario: resolve returns global config value when no higher overrides
    Given a temporary directory for config service
    And a ConfigService with global config key "core.log.level" set to "GLOBAL_WARN"
    When I resolve key "core.log.level" with no overrides
    Then the resolved value should be "GLOBAL_WARN" from source GLOBAL


  Scenario: resolve populates chain when verbose is True
    Given a temporary directory for config service
    And a ConfigService with empty config for resolve tests
    When I resolve key "core.log.level" with verbose True and no overrides
    Then the resolved chain should have 6 entries covering all levels


  Scenario: resolve verbose chain includes env_name for ENV_VAR level
    Given a temporary directory for config service
    And a ConfigService with empty config for resolve tests
    When I resolve key "core.log.level" with verbose True and no overrides
    Then the verbose chain ENV_VAR entry should include env_name "CLEVERAGENTS_LOG_LEVEL"


  Scenario: resolve verbose chain includes path for GLOBAL level
    Given a temporary directory for config service
    And a ConfigService with empty config for resolve tests
    When I resolve key "core.log.level" with verbose True and no overrides
    Then the verbose chain GLOBAL entry should include the config file path


  Scenario: resolve verbose chain shows project value when project-scoped wins
    Given a temporary directory for config service
    And a ConfigService with project-scoped config for key "core.automation-profile" value "PROJECT_DEBUG" under project "myproj"
    When I resolve key "core.automation-profile" with project_name "myproj" and verbose True
    Then the resolved value should be "PROJECT_DEBUG" from source PROJECT
    And the verbose chain PROJECT entry should have value "PROJECT_DEBUG"


  Scenario: resolve verbose chain shows global value when global config wins
    Given a temporary directory for config service
    And a ConfigService with global config key "core.log.level" set to "GLOBAL_WARN"
    When I resolve key "core.log.level" with verbose True and no overrides
    Then the resolved value should be "GLOBAL_WARN" from source GLOBAL
    And the verbose chain GLOBAL entry should have value "GLOBAL_WARN"


  Scenario: resolve skips project scope for non-scopable keys
    Given a temporary directory for config service
    And a ConfigService with project-scoped config for key "core.data-dir" value "/proj/data" under project "myproj"
    When I resolve key "core.data-dir" with project_name "myproj"
    Then the resolved value should not be "/proj/data"
    And the resolved source should be DEFAULT or GLOBAL

    # ---------- env_var_for_key ----------


  Scenario: env_var_for_key returns the env var name for a valid key
    When I call env_var_for_key with "core.log.level"
    Then it should return "CLEVERAGENTS_LOG_LEVEL"


  Scenario: env_var_for_key raises ValueError for an unknown key
    When I call env_var_for_key with "nonexistent.key"
    Then a ValueError should be raised mentioning "Unknown configuration key"

    # ---------- resolve_all ----------


  Scenario: resolve_all returns a resolved value for every registered key
    Given a temporary directory for config service
    And a ConfigService with empty config for resolve tests
    When I call resolve_all with no overrides
    Then the result should contain an entry for every registered key


  Scenario: resolve_all applies CLI overrides to matching keys
    Given a temporary directory for config service
    And a ConfigService with empty config for resolve tests
    When I call resolve_all with cli_override "core.log.level" set to "FATAL"
    Then the resolve_all result for "core.log.level" should have value "FATAL" and source CLI_FLAG


  # ============================================================
  # Originally from: coverage_threshold_config.feature
  # Feature: Coverage threshold configuration enforcement
  # ============================================================

  Scenario: Coverage configuration exists in pyproject.toml
    Given the pyproject toml file is loaded for coverage check
    Then the coverage run section should exist
    And the coverage source should include "src"
    And the coverage branch tracking should be enabled


  @tdd_issue @tdd_issue_4227
  Scenario: Coverage threshold is at least 96.5 percent in noxfile
    Given the noxfile py is loaded for coverage check
    Then the noxfile should contain a fail-under threshold of at least 96.5


  Scenario: Coverage report session exists in noxfile
    Given the noxfile py is loaded for coverage check
    Then the noxfile should define a coverage_report session


  Scenario: Coverage HTML output directory is configured
    Given the pyproject toml file is loaded for coverage check
    Then the coverage html directory should be "build/htmlcov"


  Scenario: Coverage XML output path is configured
    Given the pyproject toml file is loaded for coverage check
    Then the coverage xml output should be "build/coverage.xml"


  Scenario: Coverage data file path is configured
    Given the pyproject toml file is loaded for coverage check
    Then the coverage data file should be "build/.coverage"


  Scenario: Coverage omits test directories
    Given the pyproject toml file is loaded for coverage check
    Then the coverage omit patterns should include "features/*"
    And the coverage omit patterns should include "*/tests/*"


  Scenario: CI workflow enforces coverage via nox session
    Given the ci workflow file is loaded for coverage check
    Then the ci workflow should reference nox coverage_report session


  Scenario: Nightly workflow uses at least 96.5 percent threshold
    Given the nightly quality workflow file is loaded for coverage check
    Then the nightly workflow should use a fail-under of at least 96.5
