Skip to content

Lazy reference confirmation — restore usages accuracy on demand#266

Merged
zzet merged 1 commit into
mainfrom
feat/lazy-reference-confirmation
Jul 8, 2026
Merged

Lazy reference confirmation — restore usages accuracy on demand#266
zzet merged 1 commit into
mainfrom
feat/lazy-reference-confirmation

Conversation

@zzet

@zzet zzet commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Lazy reference confirmation — restore usages accuracy without the cold-path sweep

Lazy LSP (#265) took enrichment off the cold path but degraded find_usages accuracy — the benchmark caught it: line-recall 1.000 → 0.294 (gin), 0.894 → 0.329 (httpx). The lsp_resolved reference tier those answers rank on was never produced (the on-demand path faulted in semantic_type on reads, not reference edges), so a usages query returned only the resolver's heuristic (ast_inferred) edges — or nothing.

Fix: move the unit of laziness from the whole-repo enrichment pass to one symbol's reference confirmation. A find_usages answer for symbol S needs S's callers confirmed — not the whole repo's.

  • lsp.Provider.ConfirmSymbolRefs(g, repoRoot, node) — the per-symbol unit of the confirm + call-hierarchy sweep: prepares a call hierarchy at the symbol's definition and, for each server-verified incoming call, mints or promotes an lsp_resolved edge via the existing recordHierarchyCall (every correctness rule preserved — callable-kind match, per-site promotion, declaration identity). LSP round-trips unlocked; graph mutations batched under the resolve lock.
  • find_usages / get_callers call it on the target symbol before answering, lazy-spawning the language server through the router (the same path the diagnostics tools use). An in-memory ledger (refsConfirmed) keeps a repeat query free.

Verified

Interface-dispatch Go fixture, indexed with 0 eager LSP passes: the caller useIt → Impl.Greet, which the resolver had only at ast_inferred, is upgraded to lsp_resolved / lsp tier by the on-demand gopls call-hierarchy on the first find_usages, and the promotion persists. go test -race ./internal/mcp/ ./internal/semantic/lsp/ green.

Scope — this is the accuracy-restoring core, not the whole spec

Lands per-symbol confirmation (W2) + an in-memory ledger (W1 MVP). Remaining workstreams from the design: synchronous latency budget + enrichment: pending caveat + background completion (W2/W6), background convergence queue (W4), go-types "earn-the-slot-or-yield" registration gate (W5), durable ledger with edit-invalidation (W1 full), and the full gortex-bench acceptance run (gin/httpx recall fence at default config) — my verification is a mechanism fixture, not the benchmark. Call-hierarchy servers (gopls/pyright/rust-analyzer/
jdtls) are covered; references-only servers are a follow-up branch in ConfirmSymbolRefs.

…ueries

Lazy LSP took enrichment off the cold path but degraded find_usages accuracy:
the lsp_resolved reference tier those answers rank on was never produced, so a
usages query returned only the resolver's heuristic (ast_inferred) edges — or
nothing. The fix moves the unit of laziness from the whole-repo enrichment pass
to one symbol's reference confirmation.

lsp.Provider.ConfirmSymbolRefs(g, repoRoot, node) is the per-symbol unit of the
whole-repo confirm + call-hierarchy sweep: it prepares a call hierarchy at the
symbol's definition and, for each server-verified incoming call, mints or
promotes an lsp_resolved edge via the existing recordHierarchyCall (so every
correctness rule — callable-kind match, per-site promotion, declaration
identity — is unchanged). find_usages and get_callers call it on the target
symbol before answering, lazy-spawning the language server through the router;
an in-memory ledger keeps a repeat query free.

Verified on an interface-dispatch Go fixture indexed with zero eager LSP: a
caller the resolver had only at ast_inferred is upgraded to lsp_resolved/lsp
tier by the on-demand gopls call-hierarchy, and the promotion persists.

Scope: this lands the per-symbol confirmation (W1 in-memory ledger + W2 fault-in
on usages reads). The synchronous-budget/pending-caveat, background convergence,
go-types registration gate, and durable ledger are the remaining workstreams.
@zzet zzet merged commit aea460e into main Jul 8, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant