Resolver precision release. Resolved-relationship counts drop across the board, and the drop is the fix: method-call edges that resolve now target the call site's actual receiver, method calls whose receiver type cannot be named return nothing instead of a guess, and resolution output is deterministic run to run. On the recall side, Python imports resolve across package boundaries and re-exports, and super() calls resolve to the parent's method instead of the caller's own override.
Breaking Changes
- Resolved-relationship counts drop across indexed codebases. The resolver previously picked the first same-name candidate for method calls with unknown receiver types; those calls now return unresolved. Import, inheritance, and function-call edges keep their semantics. Cached counts will not match.
- Full rebuild required (
rm -rf .codanna && codanna init && codanna index <root>, or--force). Mandatory for watcher-served indexes: through 0.9.22 the watcher's single-file path never persisted id counters, so each watch-triggered reindex could mint duplicatesymbol_ids. Rebuilding with 0.9.23 corrects existing duplicate ids; the atomic counter commit prevents recurrence. Also rebuild-not-migrate:scope_contextvalues written by older versions read as no-scope-info, and Python imports and method names index differently (see Added). - CLI
--json: ambiguous symbol names return anINVALID_QUERYenvelope with the candidate list and exit 2, replacing aggregation across same-named symbols; backend query failures returnINDEX_ERRORand exit 2 instead of an empty result. LanguageBehavior::resolve_method_callremoved (no remaining call path). External implementors drop their overrides.indexing.project_rootconfig field removed; it was never read.
Added
- Python package-level import graph: relative imports normalize to absolute form at parse time; re-exports (explicit, aliased,
import *) resolve through__init__to the definition site; class inheritance emitsExtendsedges (previously mis-emitted asImplements); methods index under bare names, withClass.methoddotted lookup now a query-layer feature across all languages. super()calls resolve to the parent class's directly-declared member: single hop through theExtendsedge in base-list order; no parent declaring the member yields no edge rather than a guess.dump_edgesexample binary: full edge dumps for run-to-run diffing;--dupslists everysymbol_idwith more than one indexed doc.- Deletion-only indexing runs report
Removed N deleted file(s), M symbol(s) from index;Index up to datenow means no changes in either direction.
Changed
- Symbol cards request one context set on every surface (implementations, definitions, callers, extends, uses): CLI
find_symbol --json,semantic_search_with_context, MCPfind_symbol,retrieve_symbol,retrieve_search.extends/extended_by/usespreviously rendered null on the CLI and retrieve paths. - Resolution is order-independent: candidate lists sort by identity (file path, line, id), not session insertion order; repeated runs over the same tree produce identical edge sets.
- One resolution policy for MCP text and CLI JSON: symbol lookup (refuse-and-list on ambiguity), the
SymbolKindvocabulary, and receiver formatting are a shared service (src/mcp/service.rs). - Module decomposition:
src/indexing/pipeline/split by responsibility withrun_phase1as the single Phase 1 orchestrator;tantivy.rssplit into schema/codec/writer/query;config.rsandmcp/mod.rssplit likewise. - Hot paths move and borrow instead of cloning;
CompactStringbacks its alias withArc<str>. rmcp1.7 -> 2.1: model types align with the MCP 2025-11-25 spec revision; tool results carry specContentBlockvalues (wire format for text content unchanged; MCP text and CLI outputs byte-identical). Logging notifications keep emitting for client compatibility; the spec deprecates them under SEP-2577.tower-http0.6 -> 0.7; patch/minor bumps acrossanyhow,bitflags,chrono,console,ignore,indicatif,memmap2,rand,regex,rustls,sysinfo,tree-sitter,tree-sitter-swift.
Fixed
- Method calls on receivers whose type is neither inferred nor indexed fail closed instead of resolving by insertion order.
- Call sites attribute to the enclosing same-name symbol, so a test stub no longer absorbs the real function's callers.
- Import-path matching respects segment boundaries (
crate::widgetsno longer matchescrate::widget); same-module checks bound their prefix match to the caller language's separator, closing private-symbol leaks across string-prefix sibling modules. - Batch-incremental indexing resolves against the persisted index; edges through an unchanged re-export survive consumer-only changes.
- Module paths resolve for out-of-tree indexed roots; TS/JS resolver-provider config lookup keys on absolute file path.
- Id counters commit atomically with their docs on rolling commits, final commits, and the watcher single-file path.
find_symbolandanalyze_impactheaders render from the name-matched doc, keeping each row self-consistent even against an index carrying duplicate ids.scope_contextpersists as JSON via serde, replacing a Debug-string scrape that silently decoded most parent kinds to none.- Embedding pool acquire is bounded (60s, then a
PoolExhaustederror) instead of blocking forever; checked-out instances release on drop, panic-safe; the embed fan-out runs on a dedicated rayon pool. - Semantic saves stage to a temp path and rename into place; vector storage drops its mmap before writing the backing file; Tantivy rolls back on cleanup errors instead of half-committing.
codanna servelock acquisition race closed; the lock releases beforeprocess::exit.- Panicked read workers and failed symbol writes surface as indexing errors instead of being swallowed.
- Profile rollback failures propagate instead of being discarded.
- Config guidance templates and variables serialize in insertion order.
Removed
- Dead code with no callers:
SymbolStore,IndexTransaction,ResolutionMemo, unused vector wiring.