[KongchangAI]
· 4 min read· 2,490 words

One Contract Clause Changes, and FalkorDB Instantly Identifies Affected Customers

One Contract Clause Changes, and FalkorDB Instantly Identifies Affected Customers

ClauseRipple uses FalkorDB to connect contracts, dependencies, and org relationships, making clause-change impact traversable and explainable.

ClauseRipple is a Graph Hacks hackathon project tackling the broken-chain problem of who can answer which customers are in breach after a vendor quietly changes a DPA. It stores entities and relationships from 20 synthetic documents in a single FalkorDB graph, where dependency chains and contract chains meet at region nodes. After a change, the agent traces the blast radius via MCP tools, but compliance judgment runs in plain code while the LLM only selects tools and explains. A small benchmark shows graph traversal achieves 0.99 evidence recall with 11/12 questions complete versus 0.37 and 2/12 for pure vector at k=5.

When a vendor quietly changes a single sentence in a Data Processing Agreement (DPA), who can immediately answer "which customers are now in breach?" The legal team can find that sentence, the engineering team knows which systems call that vendor, the sales team knows which products customers use, and the compliance team knows what the contracts say. But no one has the complete chain. Developer bilal-feroz built ClauseRipple during the Graph Hacks hackathon (FalkorDB x WeMakeDevs), using a graph database to reconnect this broken chain.

ClauseRipple main interface: changes on the left, propagation paths in the middle, affected customers and owners on the right

Why Vector Search Falls Short

The story begins simply: fictional company AtlasAI's model vendor ModelCloud released DPA version 2, with Section 4.1 adding just one processing region—the United States. Previously, customer data could only be processed in the UAE and the EU.

Whether this single sentence constitutes a problem depends on information scattered across completely different locations: which systems send data to ModelCloud in the architecture docs, which products run on those systems in the product catalog, which customers use those products in the CRM, which numbered clauses in each Master Service Agreement (MSA) permit data flows where, who owns the affected systems in the team directory, and whether prior decisions already exist in historical records.

Vector search is good at finding "the sentence that changed," but "which customers are affected" isn't written in any document. The answer is the connections between five documents. Take Falcon Bank: two independent chains must intersect:

Falcon Bank -USES-> DocSummarizer -POWERED_BY-> Document Processing API -DEPENDS_ON-> ModelCloud
Falcon Bank -BOUND_BY-> MSA -HAS_CLAUSE-> Clause 7.2 -IMPOSES-> Data Residency -ALLOWS-> UAE, EU
ModelCloud -PROCESSES_IN-> US

The first chain proves Falcon Bank's data actually reaches ModelCloud; the second shows its contract only permits the UAE and EU. Placed alongside the new fact, a breach is established.

The author ran a quantitative comparison: with pure vector retrieval at k=5, only 2 of 12 questions assembled all necessary evidence; graph traversal achieved 11/12.

DPA (Data Processing Agreement) is a contract annex between a data controller and a data processor that specifies how data is handled, typically covering processing purposes, data types, security measures, and data residency regions. In supply chain scenarios, the Master Service Agreement (MSA) defines commercial terms while the DPA carries compliance details, and the two are linked by reference clauses. When a vendor changes a processing region in the DPA, it may directly violate a customer's MSA data residency obligations, so contract clauses, dependency chains, and regional facts must be compared in the same graph.

The difference between vector retrieval and graph traversal: vector retrieval chunks documents and recalls by semantic similarity—great at "finding relevant sentences" but unable to guarantee that multi-hop facts across documents all enter the context. Graph traversal expands hop by hop along predefined relationships, systematically collecting every node on a dependency or contract chain. When the answer depends on connections like "A uses B, B depends on C, C permits D," graph traversal achieves significantly higher evidence recall because each hop is an explicit edge rather than a similarity guess.

Graph Model: Two Chains Meet at "Region"

ClauseRipple puts an entire company into one FalkorDB graph: 20 node labels, 20 synthetic source documents, a baseline of 144 nodes and 173 relationships. The core structure:

Customer -USES-> Product
Product -POWERED_BY-> System
System -DEPENDS_ON-> Vendor
Vendor -PROCESSES_IN-> Region
Customer -BOUND_BY-> Contract
Contract -HAS_CLAUSE-> Clause
Clause -IMPOSES-> Obligation
Obligation -ALLOWS-> Region
System -OWNED_BY-> Team
Person -LEADS-> Team
Decision -APPLIES_TO-> Customer
ImpactCase -AFFECTS-> Customer
ImpactCase -ASSIGNED_TO-> Person

Every other feature exists to walk these two chains, explain them, and act on them. The graph also stores the agent's own memory: ChangeEvent, ImpactCase, Action, AgentRun, and ToolCall are ordinary nodes, so "which agent runs touched Falcon Bank" is just another traversal.

The Complete Sequence After a Single Clause Change

Change panel: DPA v1 versus v2, with the US highlighted as a new region

When the change is applied, ClauseRipple executes as follows:

  1. Incrementally update the graph: diff DPA v1 and v2, write only one new fact ModelCloud -PROCESSES_IN-> US, recorded as ChangeEvent CHG-2026-001, taking about 180 ms locally.
  2. Wake the agent: the Change Impact Agent calls graph tools via the MCP protocol.
  3. Trace the blast radius: find systems depending on ModelCloud, products running on those systems, and customers using those products.
  4. Evaluate each customer with rules: this is the most critical design choice, detailed below.
  5. Recall company memory: find decision CR-087—"when ModelCloud's region scope changes, Falcon Bank workloads must remain locked to UAE/EU processing."
  6. Locate the owner: Document Processing API -OWNED_BY-> Platform Engineering <-LEADS- Sarah Malik.
  7. Take action: write impact cases CR-104 (Falcon Bank) and CR-105 (Acme Insurance) to FalkorDB, with next steps and assigned owners.
  8. Explain: every step links to its source document and specific sentence.

The result is a clear verdict table: Falcon Bank and Acme Insurance are flagged as severely affected because a dependency path exists and their contracts only permit the UAE/EU; Nova Retail uses ModelCloud but its contract permits the US, so it's unaffected; GulfGov has no path to ModelCloud at all and is likewise safe.

Why FalkorDB: Relationships as First-Class Citizens

FalkorDB is the only database in ClauseRipple—no parallel Postgres, no separate vector store. Every tool the agent calls is a Cypher query running on it. Key design points:

  • Blast radius is a live multi-hop traversal: a single variable-length pattern DEPENDS_ON*1..4 finds every customer reaching the vendor through any internal system.
  • "Unaffected" is proven, not assumed: running a bounded shortestPath for GulfGov returns empty—and that empty result is the evidence.
  • Ownership is also a traversal: assignment comes from OWNED_BY and LEADS edges, not from an LLM guessing a name.
  • Evidence lives on edges: every relation extracted from documents records its source document, version, line number, and verbatim quote.
  • Search lives in the same place: document chunks with embeddings are stored in FalkorDB vector and full-text indexes, powering the "Ask ClauseRipple" Q&A box.

Performance was never the bottleneck. On the author's laptop (FalkorDB in Docker), the core blast-radius query had a median FalkorDB execution time of 0.86 ms. A full agent run (14 tool calls, 63 graph reads, 13 graph writes) totaled about 75 ms inside FalkorDB.

Cypher and variable-length paths: Cypher is the declarative query language for graph databases, matching nodes and relationships with ()-[]->() patterns. A variable-length pattern like DEPENDS_ON*1..4 expands 1 to 4 hops along DEPENDS_ON edges, used to compute the "blast radius" live—finding all customers reaching the vendor through internal systems. shortestPath returns the shortest path between two points; an empty result proves no connection exists, and this "empty result as evidence" usage is unique to graph queries.

MCP (Model Context Protocol) is an open protocol from Anthropic that lets LLMs discover and call external tools in a standardized way. ClauseRipple wraps 10 graph queries as MCP tools, so the planner only selects tool names and parameters without generating Cypher. The MCP server acts as a controlled interface between the model and FalkorDB, making tool calls auditable and restrictable, while write tools can rerun rules server-side and reject invalid operations.

Three-Layer Separation of Powers: Rules Judge Compliance, the Model Only Explains

This is the author's favorite part. ClauseRipple has three layers, each with its own job:

  • The LLM (planner) decides which tool to call next and explains results in natural language.
  • FalkorDB stores facts and traverses relationships.
  • Plain code judges compliance.

The compliance rule is deliberately "boring":

violating_regions = vendor_processing_regions - customer_allowed_regions
affected = dependency_path_exists AND violating_regions not empty

For Falcon Bank: {UAE, EU, US} - {UAE, EU} = {US}, and a dependency path exists, so it's affected. The LLM is never asked "is this customer compliant." It can explain the answer but cannot change it.

The agent has 10 tools provided by the MCP server, including inspect_change, trace_vendor_dependents, find_impacted_customers, evaluate_residency, create_impact_case, and more. Two write tools are guarded: create_impact_case reruns the rules on the live graph and refuses if there's no violation; assign_impact_case rejects anyone not on the team that owns the affected system.

The planner is pluggable: Claude, any OpenAI-compatible API, or a local Ollama model. Without an LLM configured, a clearly labeled deterministic playbook calls the same tools in the same order—the demo runs this mode by default, so it needs no API key or rate limits.

A deterministic playbook is hardcoded orchestration logic independent of any LLM, calling the same MCP tools as the agent in a fixed order to trace, judge, create cases, and assign. Its value lies in reproducibility and zero external dependencies: the demo needs no API key or network, and evaluations exclude model randomness. When the planner stops early or produces incomplete output, the playbook completes missing steps and notes them in the trace, degrading "the model might err" into "the model might do less, but the system covers it."

RippleSpace: A Visible Shockwave of Change

RippleSpace in action: affected paths shown in red-orange, safe customers in green, current agent step at the bottom

The 3D view RippleSpace is built with three.js, React Three Fiber, and Drei, with bloom glow effects. It's not decorative animation: nodes and links are the live FalkorDB graph, laid out semantically—dependency chains, contracts and obligations, organization and memory layers. As the agent runs, each tool event carries a "ripple hint" from the graph: which node, what state, how many hops from ModelCloud. RippleSpace lights up nodes in that order at 170 ms per hop, so the animated path exactly matches the path the impact engine found.

A 2D evidence graph sits alongside for reading the reasoning: Falcon Bank's dependency path and contract path meet at the region, with an explicit "US not allowed" edge marking the conflict.

Does the Graph Really Help: A Small Benchmark

The author didn't want to merely assert "graphs beat RAG," so he wrote a small benchmark: 12 questions requiring cross-document facts, with both sides using the same 20 documents, same chunking, and same embedding model (bge-small-en-v1.5). The vector baseline is pure cosine search, never touching FalkorDB. The metric is "evidence recall"—the fraction of documents needed for the answer that actually enter the context.

MetricFalkorDB graphVector only k=5Vector only k=8
Questions answered exactly12/12n/an/a
Mean evidence recall0.990.370.62
Questions with complete evidence11/122/124/12

The author cautions proper interpretation: 12 questions, a small synthetic corpus, and an untuned vector side—this is not a general conclusion about RAG. But it clearly shows the shape of the problem: when answers are spread across relationships, increasing k only drags in more noise before the right documents.

Hard Problems During Development

Extracting facts from documents with evidence was one challenge. The author chose a deterministic, rule-based extractor rather than having an LLM generate triples. Every relationship stores the exact source sentence, and every citation is verified verbatim against the document before writing. Negations like "does not call ModelCloud" must produce no edges—obvious until you start writing rules. After every reset, 20 key facts are checked against the live graph; if one is missing, the reset fails loudly rather than quietly patching. The cost is real: the corpus is synthetic and written to be parseable, while messy real-world contracts would need an additional LLM extraction layer.

Learning FalkorDB's Cypher dialect also required rewrites: variable-length bounds must be literals, shortestPath can only be used in WITH or RETURN, and ORDER BY after aggregation must use projected columns.

Tool calling with small local models has pitfalls too. The author tried llama3.2:3b via Ollama on a 4 GB laptop GPU; after correctly calling tools four or five times, it began to "narrate" instead of continuing to call. So the orchestrator added completeness checks: if the planner stops early, the deterministic playbook completes the missing cases and notes it in the trace. This experience is precisely why compliance judgment lives in code, not the model.

Interface comprehensibility was the final challenge. The first UI showed everything at once: graph, trace, metrics, badges. Technically complete, but no one could follow what happened. The final version tells a story left to right: what changed, how it propagated, who's affected, with reasons below.

Two Insights on Graphs and Agents

On graphs: ordinary databases can store entities—that's not the interesting part. What's interesting is that relationships themselves become queryable, evidence-carrying, reason-able objects. "Falcon Bank uses DocSummarizer" isn't a field on some row; it's a traversable fact with provenance, version, and citation. Once relationships are first-class, "who's affected" turns from a search problem into a path problem.

On agents: giving an agent more text isn't giving it better context. The agent in ClauseRipple doesn't get a pile of chunks and a "figure it out"—it gets tools that return specific related facts, and a rule it cannot override. This constrained design is what makes it trustworthy enough to write cases and assign people. The graph doesn't just inform the agent; it limits what the agent is allowed to do.

Next Steps

The author's roadmap includes: connecting real data sources (contract repositories, Jira, team directories) so the graph updates itself; supporting more change types beyond data residency (sub-processor changes, notice periods, security controls); and a "what-if" mode—simulating a vendor change's impact before signing.

The project runs fully locally (Docker, Python, Node), and the demo needs no API key. Repository: github.com/bilal-feroz/ClauseRipple. All companies, people, and contracts are fictional. The author used Claude Code for implementation, debugging, and documentation, but the problem design, graph model, Cypher, rules, architecture, and demo behavior were all reviewed and tested personally.

A single clause is rarely dangerous on its own. The risk lives in everything connected to it.

One-line Summary

ClauseRipple uses the FalkorDB graph database to connect contracts, dependencies, and organizational relationships, making the impact of a single clause change traversable, judgeable, and explainable.

Paragraph Summary

ClauseRipple is a Graph Hacks hackathon project addressing the broken-chain problem of "who can answer which customers are in breach" after a vendor quietly changes a DPA. It stores entities and relationships from 20 synthetic documents in a single FalkorDB graph, with the core idea that dependency chains and contract chains meet at "region" nodes: one chain proves customer data reaches the vendor, the other shows which regions the contract permits. After a change is applied, the agent traces the blast radius via MCP tools, but compliance judgment runs in plain code—the LLM only selects tools and explains. A small benchmark shows graph traversal achieves 0.99 evidence recall with 11/12 questions complete, versus 0.37 and 2/12 for pure vector at k=5. Core queries have a median of 0.86 ms, and a full run takes about 75 ms inside the graph.

#FalkorDB#graph database#vector search#RAG#compliance#MCP#contract analysis
Share:

Related articles