Skip to main content

lean_ctx/core/ocla/
capsule.rs

1use std::collections::{HashMap, HashSet};
2use std::sync::atomic::{AtomicU64, Ordering};
3use std::sync::{Arc, OnceLock, RwLock};
4use std::time::{Instant, SystemTime, UNIX_EPOCH};
5
6use serde::{Deserialize, Serialize};
7
8use super::types::{OclaError, OclaResult};
9use crate::core::ocla_bus::{self, OclaEvent};
10
11static NEXT_FORK_ID: AtomicU64 = AtomicU64::new(1);
12static NEXT_SNAPSHOT_ID: AtomicU64 = AtomicU64::new(1);
13static GLOBAL_CAPSULE_STORE: OnceLock<CapsuleStore> = OnceLock::new();
14
15#[must_use]
16pub fn global_capsule_store() -> &'static CapsuleStore {
17    GLOBAL_CAPSULE_STORE.get_or_init(CapsuleStore::new)
18}
19
20#[derive(Clone, Debug, Eq, PartialEq)]
21pub struct Delta {
22    pub offset: usize,
23    pub data: Vec<u8>,
24}
25
26/// A point-in-time snapshot of a capsule for rollback.
27#[derive(Clone, Debug, Serialize, Deserialize)]
28pub struct CapsuleSnapshot {
29    pub snapshot_id: String,
30    pub capsule_ref: String,
31    pub content: Vec<u8>,
32    pub delta_count: usize,
33    pub created_at_ms: u64,
34}
35
36/// A compressed change set for transferring a capsule between agents.
37#[derive(Clone, Debug, Serialize, Deserialize)]
38pub struct HandoffDelta {
39    pub from_ref: String,
40    pub to_ref: String,
41    pub operations: Vec<DeltaOp>,
42    pub compressed_size: usize,
43    pub original_size: usize,
44}
45
46/// A single operation in a [`HandoffDelta`].
47#[derive(Clone, Debug, Serialize, Deserialize)]
48pub enum DeltaOp {
49    Keep { offset: usize, len: usize },
50    Insert { offset: usize, data: Vec<u8> },
51    Delete { offset: usize, len: usize },
52}
53
54#[derive(Clone, Debug)]
55pub struct CapsuleEntry {
56    pub parent_ref: Option<String>,
57    pub data: Vec<u8>,
58    pub deltas: Vec<Delta>,
59    pub budget_tokens: u64,
60    pub created_at: Instant,
61}
62
63#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
64pub struct CapsuleStats {
65    pub total_entries: usize,
66    pub total_bytes: usize,
67    pub max_depth: usize,
68}
69
70#[derive(Clone, Debug, Default)]
71struct CapsuleStoreState {
72    entries: HashMap<String, CapsuleEntry>,
73    snapshots: Vec<CapsuleSnapshot>,
74}
75
76#[derive(Clone, Debug, Default)]
77pub struct CapsuleStore {
78    state: Arc<RwLock<CapsuleStoreState>>,
79}
80
81impl CapsuleStore {
82    #[must_use]
83    pub fn new() -> Self {
84        Self::default()
85    }
86
87    pub fn register(&self, data: &[u8]) -> String {
88        let capsule_ref = format!("capsule:{}", blake3::hash(data).to_hex());
89        let entry = CapsuleEntry {
90            parent_ref: None,
91            data: data.to_vec(),
92            deltas: Vec::new(),
93            budget_tokens: 0,
94            created_at: Instant::now(),
95        };
96        if let Ok(mut state) = self.state.write() {
97            state.entries.insert(capsule_ref.clone(), entry);
98        }
99        capsule_ref
100    }
101
102    pub fn fork(&self, parent_ref: &str, budget_tokens: u64) -> OclaResult<String> {
103        let mut state = self
104            .state
105            .write()
106            .map_err(|_| invalid("capsule store lock poisoned"))?;
107        if !state.entries.contains_key(parent_ref) {
108            return Err(invalid(format!("unknown parent capsule: {parent_ref}")));
109        }
110
111        let fork_id = NEXT_FORK_ID.fetch_add(1, Ordering::Relaxed);
112        let identity = format!("{parent_ref}\0{budget_tokens}\0{fork_id}");
113        let capsule_ref = format!("capsule:{}", blake3::hash(identity.as_bytes()).to_hex());
114        state.entries.insert(
115            capsule_ref.clone(),
116            CapsuleEntry {
117                parent_ref: Some(parent_ref.to_string()),
118                data: Vec::new(),
119                deltas: Vec::new(),
120                budget_tokens,
121                created_at: Instant::now(),
122            },
123        );
124        Ok(capsule_ref)
125    }
126
127    pub fn resolve(&self, capsule_ref: &str) -> OclaResult<Vec<u8>> {
128        let state = self
129            .state
130            .read()
131            .map_err(|_| invalid("capsule store lock poisoned"))?;
132        resolve_entries(&state.entries, capsule_ref)
133    }
134
135    #[cfg(test)]
136    pub(crate) fn budget_tokens(&self, capsule_ref: &str) -> OclaResult<u64> {
137        let state = self
138            .state
139            .read()
140            .map_err(|_| invalid("capsule store lock poisoned"))?;
141        state
142            .entries
143            .get(capsule_ref)
144            .map(|entry| entry.budget_tokens)
145            .ok_or_else(|| invalid(format!("unknown capsule: {capsule_ref}")))
146    }
147
148    pub fn apply_delta(&self, capsule_ref: &str, delta: Delta) -> OclaResult<()> {
149        let mut state = self
150            .state
151            .write()
152            .map_err(|_| invalid("capsule store lock poisoned"))?;
153        let current = resolve_entries(&state.entries, capsule_ref)?;
154        let entry = state
155            .entries
156            .get_mut(capsule_ref)
157            .ok_or_else(|| invalid(format!("unknown capsule: {capsule_ref}")))?;
158        if entry.parent_ref.is_none() {
159            return Err(invalid("deltas can only be applied to forked capsules"));
160        }
161        if delta.offset > current.len() {
162            return Err(invalid("capsule delta starts beyond materialized content"));
163        }
164        entry.deltas.push(delta);
165        Ok(())
166    }
167
168    pub fn merge_back(&self, child_ref: &str) -> OclaResult<()> {
169        let mut state = self
170            .state
171            .write()
172            .map_err(|_| invalid("capsule store lock poisoned"))?;
173        resolve_entries(&state.entries, child_ref)?;
174        let (parent_ref, deltas) = {
175            let child = state
176                .entries
177                .get(child_ref)
178                .ok_or_else(|| invalid(format!("unknown capsule: {child_ref}")))?;
179            (
180                child
181                    .parent_ref
182                    .clone()
183                    .ok_or_else(|| invalid("root capsules cannot merge back"))?,
184                child.deltas.clone(),
185            )
186        };
187        let parent = state
188            .entries
189            .get_mut(&parent_ref)
190            .ok_or_else(|| invalid(format!("unknown parent capsule: {parent_ref}")))?;
191        parent.deltas.extend(deltas);
192        state
193            .entries
194            .get_mut(child_ref)
195            .ok_or_else(|| invalid(format!("unknown capsule: {child_ref}")))?
196            .deltas
197            .clear();
198        Ok(())
199    }
200
201    /// Creates a snapshot of the current capsule state for potential rollback.
202    pub fn snapshot(&self, capsule_ref: &str) -> OclaResult<CapsuleSnapshot> {
203        let mut state = self
204            .state
205            .write()
206            .map_err(|_| invalid("capsule store lock poisoned"))?;
207        let content = resolve_entries(&state.entries, capsule_ref)?;
208        let delta_count = state
209            .entries
210            .get(capsule_ref)
211            .ok_or_else(|| invalid(format!("unknown capsule: {capsule_ref}")))?
212            .deltas
213            .len();
214        let snapshot_number = NEXT_SNAPSHOT_ID.fetch_add(1, Ordering::Relaxed);
215        let snapshot_id = format!(
216            "snapshot:{}",
217            blake3::hash(format!("{capsule_ref}\\0{snapshot_number}").as_bytes()).to_hex()
218        );
219        let snapshot = CapsuleSnapshot {
220            snapshot_id,
221            capsule_ref: capsule_ref.to_string(),
222            content,
223            delta_count,
224            created_at_ms: unix_time_ms(),
225        };
226        state.snapshots.push(snapshot.clone());
227        Ok(snapshot)
228    }
229
230    /// Rolls back a capsule to a previous snapshot.
231    pub fn rollback(&self, capsule_ref: &str, snapshot_id: &str) -> OclaResult<()> {
232        let mut state = self
233            .state
234            .write()
235            .map_err(|_| invalid("capsule store lock poisoned"))?;
236        let snapshot = state
237            .snapshots
238            .iter()
239            .find(|snapshot| {
240                snapshot.snapshot_id == snapshot_id && snapshot.capsule_ref == capsule_ref
241            })
242            .cloned()
243            .ok_or_else(|| invalid(format!("unknown capsule snapshot: {snapshot_id}")))?;
244        let entry = state
245            .entries
246            .get_mut(capsule_ref)
247            .ok_or_else(|| invalid(format!("unknown capsule: {capsule_ref}")))?;
248        entry.parent_ref = None;
249        entry.data = snapshot.content;
250        entry.deltas.clear();
251        ocla_bus::emit(OclaEvent::AgentChainEvent {
252            agent_id: capsule_ref.to_string(),
253            action: "capsule_rollback".to_string(),
254            parent_agent: Some(snapshot_id.to_string()),
255        });
256        Ok(())
257    }
258
259    /// Computes a compressed delta between two capsule versions.
260    pub fn compute_handoff_delta(&self, from_ref: &str, to_ref: &str) -> OclaResult<HandoffDelta> {
261        let state = self
262            .state
263            .read()
264            .map_err(|_| invalid("capsule store lock poisoned"))?;
265        let from = resolve_entries(&state.entries, from_ref)?;
266        let to = resolve_entries(&state.entries, to_ref)?;
267        let operations = compute_delta_operations(&from, &to);
268        Ok(HandoffDelta {
269            from_ref: from_ref.to_string(),
270            to_ref: to_ref.to_string(),
271            compressed_size: handoff_delta_size(&operations),
272            original_size: to.len(),
273            operations,
274        })
275    }
276
277    /// Applies a handoff delta to create a new capsule version.
278    pub fn apply_handoff_delta(&self, base_ref: &str, delta: &HandoffDelta) -> OclaResult<String> {
279        if delta.from_ref != base_ref {
280            return Err(invalid("handoff delta base reference does not match"));
281        }
282        let mut state = self
283            .state
284            .write()
285            .map_err(|_| invalid("capsule store lock poisoned"))?;
286        let base = resolve_entries(&state.entries, base_ref)?;
287        let content = apply_handoff_operations(&base, &delta.operations)?;
288        let handoff_id = NEXT_FORK_ID.fetch_add(1, Ordering::Relaxed);
289        let identity = format!(
290            "handoff\\0{base_ref}\\0{}\\0{handoff_id}",
291            blake3::hash(&content)
292        );
293        let capsule_ref = format!("capsule:{}", blake3::hash(identity.as_bytes()).to_hex());
294        state.entries.insert(
295            capsule_ref.clone(),
296            CapsuleEntry {
297                parent_ref: None,
298                data: content,
299                deltas: Vec::new(),
300                budget_tokens: 0,
301                created_at: Instant::now(),
302            },
303        );
304        Ok(capsule_ref)
305    }
306
307    #[must_use]
308    pub fn stats(&self) -> CapsuleStats {
309        let Ok(state) = self.state.read() else {
310            return CapsuleStats::default();
311        };
312        let total_bytes = state.entries.values().fold(0_usize, |total, entry| {
313            total.saturating_add(entry.data.len()).saturating_add(
314                entry
315                    .deltas
316                    .iter()
317                    .map(|delta| delta.data.len())
318                    .sum::<usize>(),
319            )
320        });
321        let max_depth = state
322            .entries
323            .keys()
324            .map(|capsule_ref| depth_of(&state.entries, capsule_ref))
325            .max()
326            .unwrap_or(0);
327        CapsuleStats {
328            total_entries: state.entries.len(),
329            total_bytes,
330            max_depth,
331        }
332    }
333}
334
335fn resolve_entries(
336    entries: &HashMap<String, CapsuleEntry>,
337    capsule_ref: &str,
338) -> OclaResult<Vec<u8>> {
339    let mut current = capsule_ref;
340    let mut visited = HashSet::new();
341    let mut layers = Vec::new();
342    loop {
343        if !visited.insert(current) {
344            return Err(invalid("capsule parent cycle detected"));
345        }
346        let entry = entries
347            .get(current)
348            .ok_or_else(|| invalid(format!("unknown capsule: {capsule_ref}")))?;
349        layers.push(entry.deltas.clone());
350        if let Some(parent_ref) = entry.parent_ref.as_deref() {
351            current = parent_ref;
352        } else {
353            let mut data = entry.data.clone();
354            for layer in layers.iter().rev() {
355                for delta in layer {
356                    apply_patch(&mut data, delta)?;
357                }
358            }
359            return Ok(data);
360        }
361    }
362}
363
364fn apply_patch(data: &mut Vec<u8>, delta: &Delta) -> OclaResult<()> {
365    let end = delta
366        .offset
367        .checked_add(delta.data.len())
368        .ok_or_else(|| invalid("capsule delta range overflow"))?;
369    if delta.offset > data.len() {
370        return Err(invalid("capsule delta starts beyond materialized content"));
371    }
372    if end > data.len() {
373        data.resize(end, 0);
374    }
375    data[delta.offset..end].copy_from_slice(&delta.data);
376    Ok(())
377}
378
379fn compute_delta_operations(from: &[u8], to: &[u8]) -> Vec<DeltaOp> {
380    if from == to {
381        return Vec::new();
382    }
383
384    let prefix_len = from
385        .iter()
386        .zip(to)
387        .take_while(|(left, right)| left == right)
388        .count();
389    let suffix_len = from[prefix_len..]
390        .iter()
391        .rev()
392        .zip(to[prefix_len..].iter().rev())
393        .take_while(|(left, right)| left == right)
394        .count();
395    let from_middle_end = from.len() - suffix_len;
396    let to_middle_end = to.len() - suffix_len;
397    let mut operations = Vec::with_capacity(4);
398
399    if prefix_len > 0 {
400        operations.push(DeltaOp::Keep {
401            offset: 0,
402            len: prefix_len,
403        });
404    }
405    if from_middle_end > prefix_len {
406        operations.push(DeltaOp::Delete {
407            offset: prefix_len,
408            len: from_middle_end - prefix_len,
409        });
410    }
411    if to_middle_end > prefix_len {
412        operations.push(DeltaOp::Insert {
413            offset: from_middle_end,
414            data: to[prefix_len..to_middle_end].to_vec(),
415        });
416    }
417    if suffix_len > 0 {
418        operations.push(DeltaOp::Keep {
419            offset: from_middle_end,
420            len: suffix_len,
421        });
422    }
423    operations
424}
425
426fn apply_handoff_operations(base: &[u8], operations: &[DeltaOp]) -> OclaResult<Vec<u8>> {
427    if operations.is_empty() {
428        return Ok(base.to_vec());
429    }
430
431    let mut cursor = 0;
432    let mut output = Vec::with_capacity(base.len());
433    for operation in operations {
434        match operation {
435            DeltaOp::Keep { offset, len } => {
436                validate_handoff_offset(*offset, cursor)?;
437                let end = cursor
438                    .checked_add(*len)
439                    .ok_or_else(|| invalid("handoff keep range overflow"))?;
440                let bytes = base
441                    .get(cursor..end)
442                    .ok_or_else(|| invalid("handoff keep extends beyond base content"))?;
443                output.extend_from_slice(bytes);
444                cursor = end;
445            }
446            DeltaOp::Insert { offset, data } => {
447                validate_handoff_offset(*offset, cursor)?;
448                output.extend_from_slice(data);
449            }
450            DeltaOp::Delete { offset, len } => {
451                validate_handoff_offset(*offset, cursor)?;
452                cursor = cursor
453                    .checked_add(*len)
454                    .ok_or_else(|| invalid("handoff delete range overflow"))?;
455                if cursor > base.len() {
456                    return Err(invalid("handoff delete extends beyond base content"));
457                }
458            }
459        }
460    }
461    if cursor != base.len() {
462        return Err(invalid("handoff delta does not consume base content"));
463    }
464    Ok(output)
465}
466
467fn validate_handoff_offset(offset: usize, cursor: usize) -> OclaResult<()> {
468    if offset != cursor {
469        return Err(invalid("handoff operation offset is out of order"));
470    }
471    Ok(())
472}
473
474fn handoff_delta_size(operations: &[DeltaOp]) -> usize {
475    operations.iter().fold(0_usize, |size, operation| {
476        let operation_size = match operation {
477            DeltaOp::Keep { .. } | DeltaOp::Delete { .. } => 2 * std::mem::size_of::<usize>(),
478            DeltaOp::Insert { data, .. } => 2 * std::mem::size_of::<usize>() + data.len(),
479        };
480        size.saturating_add(operation_size)
481    })
482}
483
484fn unix_time_ms() -> u64 {
485    SystemTime::now()
486        .duration_since(UNIX_EPOCH)
487        .unwrap_or_default()
488        .as_millis()
489        .try_into()
490        .unwrap_or(u64::MAX)
491}
492
493fn depth_of(entries: &HashMap<String, CapsuleEntry>, capsule_ref: &str) -> usize {
494    let mut depth = 0;
495    let mut current = capsule_ref;
496    let mut visited = HashSet::new();
497    while visited.insert(current) {
498        let Some(entry) = entries.get(current) else {
499            break;
500        };
501        let Some(parent_ref) = entry.parent_ref.as_deref() else {
502            break;
503        };
504        depth += 1;
505        current = parent_ref;
506    }
507    depth
508}
509
510fn invalid(message: impl Into<String>) -> OclaError {
511    OclaError::InvalidRequest(message.into())
512}
513
514#[cfg(test)]
515mod tests {
516    use super::{CapsuleStore, Delta, DeltaOp, global_capsule_store};
517
518    fn test_delta() -> Delta {
519        Delta {
520            offset: 1,
521            data: vec![b'a'],
522        }
523    }
524
525    #[test]
526    fn global_store_registers_capsule() {
527        let capsule_ref = global_capsule_store().register(b"global capsule");
528        assert_eq!(
529            global_capsule_store()
530                .resolve(&capsule_ref)
531                .expect("global resolves"),
532            b"global capsule"
533        );
534    }
535
536    #[test]
537    fn register_resolves_original_data() {
538        let store = CapsuleStore::new();
539        let capsule_ref = store.register(b"hello");
540        assert_eq!(
541            store.resolve(&capsule_ref).expect("root resolves"),
542            b"hello"
543        );
544    }
545    #[test]
546    fn fork_resolves_parent_data() {
547        let store = CapsuleStore::new();
548        let parent_ref = store.register(b"hello");
549        let child_ref = store.fork(&parent_ref, 100).expect("fork succeeds");
550        assert_eq!(store.resolve(&child_ref).expect("child resolves"), b"hello");
551        assert_eq!(store.budget_tokens(&child_ref).expect("budget exists"), 100);
552    }
553    #[test]
554    fn fork_delta_resolves_patched_data() {
555        let store = CapsuleStore::new();
556        let parent_ref = store.register(b"hello");
557        let child_ref = store.fork(&parent_ref, 100).expect("fork succeeds");
558        store
559            .apply_delta(&child_ref, test_delta())
560            .expect("delta applies");
561        assert_eq!(store.resolve(&child_ref).expect("child resolves"), b"hallo");
562    }
563
564    #[test]
565    fn later_overlapping_delta_wins_within_layer() {
566        let store = CapsuleStore::new();
567        let parent_ref = store.register(b"hello");
568        let fork_ref = store.fork(&parent_ref, 100).expect("fork succeeds");
569
570        store
571            .apply_delta(
572                &fork_ref,
573                Delta {
574                    offset: 1,
575                    data: vec![b'a'],
576                },
577            )
578            .expect("first delta applies");
579        store
580            .apply_delta(
581                &fork_ref,
582                Delta {
583                    offset: 1,
584                    data: vec![b'u'],
585                },
586            )
587            .expect("second delta applies");
588
589        assert_eq!(store.resolve(&fork_ref).expect("fork resolves"), b"hullo");
590    }
591
592    #[test]
593    fn child_delta_overrides_parent_delta() {
594        let store = CapsuleStore::new();
595        let root_ref = store.register(b"hello");
596        let parent_ref = store.fork(&root_ref, 100).expect("parent fork succeeds");
597        store
598            .apply_delta(
599                &parent_ref,
600                Delta {
601                    offset: 1,
602                    data: vec![b'a'],
603                },
604            )
605            .expect("parent delta applies");
606        let child_ref = store.fork(&parent_ref, 100).expect("child fork succeeds");
607        store
608            .apply_delta(
609                &child_ref,
610                Delta {
611                    offset: 1,
612                    data: vec![b'u'],
613                },
614            )
615            .expect("child delta applies");
616
617        assert_eq!(store.resolve(&child_ref).expect("child resolves"), b"hullo");
618    }
619
620    #[test]
621    fn merge_back_preserves_chronological_delta_order() {
622        let store = CapsuleStore::new();
623        let root_ref = store.register(b"hello");
624        let parent_ref = store.fork(&root_ref, 100).expect("parent fork succeeds");
625        store
626            .apply_delta(
627                &parent_ref,
628                Delta {
629                    offset: 1,
630                    data: vec![b'a'],
631                },
632            )
633            .expect("parent delta applies");
634        let child_ref = store.fork(&parent_ref, 100).expect("child fork succeeds");
635        store
636            .apply_delta(
637                &child_ref,
638                Delta {
639                    offset: 1,
640                    data: vec![b'u'],
641                },
642            )
643            .expect("child delta applies");
644
645        store.merge_back(&child_ref).expect("merge succeeds");
646
647        assert_eq!(
648            store.resolve(&parent_ref).expect("parent resolves"),
649            b"hullo"
650        );
651        assert_eq!(store.resolve(&child_ref).expect("child resolves"), b"hullo");
652    }
653    #[test]
654    fn merge_back_projects_deltas_to_parent() {
655        let store = CapsuleStore::new();
656        let parent_ref = store.register(b"hello");
657        let child_ref = store.fork(&parent_ref, 100).expect("fork succeeds");
658        store
659            .apply_delta(&child_ref, test_delta())
660            .expect("delta applies");
661        store.merge_back(&child_ref).expect("merge succeeds");
662        assert_eq!(
663            store.resolve(&parent_ref).expect("parent resolves"),
664            b"hallo"
665        );
666        assert_eq!(store.resolve(&child_ref).expect("child resolves"), b"hallo");
667    }
668    #[test]
669    fn stats_report_entries_storage_and_depth() {
670        let store = CapsuleStore::new();
671        let parent_ref = store.register(b"hello");
672        let child_ref = store.fork(&parent_ref, 100).expect("fork succeeds");
673        store
674            .apply_delta(&child_ref, test_delta())
675            .expect("delta applies");
676        let stats = store.stats();
677        assert_eq!(stats.total_entries, 2);
678        assert_eq!(stats.total_bytes, 6);
679        assert_eq!(stats.max_depth, 1);
680    }
681
682    #[test]
683    fn snapshot_rollback_restores_snapshot_content() {
684        let store = CapsuleStore::new();
685        let root_ref = store.register(b"hello");
686        let child_ref = store.fork(&root_ref, 100).expect("fork succeeds");
687        store
688            .apply_delta(
689                &child_ref,
690                Delta {
691                    offset: 1,
692                    data: vec![b'a'],
693                },
694            )
695            .expect("first delta applies");
696        let snapshot = store.snapshot(&child_ref).expect("snapshot succeeds");
697        store
698            .apply_delta(
699                &child_ref,
700                Delta {
701                    offset: 1,
702                    data: vec![b'u'],
703                },
704            )
705            .expect("second delta applies");
706
707        store
708            .rollback(&child_ref, &snapshot.snapshot_id)
709            .expect("rollback succeeds");
710
711        assert_eq!(store.resolve(&child_ref).expect("child resolves"), b"hallo");
712    }
713
714    #[test]
715    fn handoff_delta_for_identical_capsules_is_empty() {
716        let store = CapsuleStore::new();
717        let first_ref = store.register(b"unchanged");
718        let second_ref = store.register(b"unchanged");
719
720        let delta = store
721            .compute_handoff_delta(&first_ref, &second_ref)
722            .expect("delta computes");
723
724        assert!(delta.operations.is_empty());
725        assert_eq!(delta.compressed_size, 0);
726    }
727
728    #[test]
729    fn handoff_delta_for_different_capsules_has_insert_and_delete() {
730        let store = CapsuleStore::new();
731        let from_ref = store.register(b"hello");
732        let to_ref = store.register(b"halo!");
733
734        let delta = store
735            .compute_handoff_delta(&from_ref, &to_ref)
736            .expect("delta computes");
737
738        assert!(
739            delta
740                .operations
741                .iter()
742                .any(|operation| matches!(operation, DeltaOp::Insert { .. }))
743        );
744        assert!(
745            delta
746                .operations
747                .iter()
748                .any(|operation| matches!(operation, DeltaOp::Delete { .. }))
749        );
750    }
751
752    #[test]
753    fn apply_handoff_delta_round_trip_matches_target() {
754        let store = CapsuleStore::new();
755        let from_ref = store.register(b"goodbye");
756        let to_ref = store.register(b"good day!");
757        let delta = store
758            .compute_handoff_delta(&from_ref, &to_ref)
759            .expect("delta computes");
760
761        let applied_ref = store
762            .apply_handoff_delta(&from_ref, &delta)
763            .expect("delta applies");
764
765        assert_eq!(
766            store.resolve(&applied_ref).expect("applied resolves"),
767            store.resolve(&to_ref).expect("target resolves")
768        );
769    }
770
771    #[test]
772    fn rollback_with_invalid_snapshot_id_errors() {
773        let store = CapsuleStore::new();
774        let capsule_ref = store.register(b"hello");
775
776        assert!(store.rollback(&capsule_ref, "snapshot:missing").is_err());
777    }
778}