fix(lsp-status): unify --lsp-status flag and lsp-status subcommand payload (issue #33)#87
Merged
Merged
Conversation
…yload (issue #33) Both entry points now delegate to hybrid_engine.get_lsp_status() (single source of truth). Previously --lsp-status called get_lsp_status() while lsp-status called detect_available_servers() directly, producing structurally different payloads for what the docs treat as the same operation. The MCP server (which only exposes the subcommand) got the smaller payload, so CLI users and MCP agents saw different 'truths'. Also fixes a pre-existing determinism bug in detect_available_servers(): extensions was list(set) which varies across Python invocations due to hash randomization. Now sorted, so the repro diff is byte-identical. Chose Option B over Option A (issue suggested A is 'more recommended') because the DoD explicitly requires both entry points to produce byte-identical output (repro diff exit code 0) AND a test asserting 'both entry points have the same top-level keys' — both DoD items are unsatisfiable if the top-level flag is removed entirely. Option A's architectural concern (single source of truth) is preserved by routing both entry points through the same backend function. Files changed: - scripts/commands/lsp_status.py: delegate to hybrid_engine.get_lsp_status() - scripts/lsp_client.py: sort extensions for deterministic output - SKILL-QUICK.md: document both entry points in trigger map - CHANGELOG.md: add issue #33 entry - tests/test_cli.py: new TestLspStatusEntryPointParity class (3 tests) Closes #33.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
# Conflicts: # tests/test_cli.py
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Fixes #33.
codelens --lsp-status(top-level flag,scripts/codelens.pyL829-837) andcodelens lsp-status(subcommand,scripts/commands/lsp_status.py) returned structurally different payloads for what the documentation treats as the same operation. The MCP server (which only exposes subcommands) got the smaller payload, so CLI users and MCP agents saw different "truths" for the same question.Option chosen: B (unify schema, keep both entry points)
The issue suggested Option A is "more recommended" because it removes code duplication. I chose Option B instead, for the following reason:
The issue's own Definition of Done requires:
diff <(...) <(...)command must show IDENTIK output with diff exit code 0Pure Option A (delete the
--lsp-statusinterception entirely) makes the flag invalid ->codelens --lsp-statuswould fail with an argparse "unrecognized arguments" error -> diff exit code != 0 -> DoD #1 unsatisfiable, and DoD #2 untestable (only one entry point would remain).Option B is the only choice consistent with the literal DoD. The architectural concern that motivated Option A (single source of truth / no duplicate logic) is preserved by routing both entry points through the same backend function,
hybrid_engine.get_lsp_status(). There is no duplicate business logic — only a 9-line alias block incodelens.pythat delegates to the same function the subcommand now delegates to.Files changed
scripts/commands/lsp_status.pyexecute()now delegates tohybrid_engine.get_lsp_status()instead of rebuilding a smaller dict fromlsp_client.detect_available_servers(). ImportError fallback updated to match the new richer shape.scripts/lsp_client.pydetect_available_servers()now returnssorted(config["extensions"])instead oflist(config["extensions"])(deterministic across Python invocations;config["extensions"]is asetsolist(set)order depended on hash randomization).SKILL-QUICK.md"LSP servers available?"->lsp-statusentry noting that--lsp-statusis an alias. Setup & Lifecycle command list also documents the alias relationship.CHANGELOG.md[8.2.0] - Unreleased.tests/test_cli.pyTestLspStatusEntryPointParityclass with 3 tests.Note on dead code:
lsp_client.detect_available_servers()is not removed — it is still used byhybrid_engine.HybridEngine.__init__,lsp_client.get_server_for_file, andlsp_client.get_server_for_workspace. It is the low-level building block;get_lsp_status()is the high-level wrapper. Both belong in the architecture.Repro diff (DoD #1)
Before the fix (baseline, on
main):After the fix:
Stable across 5 consecutive runs (hash randomization mitigated by the
sorted()fix indetect_available_servers()):Test run (DoD #2 + DoD #3)
New parity tests
LSP-related test files
(The 1 skip is
test_hybrid_engine.py::TestHybridIntegration::test_deep_with_pyright— skips when pyright isn't installed; pre-existing, unrelated to this change.)Full test suite
PYTHONPATH=scripts python3 -m pytest tests/ -v:mainbaseline (before my changes) — verified bygit stash+ re-run:tests/test_integration.py— hangs indefinitely even on baseline (likely because every test spawns acodelens.pysubprocess and the environment is slow). Not caused by this PR.tests/test_vuln_staleness.py::TestScanVulnerabilitiesCacheInfo::test_vulnerable_app_has_stale_cache_info— fails on baseline because the env's built-in VULN_DB is 486 days old but the test's staleness check returns False (clock/environment issue). Not caused by this PR.TestLspStatusEntryPointParityclass adds 3 new passing tests.Checklist
tests/test_cli.pydetect_available_servers()is still used by 3 other call sites)fix: ...format from CONTRIBUTING.mdCloses #33.