Feature: ConfigService coverage round 3 — path accessors, write_scoped_config, set_value, and resolve local
  Exercises uncovered lines in config_service.py:
    - Line 1195:  project_root property
    - Line 1201:  project_config_path returns None
    - Line 1208:  local_config_path returns None
    - Lines 1284-1285, 1289:  write_scoped_config ValueError for missing project root
    - Lines 1297-1298:  write_scoped_config reads existing target file
    - Lines 1336-1337:  set_value redacts sensitive keys
    - Lines 1351-1352:  set_value catches event_bus emit failure
    - Lines 1507-1508, 1510-1511:  resolve verbose with local config winning

  Background:
    Given cfscov3 a fresh temporary directory

  # -- project_root property (line 1195) --

  Scenario: project_root returns the configured project root path
    Given cfscov3 a ConfigService with an explicit project root
    Then cfscov3 project_root should return the configured path

  Scenario: project_root returns None when no project root is set
    Given cfscov3 a ConfigService with no project root
    Then cfscov3 project_root should return None

  # -- project_config_path returns None (line 1201) --

  Scenario: project_config_path returns None when project root is absent
    Given cfscov3 a ConfigService with no project root
    Then cfscov3 project_config_path should return None

  # -- local_config_path returns None (line 1208) --

  Scenario: local_config_path returns None when project root is absent
    Given cfscov3 a ConfigService with no project root
    Then cfscov3 local_config_path should return None

  # -- write_scoped_config raises ValueError (lines 1284-1285, 1289) --

  Scenario: write_scoped_config raises ValueError for PROJECT scope without project root
    Given cfscov3 a ConfigService with no project root
    When cfscov3 I call write_scoped_config with PROJECT scope
    Then cfscov3 a ValueError mentioning "no project root" should be stored

  Scenario: write_scoped_config raises ValueError for LOCAL scope without project root
    Given cfscov3 a ConfigService with no project root
    When cfscov3 I call write_scoped_config with LOCAL scope
    Then cfscov3 a ValueError mentioning "no project root" should be stored

  # -- write_scoped_config reads existing target (lines 1297-1298) --

  Scenario: write_scoped_config merges into existing project config.toml
    Given cfscov3 a ConfigService with a project root containing an existing config.toml
    When cfscov3 I call write_scoped_config with PROJECT scope adding a new key
    Then cfscov3 the project config.toml should contain both the old and new keys

  Scenario: write_scoped_config merges into existing local config.local.toml
    Given cfscov3 a ConfigService with a project root containing an existing config.local.toml
    When cfscov3 I call write_scoped_config with LOCAL scope adding a new key
    Then cfscov3 the local config.local.toml should contain both the old and new keys

  # -- set_value redacts sensitive keys (lines 1336-1337) --

  Scenario: set_value redacts old and new values for a sensitive key
    Given cfscov3 a ConfigService with a mock event bus
    When cfscov3 I call set_value with sensitive key "provider.openai.api-key" and value "sk-secret-123"
    Then cfscov3 the event bus should have received redacted values

  # -- set_value catches event_bus emit failure (lines 1351-1352) --

  Scenario: set_value swallows exception when event_bus.emit raises
    Given cfscov3 a ConfigService with a failing event bus
    When cfscov3 I call set_value with key "core.log.level" and value "DEBUG"
    Then cfscov3 no error should have been raised

  # -- resolve verbose with local config winning (lines 1507-1508, 1510-1511) --

  Scenario: resolve in verbose mode returns local config value with chain entry
    Given cfscov3 a ConfigService with a local config containing "core.log.level" set to "TRACE"
    When cfscov3 I resolve "core.log.level" with verbose True
    Then cfscov3 the resolved value should be "TRACE" from LOCAL source
    And cfscov3 the chain should contain a local entry with value "TRACE" and a path
