Feature: LSP language discovery coverage
  Exercise uncovered lines in src/cleveragents/lsp/discovery.py
  covering shebang detection, cache behaviour, directory scanning,
  special-name detection, UKO layer, and server matching.

  # ------------------------------------------------------------------
  # Layer 2 – shebang detection edge cases (lines 142, 146, 157)
  # ------------------------------------------------------------------

  Scenario: Shebang returns None for non-shebang line
    Given ldcov a first line "echo hello"
    When ldcov I detect from shebang
    Then ldcov the shebang result is None

  Scenario: Shebang returns None for bare hashbang
    Given ldcov a first line "#!"
    When ldcov I detect from shebang
    Then ldcov the shebang result is None

  Scenario: Shebang returns None for empty hashbang with whitespace
    Given ldcov a first line "#!  "
    When ldcov I detect from shebang
    Then ldcov the shebang result is None

  Scenario: Shebang returns None for unknown interpreter
    Given ldcov a first line "#!/usr/bin/unknownlang"
    When ldcov I detect from shebang
    Then ldcov the shebang result is None

  # ------------------------------------------------------------------
  # Cache hit (line 201)
  # ------------------------------------------------------------------

  Scenario: detect_file_language returns cached result on second call
    Given ldcov a LanguageDiscovery instance
    And ldcov the cache already contains "/tmp/cached.py" mapped to "python"
    When ldcov I detect file language for "/tmp/cached.py"
    Then ldcov the detected language is "python"

  # ------------------------------------------------------------------
  # invalidate_all (line 246)
  # ------------------------------------------------------------------

  Scenario: invalidate_all clears the entire cache
    Given ldcov a LanguageDiscovery instance
    And ldcov the cache already contains "/a.py" mapped to "python"
    And ldcov the cache already contains "/b.rs" mapped to "rust"
    When ldcov I call invalidate_all
    Then ldcov the cache is empty

  # ------------------------------------------------------------------
  # Special basenames – Makefile (line 257), CMakeLists.txt (line 259)
  # ------------------------------------------------------------------

  Scenario: Makefile is detected as makefile language
    Given ldcov a LanguageDiscovery instance
    When ldcov I detect uncached language for "project/Makefile"
    Then ldcov the detected language is "makefile"

  Scenario: CMakeLists.txt is detected as cmake language
    Given ldcov a LanguageDiscovery instance
    When ldcov I detect uncached language for "project/CMakeLists.txt"
    Then ldcov the detected language is "cmake"

  # ------------------------------------------------------------------
  # Layer 3 – UKO classification (line 276)
  # ------------------------------------------------------------------

  Scenario: UKO classification is used when extension and shebang miss
    Given ldcov a LanguageDiscovery instance with UKO mapping "/data/blob" to "python"
    When ldcov I detect uncached language for "/data/blob"
    Then ldcov the detected language is "python"

  # ------------------------------------------------------------------
  # Directory scanning (lines 219-231, 234)
  # ------------------------------------------------------------------

  Scenario: detect_directory_languages finds languages in a tree
    Given ldcov a LanguageDiscovery instance
    And ldcov a mock directory tree with files "app.py,lib.rs,readme.txt"
    When ldcov I detect directory languages
    Then ldcov the directory languages include "python"
    And ldcov the directory languages include "rust"

  Scenario: detect_directory_languages handles OSError gracefully
    Given ldcov a LanguageDiscovery instance
    And ldcov os.walk will raise an OSError
    When ldcov I detect directory languages for "/nonexistent"
    Then ldcov the directory languages result is an empty list

  # ------------------------------------------------------------------
  # get_servers_for_language (lines 298-301)
  # ------------------------------------------------------------------

  Scenario: get_servers_for_language filters matching configs
    Given ldcov a LanguageDiscovery instance
    And ldcov server configs with languages "python,rust" and "javascript"
    When ldcov I get servers for language "python"
    Then ldcov the matched server count is 1

  Scenario: get_servers_for_language returns empty for no match
    Given ldcov a LanguageDiscovery instance
    And ldcov server configs with languages "python,rust" and "javascript"
    When ldcov I get servers for language "haskell"
    Then ldcov the matched server count is 0
