feat: add optional bounded LSP semantic providers - #2951
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 5 advisory finding(s) below merit a look before merge.
Graphify review — findings
Adds an optional graphify_semantic_providers package that collects bounded, provenance-tagged language-server evidence (symbols, references, call hierarchies) and merges it into a separate graph without touching native AST extraction. Wires up the graphify-semantic CLI (list/run/merge) with an LSP client, provider registry, custom-manifest loading, and env-allowlisted shell=False subprocesses, plus protocol/merge/CLI test suites. Extends CI to lint, type-check, run graphify-semantic list, and bandit-scan the new package, and documents it in docs/SEMANTIC-PROVIDERS.md and the README.
Worth a look
- _run selects providers via registry.for_workspace but registry defines for_path —
graphify_semantic_providers/cli.py:79· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- CLI accepts negative run budgets —
graphify_semantic_providers/cli.py:39· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Forwarded PYTHONPATH makes workspace code importable by providers —
graphify_semantic_providers/lsp.py:53· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Concurrent JSON-RPC requests can consume and drop each other's responses —
graphify_semantic_providers/lsp.py:134· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- JSON-RPC server requests can be mistaken for matching client responses —
graphify_semantic_providers/lsp.py:160· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 160 functions depend on the 160 functions this change touches.
Health — this change adds coupling hotspots:
- new:
run_provider()— 7 callers, 10 callees - new:
main()— 3 callers, 4 callees - new:
_append_symbols()— 1 callers, 8 callees - new:
_run()— 1 callers, 7 callees - new:
_append_calls()— 1 callers, 7 callees - new:
_append_locations()— 1 callers, 7 callees - new:
_merge()— 1 callers, 6 callees
Verification — 160 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 160 function(s) in the blast radius were not formally verified this run
· 7 grounded finding(s) anchored inline below.
| from .registry import ProviderRegistry, builtin_registry | ||
|
|
||
|
|
||
| def main(argv: list[str] | None = None) -> int: |
There was a problem hiding this comment.
main()
high coupling complexity (Ca·Ce = 12).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| return 0 | ||
|
|
||
|
|
||
| def _run(args: argparse.Namespace, registry: ProviderRegistry) -> int: |
There was a problem hiding this comment.
_run()
fans out to 7 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| return 0 if completed or not runs else 1 | ||
|
|
||
|
|
||
| def _merge(args: argparse.Namespace) -> int: |
There was a problem hiding this comment.
_merge()
fans out to 6 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| return result | ||
|
|
||
|
|
||
| def run_provider( |
There was a problem hiding this comment.
run_provider()
fans out to 10 callees (efferent coupling); 7 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| return result | ||
|
|
||
|
|
||
| def _append_symbols( |
There was a problem hiding this comment.
_append_symbols()
fans out to 8 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| ) | ||
|
|
||
|
|
||
| def _append_locations( |
There was a problem hiding this comment.
_append_locations()
fans out to 7 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| return exhausted | ||
|
|
||
|
|
||
| def _append_calls( |
There was a problem hiding this comment.
_append_calls()
fans out to 7 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
Summary
(source_file, label)matchcompleted,unavailable,failed, andbudget_exhaustedoutcomes throughgraphify-semanticCloses #2948.
Related to #2941, which refreshes Graphify's existing semantic pipeline. This PR adds a distinct compiler/language-service evidence source and does not change that pipeline.
Static-analysis findings have different trust semantics and remain outside this PR; the bounded OpenGrep proposal is tracked separately in #2950.
Why
Tree-sitter is the right fast, deterministic baseline, but project-aware language services can resolve facts that syntax alone cannot reliably establish: configured module resolution, references, implementations, overloads, and call hierarchy.
The contribution is deliberately additive:
Safety and failure boundaries
shell=False;budget_exhaustedresult and are never silently expanded;Language servers are trusted external executables and some may invoke project tooling. The guide therefore requires a trusted workspace or an isolated execution environment; this PR does not represent an LSP process as a sandbox.
Provider evidence matrix
The distinction is intentional: a registered/profile-tested provider is not presented as real-tool interoperability proof.
Verification
4833 passed, 51 skipped28 passedruff checkandruff format --check: pass0 errors-ll): no medium/high findingsgraphify update .: completed after the code changesReview notes
This first PR intentionally does not wire providers into
graphify extract, download language servers, run providers automatically, add scanner findings, or alter Graphify's LLM semantic behavior. Those decisions can be made separately after maintainers are comfortable with the evidence contract and execution boundary.