diff --git a/rust/crates/rusty-claude-cli/src/main.rs b/rust/crates/rusty-claude-cli/src/main.rs index 08a1db03..d372f482 100644 --- a/rust/crates/rusty-claude-cli/src/main.rs +++ b/rust/crates/rusty-claude-cli/src/main.rs @@ -2018,7 +2018,14 @@ impl DiagnosticCheck { } fn json_value(&self) -> Value { + // Derive a stable snake_case id from the check name for machine-readable keying (#704). + let id = self + .name + .to_ascii_lowercase() + .replace(' ', "_") + .replace('-', "_"); let mut value = Map::from_iter([ + ("id".to_string(), Value::String(id.clone())), ( "name".to_string(), Value::String(self.name.to_ascii_lowercase()), diff --git a/rust/crates/rusty-claude-cli/tests/output_format_contract.rs b/rust/crates/rusty-claude-cli/tests/output_format_contract.rs index ad7cd706..dbebd0ca 100644 --- a/rust/crates/rusty-claude-cli/tests/output_format_contract.rs +++ b/rust/crates/rusty-claude-cli/tests/output_format_contract.rs @@ -536,6 +536,12 @@ fn doctor_and_resume_status_emit_json_when_requested() { assert!(check["status"].as_str().is_some()); assert!(check["summary"].as_str().is_some()); assert!(check["details"].is_array()); + // #704: each check must have a stable snake_case id + assert!( + check["id"].as_str().is_some(), + "doctor check missing stable id field: {:?}", + check["name"] + ); check["name"].as_str().expect("doctor check name") }) .collect::>();