Save a provenance graph to the repository. Serializes the graph to disk, registers it in the pristine database with `node_type::PROVENANCE`, and records dependencies on the changes this graph explains. # Returns The content hash of the saved provenance graph.
(
&self,
graph: &atomic_core::change::ProvenanceGraph,
)
| 1134 | /// |
| 1135 | /// The content hash of the saved provenance graph. |
| 1136 | pub fn save_provenance_graph( |
| 1137 | &self, |
| 1138 | graph: &atomic_core::change::ProvenanceGraph, |
| 1139 | ) -> Result<Hash, RepositoryError> { |
| 1140 | use atomic_core::pristine::MutTxnT; |
| 1141 | |
| 1142 | // Save to disk |
| 1143 | let hash = self |
| 1144 | .change_store |
| 1145 | .save_provenance_graph(graph) |
| 1146 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 1147 | |
| 1148 | // Register in the graph |
| 1149 | let mut txn = self |
| 1150 | .pristine |
| 1151 | .write_txn() |
| 1152 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 1153 | |
| 1154 | let prov_id = txn |
| 1155 | .register_provenance(&hash) |
| 1156 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 1157 | |
| 1158 | // Register dependencies: provenance → explained changes. Sidecars can |
| 1159 | // arrive with `--download-only`, before their changes are inserted into |
| 1160 | // a view. Registering the content hash now gives the relationship a |
| 1161 | // stable internal ID; insertion reuses that registration later. |
| 1162 | for change_hash in &graph.changes_explained { |
| 1163 | let change_id = txn |
| 1164 | .register_change(change_hash) |
| 1165 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 1166 | txn.put_dep(prov_id, change_id) |
| 1167 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 1168 | } |
| 1169 | |
| 1170 | // If chained, register dependency on previous provenance graph too |
| 1171 | if let Some(ref prev_hash) = graph.previous { |
| 1172 | if let Ok(Some(prev_id)) = txn.get_internal(prev_hash) { |
| 1173 | txn.put_dep(prov_id, prev_id) |
| 1174 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 1175 | } |
| 1176 | } |
| 1177 | |
| 1178 | // Populate session tables from the provenance graph, for any agent |
| 1179 | // (Sherpa, Claude Code, OpenCode, generic atomic-agent, ...). The |
| 1180 | // write transaction is still open, so this is atomic with the |
| 1181 | // provenance registration above. |
| 1182 | txn.populate_session_tables(prov_id.get(), graph) |
| 1183 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 1184 | |
| 1185 | // Maintain the Atomic-native session ledger alongside the provenance |
| 1186 | // registration. The JSON file is a mutable runtime cache; this index |
| 1187 | // connects the external session identity to immutable turn objects. |
| 1188 | let json_path = self |
| 1189 | .dot_dir |
| 1190 | .join("sessions") |
| 1191 | .join(format!("{}.json", graph.session_id)) |
| 1192 | .to_string_lossy() |
| 1193 | .to_string(); |