use serde::{Deserialize, Serialize};
use crate::domain::FreshnessPolicy;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FileIndexFreshnessState {
Fresh,
Pending,
Paused,
Stale,
Degraded,
Overflow,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FileIndexFreshnessCursor {
pub source_scope: String,
pub root_id: String,
pub root_path: String,
pub backend: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub scan_watermark_ms: Option<u64>,
pub indexed_file_count: usize,
pub missing_file_count: usize,
pub scan_error_count: usize,
pub overflow: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_error: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct FileIndexLag {
pub configured_root_count: usize,
pub indexed_root_count: usize,
pub pending_root_count: usize,
pub stale_root_count: usize,
pub overflow_root_count: usize,
pub missing_file_count: usize,
pub pending_task_count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FileIndexFreshnessDiagnostics {
pub state: FileIndexFreshnessState,
pub freshness_policy: FreshnessPolicy,
pub graph_version: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_scope: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub root_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stale_reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub degraded_reason: Option<String>,
pub index_lag: FileIndexLag,
pub cursors: Vec<FileIndexFreshnessCursor>,
pub direct_source_read_required: bool,
pub bounded_rescan_required: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub direct_source_read_paths: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub agent_instructions: Vec<String>,
}
impl FileIndexFreshnessDiagnostics {
pub fn legacy_unknown() -> Self {
Self {
state: FileIndexFreshnessState::Degraded,
freshness_policy: FreshnessPolicy::AllowStale,
graph_version: 0,
source_scope: None,
root_id: None,
stale_reason: None,
degraded_reason: Some("response did not include file freshness diagnostics".to_owned()),
index_lag: FileIndexLag::default(),
cursors: Vec::new(),
direct_source_read_required: false,
bounded_rescan_required: false,
direct_source_read_paths: Vec::new(),
agent_instructions: Vec::new(),
}
}
}