Documentation
¶
Overview ¶
Package ranking provides query-weighted PageRank over the code graph.
Motivation: structural search (search_graph) and semantic search (find_similar_functions) surface candidates, but they don't rank by relevance to a query the way an agent needs for context assembly. PageRank with query-seeded personalization fills that gap — given a natural-language query, it returns the top-K graph entities most relevant to feed into an LLM's context window, typically reducing context tokens by 3-5x vs dumping the full graph.
Algorithm: bidirectional weighted PageRank with personalization.
- Seed nodes are matched from the query via name + qualified-name tokens (simple tokenizer; embedding-augmented seeds are a future extension).
- Forward PageRank: column-stochastic transition matrix over outbound edges; propagates rank from seeds to nodes they reference.
- Reverse PageRank: same graph with edges reversed; propagates rank from seeds back to nodes that reference them.
- Final score: sum of forward + reverse. Bidirectional fixes the pure-source-collapse behavior that single-direction PageRank exhibits (sources with no inbound personalization go to 0).
Reference: Aider's repo-map (https://aider.chat/2023/10/22/repomap.html) pioneered PageRank over tree-sitter tags as an agent-context primitive. code-review-graph (github.com/tirth8205/code-review-graph) reports 6.8x token reduction with the same pattern.
Index ¶
- func MatchSeedNodes(st *store.Store, project, query string) ([]*store.Node, error)
- func MatchSeedNodesByEmbedding(ctx context.Context, st *store.Store, project, query string) ([]*store.Node, error)
- func MatchSeedNodesByStrategy(ctx context.Context, st *store.Store, project, query string, ...) ([]*store.Node, error)
- func MatchSeedNodesHybrid(ctx context.Context, st *store.Store, project, query string) ([]*store.Node, error)
- func SeedMatchScore(node *store.Node, query string) float64
- type RankedNode
- type SeedStrategy
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MatchSeedNodes ¶
MatchSeedNodes returns the seed nodes for a query — the subset of project nodes whose Name exactly matches any query token (case- insensitive) or whose QualifiedName contains any token (case- insensitive substring). Used by callers that need just the seeds without running the full PageRank propagation (e.g., the localize package's BFS-from-seeds pattern).
Returns the seed nodes themselves, not their indices. Empty slice if no node matched any token.
func MatchSeedNodesByEmbedding ¶
func MatchSeedNodesByEmbedding(ctx context.Context, st *store.Store, project, query string) ([]*store.Node, error)
MatchSeedNodesByEmbedding returns the top-K nodes whose embeddings are most cosine-similar to the embedded query. Returns an error wrapping ErrEmbeddingsUnavailable if VOYAGE_API_KEY is not set or the project has no embeddings populated.
func MatchSeedNodesByStrategy ¶
func MatchSeedNodesByStrategy(ctx context.Context, st *store.Store, project, query string, strategy SeedStrategy) ([]*store.Node, error)
MatchSeedNodesByStrategy dispatches to the requested seed strategy. Empty/unknown strategy defaults to hybrid.
Phase B (2026-05-07): when a caller explicitly requests SeedStrategySubstring AND embeddings are available (project has a non-zero embedding count), we route to hybrid instead. Substring on a project with embeddings consistently surfaces PageRank-propagation noise (`Result`, `IntoHandlerError`, `AsCheckOpResult` from cradlepoint-seeded callers) — D1 word-boundary closed seed pollution but did not address propagation pollution. Hybrid's embedding- dominance threshold (>=3 embeddings → drop substring entirely) was measured 10/10 relevant on the same query that produced 4/10 noise on substring. Routing substring callers through hybrid when embeddings are present is strictly an improvement; substring stays available as the explicit fallback when no embeddings exist.
func MatchSeedNodesHybrid ¶
func MatchSeedNodesHybrid(ctx context.Context, st *store.Store, project, query string) ([]*store.Node, error)
MatchSeedNodesHybrid runs both substring and embedding matching and merges the results.
Behavior (D1, 2026-05-07):
- If embedding returns ≥hybridEmbeddingDominanceThreshold seeds, drop substring seeds entirely. The strong embedding signal is a better intent match; substring at that point is mostly noise.
- Otherwise, merge: substring seeds first (preserving exact- identifier match priority), embedding seeds appended.
If embedding match fails (e.g., no VOYAGE_API_KEY or no embeddings), returns substring-only results with no error — graceful degradation is more useful than a hard failure for callers who don't know the project's embedding state in advance.
func SeedMatchScore ¶
SeedMatchScore preserves lexical seed quality when downstream graph traversal assigns its personalization weights. Exact-name matches retain precedence over qualified-name-only matches, while nodes matching more independent query tokens receive more weight. Embedding-only seeds receive the neutral score 1.
Types ¶
type RankedNode ¶
type RankedNode struct {
ID int64 `json:"id"`
Label string `json:"label"`
Name string `json:"name"`
QualifiedName string `json:"qualified_name"`
FilePath string `json:"file_path"`
Score float64 `json:"score"`
}
RankedNode is one entry in the RankByQuery result.
func RankByQuery ¶
RankByQuery computes query-weighted bidirectional PageRank over the project graph and returns the top-K nodes by relevance, using the substring seed strategy (legacy default — kept for backward compat).
New callers should prefer RankByQueryWithStrategy for the choice of substring / embedding / hybrid seed matching.
The topK parameter is clamped to [1, 200]. The returned slice is sorted by descending score.
func RankByQueryWithStrategy ¶
func RankByQueryWithStrategy(ctx context.Context, st *store.Store, project, query string, topK int, strategy SeedStrategy) ([]RankedNode, error)
RankByQueryWithStrategy is RankByQuery with explicit seed-strategy selection (substring, embedding, or hybrid). Hybrid is the recommended default — it merges substring + embedding seeds, falling back to substring-only if embeddings are unavailable.
type SeedStrategy ¶
type SeedStrategy string
SeedStrategy controls how query → seed-node matching is performed.
const ( // SeedStrategySubstring is the original behavior: tokens substring-match // node Name/QualifiedName. Cheap, no API call, deterministic. Best for // queries that contain known identifiers. SeedStrategySubstring SeedStrategy = "substring" // SeedStrategyEmbedding embeds the query via Voyage and cosine-searches // against pre-computed node embeddings. Requires VOYAGE_API_KEY at query // time and embeddings populated at index time. Best for natural-language // queries that describe intent rather than name symbols. SeedStrategyEmbedding SeedStrategy = "embedding" // SeedStrategyHybrid runs both and merges the results, deduplicated. The // default; gives the union of identifier-exact and intent-similar matches. SeedStrategyHybrid SeedStrategy = "hybrid" )