Skip to content

Branch & Diff

Branching lets you fork a run at any ledger position and explore an alternative timeline. The shared prefix costs nothing to re-execute.

BranchMeta

kando.branch.fork.BranchMeta(branch_id, parent_run_id, fork_position) dataclass

kando.branch.fork.fork(parent_run_id, fork_position, branch_id)

Source code in kando/branch/fork.py
def fork(parent_run_id: str, fork_position: int, branch_id: str) -> BranchMeta:
    return BranchMeta(
        branch_id=branch_id,
        parent_run_id=parent_run_id,
        fork_position=fork_position,
    )

WorldDiff

kando.branch.diff.WorldDiff(added_objects, removed_objects, patched_objects, added_relations, removed_relations) dataclass

__bool__()

True if any field is non-empty (i.e. there are actual differences).

Source code in kando/branch/diff.py
def __bool__(self) -> bool:
    """True if any field is non-empty (i.e. there are actual differences)."""
    return bool(
        self.added_objects
        or self.removed_objects
        or self.patched_objects
        or self.added_relations
        or self.removed_relations
    )

summary()

Human-readable one-line summary of the diff.

Source code in kando/branch/diff.py
def summary(self) -> str:
    """Human-readable one-line summary of the diff."""
    parts = self._object_parts() + self._relation_parts()
    return ", ".join(parts) if parts else "no changes"

kando.branch.diff.diff(world_a, world_b)

Source code in kando/branch/diff.py
def diff(world_a: World, world_b: World) -> WorldDiff:
    a_objs = set(world_a.objects)
    b_objs = set(world_b.objects)
    a_rels = set(world_a.relations)
    b_rels = set(world_b.relations)

    patched = [
        oid for oid in a_objs & b_objs
        if world_a.objects[oid].data != world_b.objects[oid].data
    ]

    return WorldDiff(
        added_objects=sorted(b_objs - a_objs),
        removed_objects=sorted(a_objs - b_objs),
        patched_objects=patched,
        added_relations=sorted(b_rels - a_rels),
        removed_relations=sorted(a_rels - b_rels),
    )

Forking via CLI

# Requires EVENTSTORE_URL
export EVENTSTORE_URL=http://localhost:2113

kando fork abc123def456 --at 2
# → Branch ID  : 789ghi012jkl
# → Parent run : abc123def456
# → Fork at    : 2  (shared prefix: 2 events)

Diffing via CLI

kando diff abc123def456 789ghi012jkl
# → Diff: abc123def456 -> 789ghi012jkl
# → Summary: +1 objects
#   + object  new-claim-id  {'text': 'New finding', ...}

Programmatic branching

from kando.branch.fork import BranchMeta, fork
from kando.branch.diff import diff as world_diff
from kando.world.projection import reproject

# Create branch metadata
meta = fork(parent_run_id="abc123", fork_position=2, branch_id="xyz789")

# Compare two worlds
store_a = EventStreamLedgerStore("abc123")
store_b = EventStreamLedgerStore("xyz789")
world_a = reproject(store_a)
world_b = reproject(store_b)

d = world_diff(world_a, world_b)
print(d.summary())         # "+2 objects, +1 relations"
print(bool(d))             # True if any changes
print(d.added_objects)     # list of new object IDs
print(d.patched_objects)   # list of modified object IDs

Branch replay

from kando.branch.replay import read_branch

# Yield prefix from parent + branch tail
events = list(read_branch(meta, parent_store, branch_store))

Why branching is cheap

The branch stream contains only the events after the fork position. The shared prefix is referenced by position — the parent's events are not copied. When projecting a branch:

  1. Read events 0..fork_position from the parent ledger
  2. Read all events from the branch ledger (the divergent tail)
  3. Project the concatenated stream

No LLM calls are made for the shared prefix on branch projection.