Persist the graph to disk at `{session_dir}/graph.json`. Uses atomic write (temp file + rename) to prevent corruption.
(&self, session_dir: &Path)
| 141 | /// |
| 142 | /// Uses atomic write (temp file + rename) to prevent corruption. |
| 143 | pub fn save(&self, session_dir: &Path) -> AgentResult<()> { |
| 144 | // Ensure the session directory exists |
| 145 | std::fs::create_dir_all(session_dir).map_err(|e| AgentError::SessionSaveFailed { |
| 146 | session_id: self.session_id.clone(), |
| 147 | reason: format!("create session dir: {}", e), |
| 148 | })?; |
| 149 | |
| 150 | let path = session_dir.join(GRAPH_FILENAME); |
| 151 | let tmp_path = path.with_extension("json.tmp"); |
| 152 | |
| 153 | let serialized = self.to_serialized_graph(); |
| 154 | let data = serde_json::to_string_pretty(&serialized).map_err(|e| { |
| 155 | AgentError::SessionSaveFailed { |
| 156 | session_id: self.session_id.clone(), |
| 157 | reason: format!("provenance graph serialize: {}", e), |
| 158 | } |
| 159 | })?; |
| 160 | |
| 161 | // Write to temp file |
| 162 | std::fs::write(&tmp_path, data.as_bytes()).map_err(|e| AgentError::SessionSaveFailed { |
| 163 | session_id: self.session_id.clone(), |
| 164 | reason: format!("provenance graph write temp: {}", e), |
| 165 | })?; |
| 166 | |
| 167 | // Atomic rename |
| 168 | std::fs::rename(&tmp_path, &path).map_err(|e| AgentError::SessionSaveFailed { |
| 169 | session_id: self.session_id.clone(), |
| 170 | reason: format!("provenance graph rename: {}", e), |
| 171 | })?; |
| 172 | |
| 173 | Ok(()) |
| 174 | } |
| 175 | |
| 176 | /// Serialize to the full JSON-compatible representation. |
| 177 | pub fn to_serialized_graph(&self) -> SerializedGraph { |