relay_knowledge/api/
file_index.rs1use serde::{Deserialize, Serialize};
2
3use crate::domain::FreshnessPolicy;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "snake_case")]
8pub enum FileIndexFreshnessState {
9 Fresh,
10 Pending,
11 Paused,
12 Stale,
13 Degraded,
14 Overflow,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct FileIndexFreshnessCursor {
20 pub source_scope: String,
21 pub root_id: String,
22 pub root_path: String,
23 pub backend: String,
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub scan_watermark_ms: Option<u64>,
26 pub indexed_file_count: usize,
27 pub missing_file_count: usize,
28 pub scan_error_count: usize,
29 pub overflow: bool,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub last_error: Option<String>,
32}
33
34#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
36pub struct FileIndexLag {
37 pub configured_root_count: usize,
38 pub indexed_root_count: usize,
39 pub pending_root_count: usize,
40 pub stale_root_count: usize,
41 pub overflow_root_count: usize,
42 pub missing_file_count: usize,
43 pub pending_task_count: usize,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
48pub struct FileIndexFreshnessDiagnostics {
49 pub state: FileIndexFreshnessState,
50 pub freshness_policy: FreshnessPolicy,
51 pub graph_version: u64,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub source_scope: Option<String>,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub root_id: Option<String>,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub stale_reason: Option<String>,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 pub degraded_reason: Option<String>,
60 pub index_lag: FileIndexLag,
61 pub cursors: Vec<FileIndexFreshnessCursor>,
62 pub direct_source_read_required: bool,
63 pub bounded_rescan_required: bool,
64 #[serde(default, skip_serializing_if = "Vec::is_empty")]
65 pub direct_source_read_paths: Vec<String>,
66 #[serde(default, skip_serializing_if = "Vec::is_empty")]
67 pub agent_instructions: Vec<String>,
68}
69
70impl FileIndexFreshnessDiagnostics {
71 pub fn legacy_unknown() -> Self {
72 Self {
73 state: FileIndexFreshnessState::Degraded,
74 freshness_policy: FreshnessPolicy::AllowStale,
75 graph_version: 0,
76 source_scope: None,
77 root_id: None,
78 stale_reason: None,
79 degraded_reason: Some("response did not include file freshness diagnostics".to_owned()),
80 index_lag: FileIndexLag::default(),
81 cursors: Vec::new(),
82 direct_source_read_required: false,
83 bounded_rescan_required: false,
84 direct_source_read_paths: Vec::new(),
85 agent_instructions: Vec::new(),
86 }
87 }
88}