MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / fork_session

Method fork_session

atomic-repository/src/repository/changes.rs:616–701  ·  view source on GitHub ↗

Create a forked session from a parent at a turn boundary. The child inherits the parent's turn records through `fork_turn` as an immutable ledger prefix. No provenance graphs or session rows are copied — the child manifest references the parent by content hash. Returns `(parent_manifest_hash, child_manifest_hash)`.

(
        &self,
        parent_session_id: &str,
        fork_turn: u32,
        child_session_id: &str,
    )

Source from the content-addressed store, hash-verified

614 ///
615 /// Returns `(parent_manifest_hash, child_manifest_hash)`.
616 pub fn fork_session(
617 &self,
618 parent_session_id: &str,
619 fork_turn: u32,
620 child_session_id: &str,
621 ) -> Result<(Hash, Hash), RepositoryError> {
622 // Resolve the parent ledger and manifest.
623 let (parent_record, parent_turns) =
624 self.get_session_ledger(parent_session_id)?.ok_or_else(|| {
625 RepositoryError::Database(format!(
626 "parent session not found: {}",
627 parent_session_id
628 ))
629 })?;
630
631 let last_parent_turn = parent_record.turn_count.saturating_sub(1);
632 if fork_turn > last_parent_turn && parent_record.turn_count > 0 {
633 return Err(RepositoryError::Database(format!(
634 "fork turn {} exceeds parent turn {} for session {}",
635 fork_turn, last_parent_turn, parent_session_id
636 )));
637 }
638
639 let parent_manifest = self
640 .publish_session_manifest(parent_session_id)
641 .map_err(|e| RepositoryError::Database(format!("parent manifest: {}", e)))?;
642
643 // Seed the child session record with the inherited ledger prefix:
644 // turns 0..=fork_turn from the parent. The child reuses the parent's
645 // immutable turn rows — we copy the references, not the provenance.
646 let inherited: Vec<atomic_core::change::session::SessionTurn> = parent_turns
647 .into_iter()
648 .filter(|t| t.turn_number <= fork_turn)
649 .map(|mut t| {
650 t.session_id = child_session_id.to_string();
651 t
652 })
653 .collect();
654
655 let child_json_path = self
656 .dot_dir
657 .join("sessions")
658 .join(format!("{}.json", child_session_id))
659 .to_string_lossy()
660 .to_string();
661
662 let mut txn = self
663 .pristine
664 .write_txn()
665 .map_err(|e| RepositoryError::Database(e.to_string()))?;
666 for turn in &inherited {
667 txn.index_inherited_turn(child_session_id, &child_json_path, turn)
668 .map_err(|e| RepositoryError::Database(e.to_string()))?;
669 }
670 // Create the child record even when no turns are inherited.
671 if inherited.is_empty() {
672 txn.index_empty_session(
673 child_session_id,

Calls 11

get_session_ledgerMethod · 0.80
write_txnMethod · 0.80
index_inherited_turnMethod · 0.80
index_empty_sessionMethod · 0.80
emit_session_fork_kgMethod · 0.80
commitMethod · 0.80
into_iterMethod · 0.45
is_emptyMethod · 0.45
cloneMethod · 0.45