This guide explains each example slowly and clearly. Each example has two moving parts:
- Git DAG: the commit history of patches. This is the storage layer.
- WARP graph: the materialized state created by reducing patches. This is the query layer.
If you open the HTML files in examples/html/, you will see a Git DAG diagram on the left and a WARP graph diagram on the right.
- The Git DAG diagram shows commits only. Each commit is a patch.
- The direction of the arrows shows commit order (older -> newer).
- Writers have separate chains. They do not merge in git.
- The WARP graph diagram shows nodes and edges after CRDT reduction.
- The WARP graph diagram ignores commit order. It only shows the current state.
Purpose: Create a tiny graph and materialize it.
Step-by-step (slow):
- Initialize a git repo if it does not exist.
- Open WarpGraph with graphName "demo" and writerId "writer-1".
- Create Patch 1. Add node user:alice and set her properties.
- Commit Patch 1. This becomes the first git commit on the writer ref.
- Create Patch 2. Add node user:bob and edge user:alice -> user:bob.
- Commit Patch 2. The Git DAG now has two commits in a chain.
- Create Patch 3. Add node post:1 and edge user:alice -> post:1.
- Commit Patch 3. The Git DAG now has three commits in a chain.
- Call materialize(). The reducer loads all patches and builds the CRDT state.
- Query nodes and properties from the materialized state.
What is happening in the Git DAG:
- Three commits are created under refs/warp/demo/writers/writer-1.
- Each commit stores a patch payload.
- The history is linear.
What is happening in the WARP graph:
- Nodes user:alice, user:bob, post:1 are visible.
- Edges follows and authored are visible.
- Properties are attached to user:alice and post:1.
Purpose: Read and query the materialized graph.
Step-by-step (slow):
- Open the same graphName "demo" with a new writerId.
- Call materialize() to build a cached state.
- Call getNodes() to list visible node IDs.
- For each node, call getNodeProps() to read properties.
- Call neighbors("user:alice", "both") to list connected nodes.
- Call discoverWriters() to list writer IDs.
- Call getFrontier() to read the latest patch per writer.
What is happening in the Git DAG:
- No new commits are created.
- The script only reads the existing patch chain.
What is happening in the WARP graph:
- The graph is identical to setup.js.
- The script uses the query helpers to inspect it.
Purpose: Show concurrent writers converging on one state.
Step-by-step (slow):
- Open graphName "shared" as writerId "alice".
- Open the same graphName "shared" as writerId "bob".
- Alice commits a patch that adds her user and project.
- Bob commits a patch that adds his user and project.
- Alice commits another patch to add a task.
- Bob commits another patch to add a task.
- Call materialize() from Alice. The reducer loads both writer chains.
- Call materialize() from Bob. The reducer loads the same combined patches.
- Bob commits a new patch that links to Alice's project.
- Materialize again to see the merged state.
What is happening in the Git DAG:
- There are two independent commit chains under two writer refs.
- No git merge is required. The history is separate by writer.
What is happening in the WARP graph:
- Both writers' patches are reduced into one graph.
- Nodes and edges from both writers are visible together.
- The graph converges even though the commit history is separate.
Purpose: Explain the event-sourcing model.
Step-by-step (slow):
- Treat each patch commit as an event record.
- Store events as an append-only commit history.
- Materialize when you need a state view.
- Query the state instead of scanning commits directly.
- Use checkpoints for faster recovery.
What is happening in the Git DAG:
- The DAG is the event log.
- Every commit is an immutable event.
What is happening in the WARP graph:
- The graph is a projection of the event log.
- The projection is deterministic and conflict-free.
Purpose: Run weighted shortest-path algorithms on the graph.
Step-by-step (slow):
- Open a new graphName for the demo.
- Create a patch that adds nodes A through G.
- Add edges and store CPU and memory metrics as properties.
- Commit the patch. The Git DAG has a single commit.
- Materialize the graph to build state.
- Build an adjacency list from getEdges().
- Compute weights from CPU and memory metrics.
- Run Dijkstra to find the minimum-cost path.
- Run A* with a heuristic and compare results.
What is happening in the Git DAG:
- There is one commit containing the entire demo graph.
- The DAG is trivial but still stores the full patch.
What is happening in the WARP graph:
- The graph has multiple paths between A and G.
- Weighted costs select the most efficient route.
Purpose: Benchmark Dijkstra and A* on different graph shapes.
Step-by-step (slow):
- Choose a graph size (100, 500, 1000, ...).
- Create a linear graph by adding nodes in a chain.
- Commit patches in batches to reduce commit count.
- Materialize and build adjacency from edges.
- Run Dijkstra and A* multiple times.
- Record median times and nodes explored.
- Repeat with a diamond graph shape.
- Compare results between shapes.
What is happening in the Git DAG:
- Patch commits are grouped into batches.
- The DAG is linear within a writer ref.
What is happening in the WARP graph:
- Linear graphs have one path; diamonds have multiple paths.
- A* can explore fewer nodes when the heuristic helps.
Purpose: Stress-test materialization at scale.
Step-by-step (slow):
- Open a new graphName for the benchmark run.
- Add a long chain of nodes (for example 100,000 nodes).
- Commit patches every N nodes to keep commits manageable.
- Measure the time to create all patches.
- Materialize the graph and measure time.
- Compare memory usage before and after materialization.
What is happening in the Git DAG:
- Many patch commits represent batches of nodes.
- The DAG grows in length but remains linear.
What is happening in the WARP graph:
- The graph is a long chain of nodes.
- Materialize reconstructs the full chain into memory.
Purpose: Inspect checkpoint blobs and frontier state.
Step-by-step (slow):
- Materialize the graph to compute the full CRDT state.
- Create a checkpoint commit that writes state blobs to a tree.
- Update refs/warp//checkpoints/head.
- Read the checkpoint commit and list its tree entries.
- Read frontier.cbor to see writer tips.
- Use the checkpoint to resume materialization later.
What is happening in the Git DAG:
- Patch commits are still the source of truth.
- A checkpoint commit points to a tree of state blobs.
What is happening in the WARP graph:
- The checkpoint encodes the same state the reducer would build.
- It is a faster starting point for materialize().