Skip to main content

relay_knowledge/storage/
code.rs

1//! Storage contracts for code repository indexes.
2
3use crate::domain::{
4    CodeFileFingerprint, CodeImpactRequest, CodeIndexBatch, CodeIndexCheckpoint, CodeIndexSession,
5    CodeIndexSnapshot, CodeIndexSummary, CodeIndexTaskRecord, CodeRepositoryCrossEdge,
6    CodeRepositoryRegistration, CodeRepositoryReport, CodeRepositorySet, CodeRepositorySetMember,
7    CodeRepositorySetRefreshSummary, CodeRepositorySetRefreshTaskRecord, CodeRepositorySetStatus,
8    CodeRepositoryStatus, CodeRepositoryTotals, CodeRetrievalHit, CodeRetrievalRequest,
9    CodeScopeRetentionSummary,
10};
11
12use super::{StorageError, StorageFuture};
13
14/// Diff-derived inputs used to seed code impact expansion.
15#[derive(Debug, Clone, Default, PartialEq, Eq)]
16pub struct CodeImpactChanges {
17    pub paths: Vec<String>,
18    pub deleted_symbol_names: Vec<String>,
19}
20
21/// New background code index task to persist or deduplicate.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct CodeIndexTaskSeed {
24    pub repository_id: String,
25    pub alias: String,
26    pub ref_selector: String,
27    pub resolved_commit_sha: String,
28    pub tree_hash: String,
29    pub source_scope: String,
30    pub path_filters: Vec<String>,
31    pub language_filters: Vec<String>,
32    pub mode: crate::domain::CodeIndexMode,
33    pub input_fingerprint: String,
34    pub resource_budget: crate::domain::CodeIndexResourceBudget,
35    pub payload_json: String,
36    pub now_ms: u64,
37}
38
39/// Lease acquisition request for one background code index task.
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct CodeIndexTaskClaimRequest {
42    pub task_id: Option<String>,
43    pub lease_owner: String,
44    pub lease_duration_ms: u64,
45    pub max_attempts: u32,
46    pub now_ms: u64,
47}
48
49/// Completion report guarded by task lease and attempt token.
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct CodeIndexTaskCompletion {
52    pub task_id: String,
53    pub lease_owner: String,
54    pub attempt_count: u32,
55    pub now_ms: u64,
56}
57
58/// Failure report for retry and dead-letter handling.
59#[derive(Debug, Clone, PartialEq, Eq)]
60pub struct CodeIndexTaskFailure {
61    pub task_id: String,
62    pub lease_owner: String,
63    pub attempt_count: u32,
64    pub error_kind: String,
65    pub error_message: String,
66    pub retry_backoff_ms: u64,
67    pub max_attempts: u32,
68    pub now_ms: u64,
69}
70
71/// Scope retention request after a repository index completes.
72#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct CodeScopeRetentionRequest {
74    pub repository_id: String,
75    pub active_scope: String,
76    pub retain_recent_successful_scopes: usize,
77}
78
79/// New repository set metadata to persist.
80#[derive(Debug, Clone, PartialEq, Eq)]
81pub struct CodeRepositorySetSeed {
82    pub alias: String,
83    pub description: Option<String>,
84    pub default_ref_policy_json: String,
85    pub now_ms: u64,
86}
87
88/// New or replaced repository-set member pointer.
89#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct CodeRepositorySetMemberSeed {
91    pub set_alias: String,
92    pub repository_id: String,
93    pub repository_alias: String,
94    pub ref_selector: String,
95    pub resolved_commit_sha: String,
96    pub source_scope: String,
97    pub path_filters: Vec<String>,
98    pub language_filters: Vec<String>,
99    pub priority: i32,
100}
101
102/// Repository-set overlay refresh task to persist or deduplicate.
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct CodeRepositorySetRefreshTaskSeed {
105    pub set_id: String,
106    pub set_alias: String,
107    pub input_fingerprint: String,
108    pub now_ms: u64,
109}
110
111/// Lease acquisition request for one repository-set overlay task.
112#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct CodeRepositorySetRefreshTaskClaimRequest {
114    pub task_id: Option<String>,
115    pub lease_owner: String,
116    pub lease_duration_ms: u64,
117    pub max_attempts: u32,
118    pub now_ms: u64,
119}
120
121/// Completion report guarded by task lease and attempt token.
122#[derive(Debug, Clone, PartialEq, Eq)]
123pub struct CodeRepositorySetRefreshTaskCompletion {
124    pub task_id: String,
125    pub lease_owner: String,
126    pub attempt_count: u32,
127    pub now_ms: u64,
128}
129
130/// Failure report for retry and dead-letter handling.
131#[derive(Debug, Clone, PartialEq, Eq)]
132pub struct CodeRepositorySetRefreshTaskFailure {
133    pub task_id: String,
134    pub lease_owner: String,
135    pub attempt_count: u32,
136    pub error_kind: String,
137    pub error_message: String,
138    pub retry_backoff_ms: u64,
139    pub max_attempts: u32,
140    pub now_ms: u64,
141}
142
143/// Persisted code repository graph and retrieval contract.
144pub trait CodeRepositoryStore: Send + Sync {
145    fn upsert_code_repository(
146        &self,
147        registration: CodeRepositoryRegistration,
148    ) -> StorageFuture<'_, CodeRepositoryStatus>;
149
150    fn code_repository_status(
151        &self,
152        repository: String,
153    ) -> StorageFuture<'_, Option<CodeRepositoryStatus>>;
154
155    fn code_repository_scope_status(
156        &self,
157        repository: String,
158        resolved_commit_sha: String,
159        path_filters: Vec<String>,
160        language_filters: Vec<String>,
161    ) -> StorageFuture<'_, Option<CodeRepositoryStatus>>;
162
163    fn queue_code_index_task(
164        &self,
165        task: CodeIndexTaskSeed,
166    ) -> StorageFuture<'_, CodeIndexTaskRecord>;
167
168    fn claim_code_index_task(
169        &self,
170        request: CodeIndexTaskClaimRequest,
171    ) -> StorageFuture<'_, Option<CodeIndexTaskRecord>>;
172
173    fn complete_code_index_task(
174        &self,
175        request: CodeIndexTaskCompletion,
176    ) -> StorageFuture<'_, CodeIndexTaskRecord>;
177
178    fn fail_code_index_task(
179        &self,
180        request: CodeIndexTaskFailure,
181    ) -> StorageFuture<'_, CodeIndexTaskRecord>;
182
183    fn code_index_task(&self, task_id: String) -> StorageFuture<'_, Option<CodeIndexTaskRecord>>;
184
185    fn active_code_index_task(
186        &self,
187        repository_id: String,
188    ) -> StorageFuture<'_, Option<CodeIndexTaskRecord>>;
189
190    fn code_index_checkpoint(
191        &self,
192        source_scope: String,
193    ) -> StorageFuture<'_, Option<CodeIndexCheckpoint>>;
194
195    fn code_scope_retention(
196        &self,
197        repository_id: String,
198    ) -> StorageFuture<'_, CodeScopeRetentionSummary>;
199
200    fn prune_code_repository_scopes(
201        &self,
202        request: CodeScopeRetentionRequest,
203    ) -> StorageFuture<'_, CodeScopeRetentionSummary>;
204
205    fn code_file_fingerprints(
206        &self,
207        repository_id: String,
208    ) -> StorageFuture<'_, Vec<CodeFileFingerprint>>;
209
210    fn code_file_fingerprints_for_scope(
211        &self,
212        source_scope: String,
213    ) -> StorageFuture<'_, Vec<CodeFileFingerprint>> {
214        Box::pin(async move {
215            Err(StorageError::InvalidInput(format!(
216                "code file fingerprints for scope '{source_scope}' are unavailable"
217            )))
218        })
219    }
220
221    fn apply_code_index_snapshot(
222        &self,
223        snapshot: CodeIndexSnapshot,
224    ) -> StorageFuture<'_, CodeIndexSummary>;
225
226    fn begin_code_index_session(
227        &self,
228        session: CodeIndexSession,
229    ) -> StorageFuture<'_, CodeIndexCheckpoint> {
230        Box::pin(async move {
231            Err(StorageError::InvalidInput(format!(
232                "checkpointed code index sessions for scope '{}' are unavailable",
233                session.source_scope
234            )))
235        })
236    }
237
238    fn apply_code_index_batch(
239        &self,
240        batch: CodeIndexBatch,
241    ) -> StorageFuture<'_, CodeIndexCheckpoint> {
242        Box::pin(async move {
243            Err(StorageError::InvalidInput(format!(
244                "checkpointed code index batches for scope '{}' are unavailable",
245                batch.source_scope
246            )))
247        })
248    }
249
250    fn finalize_code_index_session(
251        &self,
252        session: CodeIndexSession,
253    ) -> StorageFuture<'_, CodeIndexSummary> {
254        Box::pin(async move {
255            Err(StorageError::InvalidInput(format!(
256                "checkpointed code index finalization for scope '{}' is unavailable",
257                session.source_scope
258            )))
259        })
260    }
261
262    fn search_code(
263        &self,
264        request: CodeRetrievalRequest,
265    ) -> StorageFuture<'_, Vec<CodeRetrievalHit>>;
266
267    fn search_code_scope(
268        &self,
269        source_scope: String,
270        _request: CodeRetrievalRequest,
271    ) -> StorageFuture<'_, Vec<CodeRetrievalHit>> {
272        Box::pin(async move {
273            Err(StorageError::InvalidInput(format!(
274                "code search for source scope '{source_scope}' is unavailable"
275            )))
276        })
277    }
278
279    fn analyze_code_impact(
280        &self,
281        request: CodeImpactRequest,
282        changes: CodeImpactChanges,
283    ) -> StorageFuture<'_, Vec<CodeRetrievalHit>>;
284
285    fn code_repository_totals(&self) -> StorageFuture<'_, CodeRepositoryTotals> {
286        Box::pin(async { Ok(CodeRepositoryTotals::default()) })
287    }
288
289    fn code_repository_report(
290        &self,
291        repository: String,
292    ) -> StorageFuture<'_, CodeRepositoryReport> {
293        Box::pin(async move {
294            Err(StorageError::InvalidInput(format!(
295                "code repository report for '{repository}' is unavailable"
296            )))
297        })
298    }
299
300    fn create_code_repository_set(
301        &self,
302        _seed: CodeRepositorySetSeed,
303    ) -> StorageFuture<'_, CodeRepositorySet> {
304        Box::pin(async {
305            Err(StorageError::InvalidInput(
306                "repository set storage is unavailable".to_owned(),
307            ))
308        })
309    }
310
311    fn add_code_repository_set_member(
312        &self,
313        _seed: CodeRepositorySetMemberSeed,
314    ) -> StorageFuture<'_, CodeRepositorySetMember> {
315        Box::pin(async {
316            Err(StorageError::InvalidInput(
317                "repository set member storage is unavailable".to_owned(),
318            ))
319        })
320    }
321
322    fn remove_code_repository_set_member(
323        &self,
324        _set_alias: String,
325        _repository_alias: String,
326    ) -> StorageFuture<'_, CodeRepositorySetMember> {
327        Box::pin(async {
328            Err(StorageError::InvalidInput(
329                "repository set member storage is unavailable".to_owned(),
330            ))
331        })
332    }
333
334    fn code_repository_set(
335        &self,
336        _set_alias: String,
337    ) -> StorageFuture<'_, Option<CodeRepositorySet>> {
338        Box::pin(async { Ok(None) })
339    }
340
341    fn code_repository_set_status(
342        &self,
343        _set_alias: String,
344    ) -> StorageFuture<'_, Option<CodeRepositorySetStatus>> {
345        Box::pin(async { Ok(None) })
346    }
347
348    fn refresh_code_repository_set_overlay(
349        &self,
350        _set_alias: String,
351        _now_ms: u64,
352    ) -> StorageFuture<'_, CodeRepositorySetRefreshSummary> {
353        Box::pin(async {
354            Err(StorageError::InvalidInput(
355                "repository set overlay refresh is unavailable".to_owned(),
356            ))
357        })
358    }
359
360    fn code_repository_set_cross_edges(
361        &self,
362        _set_id: String,
363    ) -> StorageFuture<'_, Vec<CodeRepositoryCrossEdge>> {
364        Box::pin(async { Ok(Vec::new()) })
365    }
366
367    fn queue_code_repository_set_refresh_task(
368        &self,
369        _task: CodeRepositorySetRefreshTaskSeed,
370    ) -> StorageFuture<'_, CodeRepositorySetRefreshTaskRecord> {
371        Box::pin(async {
372            Err(StorageError::InvalidInput(
373                "repository set refresh task storage is unavailable".to_owned(),
374            ))
375        })
376    }
377
378    fn claim_code_repository_set_refresh_task(
379        &self,
380        _request: CodeRepositorySetRefreshTaskClaimRequest,
381    ) -> StorageFuture<'_, Option<CodeRepositorySetRefreshTaskRecord>> {
382        Box::pin(async { Ok(None) })
383    }
384
385    fn complete_code_repository_set_refresh_task(
386        &self,
387        _request: CodeRepositorySetRefreshTaskCompletion,
388    ) -> StorageFuture<'_, CodeRepositorySetRefreshTaskRecord> {
389        Box::pin(async {
390            Err(StorageError::InvalidInput(
391                "repository set refresh task storage is unavailable".to_owned(),
392            ))
393        })
394    }
395
396    fn fail_code_repository_set_refresh_task(
397        &self,
398        _request: CodeRepositorySetRefreshTaskFailure,
399    ) -> StorageFuture<'_, CodeRepositorySetRefreshTaskRecord> {
400        Box::pin(async {
401            Err(StorageError::InvalidInput(
402                "repository set refresh task storage is unavailable".to_owned(),
403            ))
404        })
405    }
406}