Phase 1: structural-parity query tools (no LLM)¶
Date: 2026-06-09 Status: design Repos: tatara-memory (pgstore + service + httpapi), tatara-cli (MCP tools) Depends on: Phase 0 (shipped) - confidence columns, line_start/end columns.
Goal¶
Close the read-side graphify gaps that need NO LLM and NO analytics job - they run on the AST data + Phase-0 columns already in prod. Gives agents shortest paths, importance ranking, corpus stats, confidence-filtered traversal, ranked search, and explain-in-context. Pure query surface; no schema change, no ingest change.
Design decisions (picked)¶
- Ranked search without pg_trgm. cnpg's
appuser cannotCREATE EXTENSION, and pg_trgm is not installed. Rank with a deterministic CASE expression (exact name = 0, name prefix = 1, name substring = 2, description substring = 3), tie-broken by name. Zero infra dependency. (pg_trgm fuzzy ranking is a noted future enhancement, not now.) - Degree on-the-fly.
code_important(by=degree)computes degree as a SQL aggregate overcode_edges(in+out). The reservedcode_entities.degreecolumn stays empty until the Phase-2 analytics job persists it (betweenness needs that job; degree ships now cheaply). - Confidence filter is opt-in. New optional
min_confidence(float) andtier(string) params default to no filtering, so existing callers are unchanged.
Components¶
tatara-memory¶
All additions are read-only PGStore methods + Service passthroughs + httpapi routes. Follow existing patterns (recursive CTE traversal, EntityDetail/ PathNode result types).
-
ShortestPath -
PGStore.ShortestPath(ctx, repo, fromID, toID, relations []string, maxDepth int) ([]Entity, error). Recursive CTE fromfromIDfollowingcode_edges(optionally filtered torelations), carrying the path as an array, stopping whentoIDis reached;ORDER BY array_length LIMIT 1. Returns the ordered entity chain (empty slice if unreachable within maxDepth, not an error). RouteGET /code-graph/path?repo=&from=&to=&relations=&max_depth=. -
ImportantEntities -
PGStore.ImportantEntities(ctx, repo string, limit int) ([]EntityDegree, error)whereEntityDegree { Entity; Degree int }.SELECT e.*, (in+out edge counts) AS degree FROM code_entities e ... GROUP BY ... ORDER BY degree DESC LIMIT. RouteGET /code-graph/important?repo=&limit=. -
Stats -
PGStore.Stats(ctx, repo string) (GraphStats, error)whereGraphStats { Entities int; Edges int; EntitiesByType map[string]int; EdgesByRelation map[string]int; EdgesByTier map[string]int; IsolatedEntities int; ImportCycles int }. Counts via GROUP BY; isolated = entities with no edges (NOT IN src/dst); import cycles via a recursive CTE overimportsedges detecting a back-edge to the start. RouteGET /code-graph/stats?repo=. -
AmbiguousEdges -
PGStore.AmbiguousEdges(ctx, repo string, limit int) ([]Edge, error).WHERE confidence_tier='AMBIGUOUS' OR confidence_score <= 0.3 ORDER BY confidence_score. RouteGET /code-graph/ambiguous?repo=&limit=. -
Confidence-filtered traversal. Add optional
minConfidence float64andtier stringto the existing neighbor/caller/callee/dependency walk methods. When set, the recursive CTE's edge join addsAND (e.confidence_score >= $minConf) AND ($tier='' OR e.confidence_tier=$tier). Default zero-value = no filter (existing behavior). Thread through service + httpapi as optional query params. -
Ranked SearchEntities. Change the
ORDER BY nameinSearchEntities(pgstore.go:175) to the CASE relevance order above, still honoring thetypefilter andlimit. No signature change. -
EntityExplain -
PGStore.EntityExplain(ctx, repo, id string) (EntityExplain, error)whereEntityExplain { EntityDetail; OutNeighbors []Entity; InNeighbors []Entity }- the entity, its in/out edges (existingEntityDetail), PLUS the joined neighbor entities (id/name/type/file_path/ line_start/line_end) so an agent gets labels + citations in one call. RouteGET /code-graph/explain?repo=&id=. (Leavescode_entityunchanged; explain is the enriched variant.)
tatara-cli (MCP tools)¶
Add to internal/mcp/tools.go OperatorTools()/code tool group (these are memory-target code_* tools). Each maps to a memory route above. JSON schemas follow the existing code_* style.
code_path(from, to, relations?, max_depth?) -> /code-graph/pathcode_important(repo?, limit?) -> /code-graph/importantcode_stats(repo?) -> /code-graph/statscode_ambiguous_edges(repo?, limit?) -> /code-graph/ambiguouscode_explain(id, repo?) -> /code-graph/explain- Extend
code_neighbors/code_callers/code_callees/code_dependencies/code_dependentsschemas with optionalmin_confidence(number) andtier(string) params, forwarded as query params. code_searchgains no new params (ranking is server-side); behavior improves.
These are additive; the contract_shape_test / tool-count tests update to the new totals.
Error handling¶
- Unknown entity id (path/explain): 404 from memory, surfaced as a clean tool error. Unreachable path: 200 with empty chain (not an error).
- Bad
tiervalue: ignored (treated as no tier filter) - or validated to the 3 tiers; pick validation with a 400 to avoid silent no-op. Validate.
Testing (TDD)¶
- memory: integration tests (skip without DSN) for each query: a small seeded graph asserts ShortestPath returns the chain and
[]when unreachable; ImportantEntities orders by degree; Stats counts + isolated + one import cycle; AmbiguousEdges filters by tier/score; confidence-filtered traversal drops low-confidence edges; ranked SearchEntities orders exact-before-substring; EntityExplain returns neighbor labels + line ranges. Plus unit tests for the SQL-builder helpers where pure. - cli: tool-build + Invoke tests (httptest memory) for each new tool and the new confidence params, matching existing
tools_test.gostyle; tool-count tests updated.
Build / deploy¶
memory image + chart bump (no migration - query-only, so a patch bump, e.g. 0.2.6); cli image bump (e.g. 0.4.4) - rebuild wrapper to bundle it. Infra: bump memoryImage pin; cli reaches agents via the wrapper image (rebuild + Project agent.image bump). No CRD/schema change.
Out of scope (Phase 2)¶
Betweenness/community/centrality persistence + the analytics job; LLM semantic edges/hyperedges; pg_trgm fuzzy search.