evidence run shares one ruby-lsp session instead of one spawn per gapped method #599

Closed
opened 2026-09-16 19:52:46 +00:00 by jared · 2 comments
Owner

Context

Branch lsp-probe-cli (ADR-0197) added bin/lsp-probe, a Thor CLI that spawns ruby-lsp over stdio per call (lib/os_sdlc/lsp_probe/query_runner.rb:21, Open3.popen3). Measured 2026-09-16: one lsp-probe call 4-9 s; bin/evidence collect --root plugins/os-sdlc/lib Model::Db 209 s because lib/os_sdlc/evidence/fingerprint.rb:83-91 runs one LSP query, and so one spawn, per method with no ast-grep sender.

Owner sketch

class SharedRunner
  def initialize(root:, spawner: ProcessSpawner) = ...
  def references(file:, line:, col:) = session.request(...)
  def symbols(name:) = ...
  def close = session.shutdown
  private def session = @session ||= @spawner.open(root: @root)
end

Cases

  • Two references calls on one SharedRunner spawn ruby-lsp exactly once (spawner double counts opens).
  • Fingerprint#sender_rows on a class with two gapped methods constructs one SharedRunner and calls close once after the map.
  • close on a SharedRunner that never opened a session is a no-op.
  • Existing tests/lsp_probe_bin_test.rb and evidence tests stay green.

Origin

  • Trigger: evidence performance audit 2026-09-16
  • Improvised this session: none
  • Chain: 209s collect run ← per-method spawn ← no session reuse in QueryRunner
  • Root candidate: n/a
  • Where: lib/os_sdlc/lsp_probe/shared_runner.rb
  • Session: 01153d94-6459-43dc-bd20-e68b757af56f
  • Transcript: https://claude.com/claude-code
## Context Branch lsp-probe-cli (ADR-0197) added bin/lsp-probe, a Thor CLI that spawns ruby-lsp over stdio per call (lib/os_sdlc/lsp_probe/query_runner.rb:21, Open3.popen3). Measured 2026-09-16: one lsp-probe call 4-9 s; `bin/evidence collect --root plugins/os-sdlc/lib Model::Db` 209 s because lib/os_sdlc/evidence/fingerprint.rb:83-91 runs one LSP query, and so one spawn, per method with no ast-grep sender. ## Owner sketch ```ruby class SharedRunner def initialize(root:, spawner: ProcessSpawner) = ... def references(file:, line:, col:) = session.request(...) def symbols(name:) = ... def close = session.shutdown private def session = @session ||= @spawner.open(root: @root) end ``` ## Cases - Two `references` calls on one SharedRunner spawn ruby-lsp exactly once (spawner double counts opens). - `Fingerprint#sender_rows` on a class with two gapped methods constructs one SharedRunner and calls `close` once after the map. - `close` on a SharedRunner that never opened a session is a no-op. - Existing `tests/lsp_probe_bin_test.rb` and evidence tests stay green. ## Origin - Trigger: evidence performance audit 2026-09-16 - Improvised this session: none - Chain: 209s collect run ← per-method spawn ← no session reuse in QueryRunner - Root candidate: n/a - Where: lib/os_sdlc/lsp_probe/shared_runner.rb - Session: 01153d94-6459-43dc-bd20-e68b757af56f - Transcript: https://claude.com/claude-code
Author
Owner

Work started via os-sdlc pipeline on branch ticket-599 (worktree off lsp-probe-cli). Session 01153d94.

Work started via os-sdlc pipeline on branch ticket-599 (worktree off lsp-probe-cli). Session 01153d94.
Author
Owner

Resolution

Done: Evidence::Fingerprint defaults to LspProbe::SharedRunner over a new LspProbe::OpenSession that spawns ruby-lsp once per run; close after sender_rows. Commit cab8b5ea on branch ticket-599 (merges to lsp-probe-cli). ADR-0198.

Evidence: Pipeline impl 23: 11 dispatches, all cases pass, suite 1269 green, rubocop clean. Measured: evidence collect --root plugins/os-sdlc/lib Model::Db 209 s -> 10.5 s. Hand-finish note: pipeline shipped SharedRunner with a doubled spawner only; the ticket cases were satisfiable by doubles, so behavior-verifier passed without a production spawner. OpenSession + Fingerprint default added by hand.

Follow-ups: One SharedRunner per Fingerprint means a multi-unit evidence run still spawns once per unit; covered by #600 (per-worktree daemon), no new ticket. Case-wording lesson: at least one case per ticket must be un-doublable (a real measurement or an end-to-end CLI run); noted here, not ticketed.

## Resolution **Done:** Evidence::Fingerprint defaults to LspProbe::SharedRunner over a new LspProbe::OpenSession that spawns ruby-lsp once per run; close after sender_rows. Commit cab8b5ea on branch ticket-599 (merges to lsp-probe-cli). ADR-0198. **Evidence:** Pipeline impl 23: 11 dispatches, all cases pass, suite 1269 green, rubocop clean. Measured: evidence collect --root plugins/os-sdlc/lib Model::Db 209 s -> 10.5 s. Hand-finish note: pipeline shipped SharedRunner with a doubled spawner only; the ticket cases were satisfiable by doubles, so behavior-verifier passed without a production spawner. OpenSession + Fingerprint default added by hand. **Follow-ups:** One SharedRunner per Fingerprint means a multi-unit evidence run still spawns once per unit; covered by #600 (per-worktree daemon), no new ticket. Case-wording lesson: at least one case per ticket must be un-doublable (a real measurement or an end-to-end CLI run); noted here, not ticketed.
jared closed this issue 2026-09-16 20:46:25 +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#599
No description provided.