You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a persisted knowledge-graph layer to the code-search corpus: typed, raw (unresolved) call/import edges with enclosing-symbol attribution, extracted by the existing tree-sitter walk for all 7 supported languages, stored in Lakebase, resolved at query time into ranked candidate sets, and exposed to agents via new find_references / list_imports MCP tools with Web UI parity.
Why now
Lexical, symbol, and semantic retrieval are solid, but agents cannot ask structural questions: who calls this, what imports that, which function contains this call site. A 3-lane deep-dive trace confirmed zero relationship data exists anywhere in the schema or indexer today, and that the wedge — typed edges, enclosing-symbol attribution, and a queryable import graph — is inexpressible via composed search_code + sym:.
Design decisions (deep-dive, probe-validated)
Raw edges, query-time resolution. Edges store (repo, file, enclosing symbol, target_name, kind, line) — never a resolved cross-file symbol_id FK. Resolution happens per query via name-join against symbols (same-repo preferred). Cross-repo staleness becomes structurally impossible; edges inherit the existing per-file delete-and-reinsert lifecycle.
Candidate-set semantics (grep, not LSP). Live probe on 30,406 call sites (this repo + flask + requests + fastapi): 28.8% unique / 33.4% ambiguous (shallow: 2–31 candidates) / 37.8% external. Tools return ranked candidate sets and say so in their docstrings.
Typed edge tables, native Postgres. Apache AGE is not on Lakebase's curated extension list; no graph extension, no generic nodes/edges JSONB.
Tier A (1-hop) only. Multi-hop (blast radius, call hierarchy, path-between) is a follow-up epic; the schema must not preclude it.
Dedicated MCP tools, not query atoms. Reference lists with enclosing symbols mismatch the file-grouped-line-matches envelope (list_repos/get_file boundary precedent). callers: atoms may be revisited later.
Extraction cost is proven cheap: +12% of parse+walk on the Python probe.
Edge rows follow the per-file delete-and-reinsert lifecycle inside the existing indexing transaction (pure DML, no network) and are swept with branch/orphan reconciliation.
No cross-file or cross-repo symbol_id FK is ever persisted at extraction time.
Tool payloads use the established contract: recoverable conditions are structured fields (truncated, truncation_reason, …), never exceptions; ordering is deterministic; branch scoping is byte-identical to search_code's default-branch coalesce.
The lexical query parser/grammar is untouched in this epic.
INDEX_SEMANTICS_VERSION is bumped deliberately (once, or once per staged language batch) so the CAS skip logic forces re-extraction.
Acceptance criteria
Raw-edge table(s) migrated; app SP SELECT / job SP DML verified on a fresh deploy without manual grant re-application (or the runbook documents the required step).
Typed call and import edges with enclosing-symbol attribution emitted for Python, JS, TS, TSX, Go, Java, Rust, with per-language fixtures.
find_references and list_imports MCP tools return ranked candidate sets with enclosing symbols, honor branch scoping, truncation flags, and deterministic ordering.
"What tests cover symbol X" works as a documented, tested composition (find_references + path filter).
Web UI parity via shared app/service.py builders.
Resolution-quality distribution measured on the indexed corpus and recorded against the probe baseline.
Indexing-time overhead of edge extraction ≤ ~15% of parse+walk.
Summary
Add a persisted knowledge-graph layer to the code-search corpus: typed, raw (unresolved) call/import edges with enclosing-symbol attribution, extracted by the existing tree-sitter walk for all 7 supported languages, stored in Lakebase, resolved at query time into ranked candidate sets, and exposed to agents via new
find_references/list_importsMCP tools with Web UI parity.Why now
Lexical, symbol, and semantic retrieval are solid, but agents cannot ask structural questions: who calls this, what imports that, which function contains this call site. A 3-lane deep-dive trace confirmed zero relationship data exists anywhere in the schema or indexer today, and that the wedge — typed edges, enclosing-symbol attribution, and a queryable import graph — is inexpressible via composed
search_code+sym:.Design decisions (deep-dive, probe-validated)
(repo, file, enclosing symbol, target_name, kind, line)— never a resolved cross-filesymbol_idFK. Resolution happens per query via name-join againstsymbols(same-repo preferred). Cross-repo staleness becomes structurally impossible; edges inherit the existing per-file delete-and-reinsert lifecycle.list_repos/get_fileboundary precedent).callers:atoms may be revisited later.Delivery sequence
Non-negotiable correctness rules
symbol_idFK is ever persisted at extraction time.truncated,truncation_reason, …), never exceptions; ordering is deterministic; branch scoping is byte-identical tosearch_code's default-branch coalesce.INDEX_SEMANTICS_VERSIONis bumped deliberately (once, or once per staged language batch) so the CAS skip logic forces re-extraction.Acceptance criteria
callandimportedges with enclosing-symbol attribution emitted for Python, JS, TS, TSX, Go, Java, Rust, with per-language fixtures.find_referencesandlist_importsMCP tools return ranked candidate sets with enclosing symbols, honor branch scoping, truncation flags, and deterministic ordering.app/service.pybuilders.Out of scope
callers:-style query-grammar atoms.References
.omc/specs/deep-dive-code-search-knowledge-graph.md.omc/specs/deep-dive-trace-code-search-knowledge-graph.md