fix(cms): perbaiki serde default hive_mind_node_timeout_ms & toleransi parse gagal di Settings

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
asepharyana
2026-07-17 09:08:41 +07:00
co-authored by Claude Sonnet 5
parent f51a32569f
commit 6d41ffc587
2 changed files with 37 additions and 2 deletions
+5
View File
@@ -44,6 +44,10 @@ impl Default for SettingsFlags {
} }
} }
fn default_hive_mind_node_timeout_ms() -> u64 {
600_000
}
/// Top-level application settings. /// Top-level application settings.
/// ///
/// Serialized to `settings.json` by the infrastructure layer. /// Serialized to `settings.json` by the infrastructure layer.
@@ -63,6 +67,7 @@ pub struct Settings {
#[serde(flatten)] #[serde(flatten)]
pub flags: SettingsFlags, pub flags: SettingsFlags,
pub lsp_languages: Vec<String>, pub lsp_languages: Vec<String>,
#[serde(default = "default_hive_mind_node_timeout_ms")]
pub hive_mind_node_timeout_ms: u64, pub hive_mind_node_timeout_ms: u64,
} }
@@ -34,8 +34,16 @@ impl SettingsRepository for JsonSettingsRepository {
fn load(&self, base_dir: &Path) -> Result<Settings> { fn load(&self, base_dir: &Path) -> Result<Settings> {
let path = base_dir.join("settings.json"); let path = base_dir.join("settings.json");
match std::fs::read_to_string(&path) { match std::fs::read_to_string(&path) {
Ok(s) => serde_json::from_str(&s) Ok(s) => match serde_json::from_str(&s) {
.map_err(|e| anyhow::anyhow!("failed to parse settings.json: {e}")), Ok(settings) => Ok(settings),
Err(e) => {
tracing::warn!(
"settings.json at '{}' failed to parse ({e}); falling back to defaults",
path.display()
);
Ok(Settings::default())
}
},
Err(e) if e.kind() == std::io::ErrorKind::NotFound => { Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
tracing::info!("settings.json not found, using defaults"); tracing::info!("settings.json not found, using defaults");
Ok(Settings::default()) Ok(Settings::default())
@@ -72,3 +80,25 @@ impl SettingsRepository for JsonSettingsRepository {
Ok(()) Ok(())
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn load_defaults_hive_mind_timeout_when_field_missing_from_old_settings_json() {
let dir = std::env::temp_dir().join(format!("zesdex-cms-settings-test-{}", uuid::Uuid::new_v4()));
std::fs::create_dir_all(&dir).unwrap();
// Simulate a settings.json written before `hive_mind_node_timeout_ms` existed.
std::fs::write(
dir.join("settings.json"),
r#"{"internet_mode":"Off","provider":"zen","model":"m","api_keys":{},"max_tokens":null,"temperature":null,"review_max_lessons_per_run":5,"adaptive_review_max_skip":3,"verify_command":null,"verify_timeout_ms":30000,"workflow_max_concurrency":5,"review_enabled":true,"session_archive_enabled":true,"lsp_auto_provision":true,"lsp_languages":[]}"#,
).unwrap();
let repo = JsonSettingsRepository::new();
let settings = repo.load(&dir).expect("load must not fail on a pre-existing settings.json missing the new field");
assert_eq!(settings.hive_mind_node_timeout_ms, 600_000);
let _ = std::fs::remove_dir_all(&dir);
}
}