Skip to main content

code_kb_core/
models.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
4pub struct Symbol {
5    pub symbol_id: String,
6    pub file_id: String,
7    pub path: String,
8    pub language: String,
9    pub name: String,
10    pub kind: String,
11    pub signature: Option<String>,
12    pub doc_comment: Option<String>,
13    pub visibility: Option<String>,
14    pub parent_symbol_id: Option<String>,
15    pub start_line: usize,
16    pub start_column: usize,
17    pub end_line: usize,
18    pub end_column: usize,
19    pub start_byte: usize,
20    pub end_byte: usize,
21    pub body_start_line: Option<usize>,
22    pub body_start_column: Option<usize>,
23    pub body_end_line: Option<usize>,
24    pub body_end_column: Option<usize>,
25    pub body_start_byte: Option<usize>,
26    pub body_end_byte: Option<usize>,
27    pub body_hash: Option<String>,
28    pub semantic_group: Option<String>,
29    pub is_test: bool,
30    pub test_container: bool,
31}
32
33impl Symbol {
34    /// Helper to compute hidden line count in implementation body if present.
35    pub fn hidden_body_line_count(&self) -> Option<usize> {
36        match (self.body_start_line, self.body_end_line) {
37            (Some(start), Some(end)) if end >= start => Some(end - start + 1),
38            _ => None,
39        }
40    }
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44pub struct FileFact {
45    pub file_id: String,
46    pub path: String,
47    pub language: String,
48    pub content_hash: String,
49    pub content_bytes: i64,
50    pub line_count: Option<i64>,
51    pub indexed_at: String,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
55pub struct ReferenceSite {
56    pub from_symbol_name: String,
57    pub from_symbol_id: String,
58    pub to_symbol_name: String,
59    pub kind: String,
60    pub path: String,
61    pub start_line: Option<usize>,
62    pub start_column: Option<usize>,
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub occurrences: Option<usize>,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
68pub struct StructuralFact {
69    pub structural_fact_id: String,
70    pub path: String,
71    pub language: String,
72    pub pattern_id: String,
73    pub capture_name: String,
74    pub node_kind: String,
75    pub key: Option<String>,
76    pub containing_symbol_name: Option<String>,
77    pub start_line: usize,
78    pub end_line: usize,
79    pub confidence: f64,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
83pub struct LiteralFact {
84    pub literal_id: String,
85    pub path: String,
86    pub literal_text: String,
87    pub kind: String,
88    pub carrier: Option<String>,
89    pub start_line: usize,
90    pub containing_symbol_name: Option<String>,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
94pub struct TypeFact {
95    pub type_fact_id: String,
96    pub symbol_id: String,
97    pub language: String,
98    pub resolved_type: String,
99    pub generic_params: Option<String>,
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
103pub struct ContextSlice {
104    pub target_symbol: Symbol,
105    pub target_body: String,
106    pub callee_signatures: Vec<String>,
107    pub related_types: Vec<String>,
108    pub related_tests: Vec<Symbol>,
109}
110
111/// One `search` hit. `score` is the rerank score; `explain` is present only when the
112/// caller asked for the breakdown.
113#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
114pub struct SymbolSearchResult {
115    pub symbol: Symbol,
116    pub score: f64,
117    pub snippet: Option<String>,
118    #[serde(default, skip_serializing_if = "Option::is_none")]
119    pub explain: Option<SearchExplain>,
120}
121
122/// Rerank breakdown for one `search` hit: which recall branches admitted the row, the name
123/// tier with its match strength, every score part, the query terms with the field that
124/// credited each and each term's rarity weight, and the timer over the whole candidate set.
125/// `score` is `term_score + name_bonus + kind_prior + path_role + documentation + test_intent`.
126#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
127pub struct SearchExplain {
128    pub bm25: Option<f64>,
129    pub branches: Vec<String>,
130    pub name_tier: String,
131    pub name_strength: u32,
132    pub terms: Vec<(String, String, f64)>,
133    pub term_score: f64,
134    pub name_bonus: f64,
135    pub kind_prior: f64,
136    pub path_role: f64,
137    pub documentation: f64,
138    pub test_intent: f64,
139    pub word_weights: Vec<(String, f64)>,
140    pub candidates: usize,
141    pub rerank_us: u128,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
145pub struct BlastRadiusResult {
146    pub seed_type: String,
147    pub seeds: Vec<String>,
148    pub likely_tests: Vec<TestTarget>,
149    pub impacted_symbols: Vec<ImpactedSymbol>,
150    #[serde(default)]
151    pub traversal_ceiling_reached: bool,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
155pub struct TestTarget {
156    pub name: String,
157    pub path: String,
158    pub line: usize,
159    pub reason: String,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
163pub struct ImpactedSymbol {
164    pub name: String,
165    pub kind: String,
166    pub path: String,
167    pub line: usize,
168    pub depth: usize,
169}