Cut Daemon and TimedLspClient cycle: Daemon owns the caller-side LSP time limit #1175

Closed
opened 2026-10-19 22:19:36 +00:00 by jared · 2 comments
Owner

Problem

OsSdlc::TimedLspClient wraps Daemon.connect and applies a 60 s caller-side time limit to each LSP query. Daemon::Navigation holds TimedLspClient, and TimedLspClient holds Daemon, so the two form a concept cycle. The 60 s limit and its message also have two owners: TimedLspClient (timed_lsp_client.rb:7, 26-34) and Daemon::LspSession (daemon/lsp_session.rb:10, 103-109). Ruling S9 gives the caller-side limit to Daemon and deletes the wrapper.

Reproduce

n/a: structure-wave cut, nothing to reproduce

Approach

Daemon gains the four query class methods that TimedLspClient has today. Daemon owns one limit constant and one message, and Daemon::LspSession uses them.

Required work:

  1. Add Daemon.definitions(at:, root:, config:), Daemon.references(at:, root:, config:), Daemon.symbols(name:, root:, config:) and Daemon.outline(path:, root:, config:) to plugins/os-sdlc/lib/os_sdlc/daemon.rb. Each connects with Daemon.connect and runs its query inside Timeout.timeout(QUERY_SECONDS, LspTimeoutError, ...), as TimedLspClient.run does today. — check: present QUERY_SECONDS = 60 in plugins/os-sdlc/lib/os_sdlc/daemon.rb
  2. Daemon::LspSession#with_timeout and #timeout_message use the Daemon constant and message. Delete LspSession::TIMEOUT_SECONDS. — check: absent TIMEOUT_SECONDS in plugins/os-sdlc/lib/os_sdlc/daemon/lsp_session.rb
  3. Change the default :server in plugins/os-sdlc/lib/os_sdlc/daemon/navigation.rb:17 and the default runner: in plugins/os-sdlc/lib/os_sdlc/evidence/probe/lsp.rb:7 to Daemon. — check: absent TimedLspClient in plugins/os-sdlc/lib/**/*.rb
  4. Delete plugins/os-sdlc/lib/os_sdlc/timed_lsp_client.rb.

Acceptance criteria

  1. Given the suite, when run after the change, then it passes with no new failures.
  2. Given the lib tree, when bin/crc-cycle-edges runs, then no cycle edge lists timed_lsp_client.rb or daemon/navigation.rb:17.
  3. Given an LSP query that runs over 60 s, when it runs through Daemon.definitions, then it raises LspTimeoutError with the message lsp-probe: ruby-lsp did not respond within 60s.

Owner sketch

class OsSdlc::Daemon
  QUERY_SECONDS = 60
  def self.definitions(at:, root:, config:)
  def self.references(at:, root:, config:)
  def self.symbols(name:, root:, config:)
  def self.outline(path:, root:, config:)
  def self.timeout_message
end

Non-goals

The fixture TSVs under plugins/os-sdlc/tests/fixtures/crc_shares/run2/ are a record of run 2. They keep the name TimedLspClient.

Origin

  • Trigger: os-sdlc CRC run 3, structure-ruling wave step 1, close row C1 (bin/crc-cycle-edges after the lopsided cuts S1 to S8)
  • Improvised this session: none
  • Chain: concept cycle Daemon <-> TimedLspClient ← daemon/navigation.rb:17 and timed_lsp_client.rb:26 ← DESIGN (docs/crc/os-sdlc/wave0/structure-rulings.tsv S9)
  • Root candidate: none found; searched TimedLspClient, LspTimeoutError, Daemon timeout, lsp-probe timeout, time limit
  • Where: plugins/os-sdlc/lib/os_sdlc/timed_lsp_client.rb
  • Ledger: docs/crc/os-sdlc/ledger.tsv
  • Rulings: docs/crc/os-sdlc/wave0/structure-rulings.tsv
  • Session: 2e167079-f404-4139-9cfa-6c0c937ce9f0
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-crc-os-sdlc-run-3/2e167079-f404-4139-9cfa-6c0c937ce9f0.jsonl

VERDICT: CREATE

## Problem `OsSdlc::TimedLspClient` wraps `Daemon.connect` and applies a 60 s caller-side time limit to each LSP query. `Daemon::Navigation` holds `TimedLspClient`, and `TimedLspClient` holds `Daemon`, so the two form a concept cycle. The 60 s limit and its message also have two owners: `TimedLspClient` (timed_lsp_client.rb:7, 26-34) and `Daemon::LspSession` (daemon/lsp_session.rb:10, 103-109). Ruling S9 gives the caller-side limit to Daemon and deletes the wrapper. ## Reproduce n/a: structure-wave cut, nothing to reproduce ## Approach `Daemon` gains the four query class methods that `TimedLspClient` has today. `Daemon` owns one limit constant and one message, and `Daemon::LspSession` uses them. Required work: 1. Add `Daemon.definitions(at:, root:, config:)`, `Daemon.references(at:, root:, config:)`, `Daemon.symbols(name:, root:, config:)` and `Daemon.outline(path:, root:, config:)` to `plugins/os-sdlc/lib/os_sdlc/daemon.rb`. Each connects with `Daemon.connect` and runs its query inside `Timeout.timeout(QUERY_SECONDS, LspTimeoutError, ...)`, as `TimedLspClient.run` does today. — check: present `QUERY_SECONDS = 60` in `plugins/os-sdlc/lib/os_sdlc/daemon.rb` 2. `Daemon::LspSession#with_timeout` and `#timeout_message` use the `Daemon` constant and message. Delete `LspSession::TIMEOUT_SECONDS`. — check: absent `TIMEOUT_SECONDS` in `plugins/os-sdlc/lib/os_sdlc/daemon/lsp_session.rb` 3. Change the default `:server` in `plugins/os-sdlc/lib/os_sdlc/daemon/navigation.rb:17` and the default `runner:` in `plugins/os-sdlc/lib/os_sdlc/evidence/probe/lsp.rb:7` to `Daemon`. — check: absent `TimedLspClient` in `plugins/os-sdlc/lib/**/*.rb` 4. Delete `plugins/os-sdlc/lib/os_sdlc/timed_lsp_client.rb`. ## Acceptance criteria 1. Given the suite, when run after the change, then it passes with no new failures. 2. Given the lib tree, when `bin/crc-cycle-edges` runs, then no cycle edge lists `timed_lsp_client.rb` or `daemon/navigation.rb:17`. 3. Given an LSP query that runs over 60 s, when it runs through `Daemon.definitions`, then it raises `LspTimeoutError` with the message `lsp-probe: ruby-lsp did not respond within 60s`. ## Owner sketch ```ruby class OsSdlc::Daemon QUERY_SECONDS = 60 def self.definitions(at:, root:, config:) def self.references(at:, root:, config:) def self.symbols(name:, root:, config:) def self.outline(path:, root:, config:) def self.timeout_message end ``` ## Non-goals The fixture TSVs under `plugins/os-sdlc/tests/fixtures/crc_shares/run2/` are a record of run 2. They keep the name `TimedLspClient`. ## Origin - Trigger: os-sdlc CRC run 3, structure-ruling wave step 1, close row C1 (bin/crc-cycle-edges after the lopsided cuts S1 to S8) - Improvised this session: none - Chain: concept cycle Daemon <-> TimedLspClient ← daemon/navigation.rb:17 and timed_lsp_client.rb:26 ← DESIGN (docs/crc/os-sdlc/wave0/structure-rulings.tsv S9) - Root candidate: none found; searched TimedLspClient, LspTimeoutError, Daemon timeout, lsp-probe timeout, time limit - Where: plugins/os-sdlc/lib/os_sdlc/timed_lsp_client.rb - Ledger: docs/crc/os-sdlc/ledger.tsv - Rulings: docs/crc/os-sdlc/wave0/structure-rulings.tsv - Session: 2e167079-f404-4139-9cfa-6c0c937ce9f0 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-crc-os-sdlc-run-3/2e167079-f404-4139-9cfa-6c0c937ce9f0.jsonl VERDICT: CREATE
Author
Owner

Work started on branch crc-os-sdlc-run-3 (crc run 3 worktree), structure-change map.

Work started on branch crc-os-sdlc-run-3 (crc run 3 worktree), structure-change map.
Author
Owner

Resolution

Done: Daemon owns the caller-side LSP time limit: QUERY_SECONDS, the four query class methods and timeout_message live in Daemon; LspSession uses them; TimedLspClient is deleted; navigation and evidence probe default to Daemon.

Evidence: Commit ed849be6 on branch crc-os-sdlc-run-3, implementation 87, structure-change map; gate green (required-work, lint, suite, unchanged), 1 dispatch, 3 min 15 s.

Follow-ups: none

## Resolution **Done:** Daemon owns the caller-side LSP time limit: QUERY_SECONDS, the four query class methods and timeout_message live in Daemon; LspSession uses them; TimedLspClient is deleted; navigation and evidence probe default to Daemon. **Evidence:** Commit ed849be6 on branch crc-os-sdlc-run-3, implementation 87, structure-change map; gate green (required-work, lint, suite, unchanged), 1 dispatch, 3 min 15 s. **Follow-ups:** none
jared closed this issue 2026-10-19 22:25:46 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#1175
No description provided.