From 7e6d4982af9a64fa15d89363324978b7a9adb32d Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 4 Jun 2026 03:48:45 +0200 Subject: [PATCH] fix(rolegraph): add serde(default) to trigger_descriptions and pinned_node_ids Refs #2039 Old persisted SerializableRoleGraph JSON written before issue #84 was merged lacked trigger_descriptions and pinned_node_ids fields. Without #[serde(default)], deserialisation failed with a missing-field error, breaking cache warm-up on any deployment with existing snapshots. Adds regression test: strips both fields from a freshly serialised graph, then verifies round-trip deserialisation succeeds with empty collections. --- crates/terraphim_rolegraph/src/lib.rs | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/crates/terraphim_rolegraph/src/lib.rs b/crates/terraphim_rolegraph/src/lib.rs index c707b6cd9..54ca56d01 100644 --- a/crates/terraphim_rolegraph/src/lib.rs +++ b/crates/terraphim_rolegraph/src/lib.rs @@ -296,8 +296,10 @@ pub struct SerializableRoleGraph { /// reverse lookup - matched id into normalized term pub ac_reverse_nterm: AHashMap, /// Trigger descriptions for each node_id (used to rebuild TriggerIndex) + #[serde(default)] pub trigger_descriptions: AHashMap, /// Node IDs that are pinned (always included in results) + #[serde(default)] pub pinned_node_ids: Vec, /// Document IDs that were indexed from shared learnings #[serde(default)] @@ -2302,4 +2304,30 @@ mod tests { let results = restored.find_matching_node_ids_with_fallback("trigger one text", false); assert!(results.contains(&1u64)); } + + #[tokio::test] + async fn serializable_rolegraph_deserializes_without_trigger_fields() { + // Regression: JSON persisted before trigger_descriptions/pinned_node_ids were added + // must deserialise successfully with those fields defaulting to empty collections. + let thesaurus = Thesaurus::new("test".to_string()); + let rg = RoleGraph::new("test".into(), thesaurus).await.unwrap(); + let mut json_value: serde_json::Value = + serde_json::from_str(&rg.to_serializable().to_json().unwrap()).unwrap(); + + // Simulate old persisted format by removing the fields added by issue #84 + let obj = json_value.as_object_mut().unwrap(); + obj.remove("trigger_descriptions"); + obj.remove("pinned_node_ids"); + let old_json = json_value.to_string(); + + let result = SerializableRoleGraph::from_json(&old_json); + assert!( + result.is_ok(), + "deserialising old JSON without trigger_descriptions/pinned_node_ids failed: {:?}", + result.err() + ); + let sg = result.unwrap(); + assert!(sg.trigger_descriptions.is_empty()); + assert!(sg.pinned_node_ids.is_empty()); + } }