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, CodeRepositoryRegistration,
6    CodeRepositoryReport, CodeRepositoryStatus, CodeRepositoryTotals, CodeRetrievalHit,
7    CodeRetrievalRequest, CodeScopeRetentionSummary,
8};
9
10use super::{StorageError, StorageFuture};
11
12/// Diff-derived inputs used to seed code impact expansion.
13#[derive(Debug, Clone, Default, PartialEq, Eq)]
14pub struct CodeImpactChanges {
15    pub paths: Vec<String>,
16    pub deleted_symbol_names: Vec<String>,
17}
18
19/// New background code index task to persist or deduplicate.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct CodeIndexTaskSeed {
22    pub repository_id: String,
23    pub alias: String,
24    pub ref_selector: String,
25    pub resolved_commit_sha: String,
26    pub tree_hash: String,
27    pub source_scope: String,
28    pub path_filters: Vec<String>,
29    pub language_filters: Vec<String>,
30    pub mode: crate::domain::CodeIndexMode,
31    pub input_fingerprint: String,
32    pub resource_budget: crate::domain::CodeIndexResourceBudget,
33    pub payload_json: String,
34    pub now_ms: u64,
35}
36
37/// Lease acquisition request for one background code index task.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct CodeIndexTaskClaimRequest {
40    pub task_id: Option<String>,
41    pub lease_owner: String,
42    pub lease_duration_ms: u64,
43    pub max_attempts: u32,
44    pub now_ms: u64,
45}
46
47/// Completion report guarded by task lease and attempt token.
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub struct CodeIndexTaskCompletion {
50    pub task_id: String,
51    pub lease_owner: String,
52    pub attempt_count: u32,
53    pub now_ms: u64,
54}
55
56/// Failure report for retry and dead-letter handling.
57#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct CodeIndexTaskFailure {
59    pub task_id: String,
60    pub lease_owner: String,
61    pub attempt_count: u32,
62    pub error_kind: String,
63    pub error_message: String,
64    pub retry_backoff_ms: u64,
65    pub max_attempts: u32,
66    pub now_ms: u64,
67}
68
69/// Scope retention request after a repository index completes.
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct CodeScopeRetentionRequest {
72    pub repository_id: String,
73    pub active_scope: String,
74    pub retain_recent_successful_scopes: usize,
75}
76
77/// Persisted code repository graph and retrieval contract.
78pub trait CodeRepositoryStore: Send + Sync {
79    fn upsert_code_repository(
80        &self,
81        registration: CodeRepositoryRegistration,
82    ) -> StorageFuture<'_, CodeRepositoryStatus>;
83
84    fn code_repository_status(
85        &self,
86        repository: String,
87    ) -> StorageFuture<'_, Option<CodeRepositoryStatus>>;
88
89    fn code_repository_scope_status(
90        &self,
91        repository: String,
92        resolved_commit_sha: String,
93        path_filters: Vec<String>,
94        language_filters: Vec<String>,
95    ) -> StorageFuture<'_, Option<CodeRepositoryStatus>>;
96
97    fn queue_code_index_task(
98        &self,
99        task: CodeIndexTaskSeed,
100    ) -> StorageFuture<'_, CodeIndexTaskRecord>;
101
102    fn claim_code_index_task(
103        &self,
104        request: CodeIndexTaskClaimRequest,
105    ) -> StorageFuture<'_, Option<CodeIndexTaskRecord>>;
106
107    fn complete_code_index_task(
108        &self,
109        request: CodeIndexTaskCompletion,
110    ) -> StorageFuture<'_, CodeIndexTaskRecord>;
111
112    fn fail_code_index_task(
113        &self,
114        request: CodeIndexTaskFailure,
115    ) -> StorageFuture<'_, CodeIndexTaskRecord>;
116
117    fn code_index_task(&self, task_id: String) -> StorageFuture<'_, Option<CodeIndexTaskRecord>>;
118
119    fn active_code_index_task(
120        &self,
121        repository_id: String,
122    ) -> StorageFuture<'_, Option<CodeIndexTaskRecord>>;
123
124    fn code_index_checkpoint(
125        &self,
126        source_scope: String,
127    ) -> StorageFuture<'_, Option<CodeIndexCheckpoint>>;
128
129    fn code_scope_retention(
130        &self,
131        repository_id: String,
132    ) -> StorageFuture<'_, CodeScopeRetentionSummary>;
133
134    fn prune_code_repository_scopes(
135        &self,
136        request: CodeScopeRetentionRequest,
137    ) -> StorageFuture<'_, CodeScopeRetentionSummary>;
138
139    fn code_file_fingerprints(
140        &self,
141        repository_id: String,
142    ) -> StorageFuture<'_, Vec<CodeFileFingerprint>>;
143
144    fn code_file_fingerprints_for_scope(
145        &self,
146        source_scope: String,
147    ) -> StorageFuture<'_, Vec<CodeFileFingerprint>> {
148        Box::pin(async move {
149            Err(StorageError::InvalidInput(format!(
150                "code file fingerprints for scope '{source_scope}' are unavailable"
151            )))
152        })
153    }
154
155    fn apply_code_index_snapshot(
156        &self,
157        snapshot: CodeIndexSnapshot,
158    ) -> StorageFuture<'_, CodeIndexSummary>;
159
160    fn begin_code_index_session(
161        &self,
162        session: CodeIndexSession,
163    ) -> StorageFuture<'_, CodeIndexCheckpoint> {
164        Box::pin(async move {
165            Err(StorageError::InvalidInput(format!(
166                "checkpointed code index sessions for scope '{}' are unavailable",
167                session.source_scope
168            )))
169        })
170    }
171
172    fn apply_code_index_batch(
173        &self,
174        batch: CodeIndexBatch,
175    ) -> StorageFuture<'_, CodeIndexCheckpoint> {
176        Box::pin(async move {
177            Err(StorageError::InvalidInput(format!(
178                "checkpointed code index batches for scope '{}' are unavailable",
179                batch.source_scope
180            )))
181        })
182    }
183
184    fn finalize_code_index_session(
185        &self,
186        session: CodeIndexSession,
187    ) -> StorageFuture<'_, CodeIndexSummary> {
188        Box::pin(async move {
189            Err(StorageError::InvalidInput(format!(
190                "checkpointed code index finalization for scope '{}' is unavailable",
191                session.source_scope
192            )))
193        })
194    }
195
196    fn search_code(
197        &self,
198        request: CodeRetrievalRequest,
199    ) -> StorageFuture<'_, Vec<CodeRetrievalHit>>;
200
201    fn analyze_code_impact(
202        &self,
203        request: CodeImpactRequest,
204        changes: CodeImpactChanges,
205    ) -> StorageFuture<'_, Vec<CodeRetrievalHit>>;
206
207    fn code_repository_totals(&self) -> StorageFuture<'_, CodeRepositoryTotals> {
208        Box::pin(async { Ok(CodeRepositoryTotals::default()) })
209    }
210
211    fn code_repository_report(
212        &self,
213        repository: String,
214    ) -> StorageFuture<'_, CodeRepositoryReport> {
215        Box::pin(async move {
216            Err(StorageError::InvalidInput(format!(
217                "code repository report for '{repository}' is unavailable"
218            )))
219        })
220    }
221}