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

Method fork_session

atomic-repository/src/repository/changes.rs:632–717  ·  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

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