Feature: LSP Runtime coverage for uncovered lines
  As a developer
  I want thorough tests for LspRuntime
  So that all code paths in runtime.py are exercised

  # ── Properties (lines 62, 67) ──────────────────────────────────────

  Scenario: Access registry property
    Given lrcov I create an LspRuntime with defaults
    Then lrcov the registry property returns the registry

  Scenario: Access lifecycle property
    Given lrcov I create an LspRuntime with defaults
    Then lrcov the lifecycle property returns the lifecycle manager

  # ── start_server success path (lines 93-97, 100) ──────────────────

  Scenario: start_server delegates to lifecycle on success
    Given lrcov I create an LspRuntime with a registered server "local/pyright"
    When lrcov I start server "local/pyright" with workspace "/tmp/ws"
    Then lrcov the lifecycle start_server should have been called

  # ── stop_server (line 116) ─────────────────────────────────────────

  Scenario: stop_server rejects empty name
    Given lrcov I create an LspRuntime with defaults
    When lrcov I try to stop server with empty name
    Then lrcov a ValueError should be raised

  Scenario: stop_server delegates to lifecycle
    Given lrcov I create an LspRuntime with a mock lifecycle
    When lrcov I stop server "local/pyright"
    Then lrcov the lifecycle stop_server should have been called with "local/pyright"

  # ── get_diagnostics (lines 143, 146, 149-155, 157-158, 161, 164, 166-172) ──

  Scenario: get_diagnostics rejects empty file_path
    Given lrcov I create an LspRuntime with defaults
    When lrcov I try to get diagnostics with name "local/pyright" and empty file_path
    Then lrcov a ValueError should be raised

  Scenario: get_diagnostics succeeds with mock client
    Given lrcov I create an LspRuntime with a healthy mock server "local/pyright"
    And lrcov I have a temp Python file with content "x = 1"
    When lrcov I get diagnostics for "local/pyright" on the temp file
    Then lrcov diagnostics should be returned as a list
    And lrcov the mock client did_open should have been called
    And lrcov the mock client did_close should have been called

  Scenario: get_diagnostics wraps OSError in LspError
    Given lrcov I create an LspRuntime with a healthy mock server "local/pyright"
    And lrcov I patch read_file to raise OSError
    When lrcov I try to get diagnostics for "local/pyright" on file "/tmp/test.py"
    Then lrcov an LspError should be raised with message containing "Cannot read file"

  # ── get_completions (lines 198, 200, 207, 210-216, 218-219, 222, 224, 226-233) ──

  Scenario: get_completions rejects empty name
    Given lrcov I create an LspRuntime with defaults
    When lrcov I try to get completions with empty name
    Then lrcov a ValueError should be raised

  Scenario: get_completions rejects empty file_path
    Given lrcov I create an LspRuntime with defaults
    When lrcov I try to get completions with name "local/pyright" and empty file_path
    Then lrcov a ValueError should be raised

  Scenario: get_completions succeeds with mock client
    Given lrcov I create an LspRuntime with a healthy mock server "local/pyright"
    And lrcov I have a temp Python file with content "x = 1"
    When lrcov I get completions for "local/pyright" on the temp file at line 1 column 1
    Then lrcov completions should be returned as a list
    And lrcov the mock client did_open should have been called
    And lrcov the mock client did_close should have been called

  Scenario: get_completions wraps OSError in LspError
    Given lrcov I create an LspRuntime with a healthy mock server "local/pyright"
    And lrcov I patch read_file to raise OSError
    When lrcov I try to get completions for "local/pyright" on file "/tmp/test.py" at line 1 column 1
    Then lrcov an LspError should be raised with message containing "Cannot read file"

  # ── _get_healthy_client healthy path (line 255) ────────────────────

  Scenario: get_healthy_client returns client when server is healthy
    Given lrcov I create an LspRuntime with a healthy mock server "local/pyright"
    When lrcov I call get_healthy_client for "local/pyright"
    Then lrcov the returned client should be the mock client

  # ── _path_to_uri (lines 260-262) ───────────────────────────────────

  Scenario: path_to_uri passes through file URI
    When lrcov I convert "file:///tmp/test.py" using path_to_uri
    Then lrcov the URI should be "file:///tmp/test.py"

  Scenario: path_to_uri converts a filesystem path
    When lrcov I convert "/tmp/test.py" using path_to_uri
    Then lrcov the URI should be "file:///tmp/test.py"

  # ── _read_file (lines 271-278) ─────────────────────────────────────

  Scenario: read_file returns content of a real file
    Given lrcov I have a temp file with content "hello world"
    When lrcov I call read_file on the temp file
    Then lrcov the file content should be "hello world"

  Scenario: read_file raises LspError for a directory path
    When lrcov I call read_file on a directory path
    Then lrcov an LspError should be raised with message containing "Not a regular file"

  # ── _detect_language (lines 287, 289) ──────────────────────────────

  Scenario: detect_language delegates to LanguageDiscovery
    When lrcov I call detect_language on "test.py"
    Then lrcov the detected language should be "python"

  # ── activate_bindings (lines 314, 317) ─────────────────────────────

  Scenario: activate_bindings skips binding with empty server name
    Given lrcov I create an LspRuntime with a mock lifecycle
    When lrcov I activate bindings with a binding that has empty server_name
    Then lrcov the activated list should be empty

  Scenario: activate_bindings starts a registered server successfully
    Given lrcov I create an LspRuntime with a registered server "local/pyright"
    When lrcov I activate bindings with a binding for "local/pyright" and workspace "/tmp"
    Then lrcov the activated list should contain "local/pyright"

  # ── deactivate_bindings (lines 333-338) ────────────────────────────

  Scenario: deactivate_bindings stops a running server
    Given lrcov I create an LspRuntime with a mock lifecycle
    When lrcov I deactivate bindings with a binding for "local/pyright"
    Then lrcov the lifecycle stop_server should have been called with "local/pyright"

  Scenario: deactivate_bindings skips binding with empty server name
    Given lrcov I create an LspRuntime with a mock lifecycle
    When lrcov I deactivate bindings with a binding that has empty server_name
    Then lrcov the lifecycle stop_server should not have been called

  Scenario: deactivate_bindings suppresses errors
    Given lrcov I create an LspRuntime with a mock lifecycle that raises on stop
    When lrcov I deactivate bindings with a binding for "local/pyright"
    Then lrcov no error should be raised

  # ── stop_all (line 342) ────────────────────────────────────────────

  Scenario: stop_all delegates to lifecycle stop_all
    Given lrcov I create an LspRuntime with a mock lifecycle
    When lrcov I call stop_all
    Then lrcov the lifecycle stop_all should have been called
