feat: persist precise (LSP) call resolution — pass-2 (stacked on #165) - #167
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (17)
📝 WalkthroughSummaryUser-visible / Reviewer-relevant changes:
Risks:
Deferred validation:
Package-boundary / schema impact:
WalkthroughAdds a second pass of precise (language-server) call-site resolution to Dextree. Introduces storage contracts, persistence functions, indexer implementation, and a cancellable VS Code command that upgrades persisted heuristic CALLS edges to precise tier using LSP-backed results. ChangesPrecise edge resolution system
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Adds the core half of persisted precise call resolution (the unbuilt 'pass-2 LSP fills them in' the edge schema references). New GraphRepository methods: - getUnresolvedCallSites(workspaceRoot): CALLS edges not yet precise, each with the source symbol's NodeLocation (file + start line/col) for the LSP query - findSymbolIdAt(filePath, line): map an LSP result location back to a stored target symbol id (file + start line; null on no/ambiguous match) - persistPreciseEdges(resolutions): set target_id + stamp metadata.resolution='precise' (confidence 1.0) in one transaction Implemented in storage/preciseResolution.ts (behind the adapter) + the in-memory FakeGraphRepository (with a seedCallSite test helper). The existing stampResolutionTier already guards <> 'precise', so precise edges are never downgraded — proven by test. Real-DuckDB tests cover list/match/persist, idempotency, and no-downgrade. core 279/279. Refs: #166
Wires the pass-2 precise resolution end to end. New Indexer.resolvePreciseEdges
(workspaceRoot, resolver, {onProgress, isCancelled}) orchestrates the core loop:
work-list (getUnresolvedCallSites) → host resolver per site → match each result
back to a target (findSymbolIdAt) → batch persist (persistPreciseEdges). The host
owns only the LSP resolver (RULE-ARCH-005); all DB access stays behind the
repository.
Extension: createResolvePreciseEdgesCommand runs the pass under a cancellable
withProgress notification (reports N/M sites · K upgraded) and refreshes the graph
on finish. Registered as dextree.resolvePreciseEdges / 'Resolve Precise Edges
(LSP)' in activate + package.json.
Behavior-preserving + opt-in: nothing runs unless invoked; idempotent (precise
edges drop out of the work-list); graceful (cold/empty resolver leaves edges
heuristic); cancellable (persists partial). Integration tests against a real
in-memory DB cover upgrade, idempotency, cold resolver, and cancellation; command
tests cover the UI shell. Indexer mocks across extension tests gained the method.
core 282 / exporters 161 / extension 643.
Refs: #166
c138bc1 to
069d605
Compare
Summary
Builds pass-2 precise resolution — the persisted half of the LSP tier. dextree
already resolves precise callers/callees via the user's language server, but only
live, per selected node; the result was never written to the
edgetable, so thewhole projected graph stayed
heuristic. This is the depth gap behind "a graph-DBindexer projects more than us": SCIP/graph-DB tools persist semantic edges. The
edge.target_idschema comment already said "pass-2 LSP fills them in" — thisfills them in.
A new opt-in command, Dextree: Resolve Precise Edges (LSP), runs a
workspace-wide pass: enumerate heuristic/unresolved
CALLSsites → ask the LSP ateach source location → match the result back to a stored symbol → persist
target_id+metadata.resolution='precise'. The whole graph then projectsprecise.
Linked spec / issue
openspec/changes/precise-resolution/(OpenSpec change; openspec/ is gitignored)Affected surfaces
packages/core(interface + adapter + fake + indexer orchestration + types)packages/extension(command + wiring + Indexer mocks)Commits
823e2edcore write path —GraphRepository.getUnresolvedCallSites/findSymbolIdAt/persistPreciseEdgesinstorage/preciseResolution.ts+FakeGraphRepository; real-DuckDB tests (list/match/persist, idempotent, no-downgrade)c138bc1orchestration + command —Indexer.resolvePreciseEdges(workspaceRoot, resolver, {onProgress, isCancelled})runs the loop;createResolvePreciseEdgesCommanddrives it under a cancellable
withProgress; registered in activate + package.json;integration + command tests
How it stays safe
stampResolutionTieralreadyguards
<> 'precise', so a heuristic re-stamp never downgrades them (proven by test).[]) or an unmatched locationleaves the edge heuristic; the pass reports upgraded-vs-total.
through
GraphRepository(RULE-ARCH-003/010).Test plan
pnpm checkgreen across all packages: core 282, exporters 161, extension 643re-run shrinks the work-list (idempotent); cold resolver upgrades 0; cancellation
persists partial
stampResolutionTierproven by testOut of scope (follow-ups)
scipIngest.ts), not wired here.🤖 Generated with Claude Code