<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohit Shirke</title>
    <description>The latest articles on DEV Community by Mohit Shirke (@mohit_shirke).</description>
    <link>https://dev.to/mohit_shirke</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4190957%2F85bdccd2-df24-41b5-b453-4644106cdd95.png</url>
      <title>DEV Community: Mohit Shirke</title>
      <link>https://dev.to/mohit_shirke</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mohit_shirke"/>
    <language>en</language>
    <item>
      <title>What a graph actually buys an incident agent (and what it doesn't)</title>
      <dc:creator>Mohit Shirke</dc:creator>
      <pubDate>Sat, 17 Oct 2026 18:03:16 +0000</pubDate>
      <link>https://dev.to/mohit_shirke/what-a-graph-actually-buys-an-incident-agent-and-what-it-doesnt-k58</link>
      <guid>https://dev.to/mohit_shirke/what-a-graph-actually-buys-an-incident-agent-and-what-it-doesnt-k58</guid>
      <description>&lt;p&gt;&lt;em&gt;By Mohit Sachin Shirke (team Night Hunter), for Graph Hacks: Context for AI Agents (WeMakeDevs × FalkorDB), Track 01.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A smoke alarm tells you there is a fire, but never which room it started in.&lt;/p&gt;

&lt;p&gt;Microservice alerts work the same way. When checkout breaks, the alert fires at the front door: the&lt;br&gt;
proxy returns errors and the frontend's latency spikes. The cause is usually somewhere those services&lt;br&gt;
call, two or four hops down. On-call engineers spend the first, most expensive minutes working out&lt;br&gt;
who calls whom, what changed, and who owns the broken thing.&lt;/p&gt;

&lt;p&gt;For Graph Hacks I built &lt;strong&gt;SynapseGuard&lt;/strong&gt;, an incident agent that walks from the alarm to the room&lt;br&gt;
where the fire began and shows every step. I wanted to find out how much a graph database really&lt;br&gt;
helps an agent do that, so I measured it, including on data I didn't make up.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Demo video (2:49): &lt;a href="https://youtu.be/mOSek0RKldQ" rel="noopener noreferrer"&gt;https://youtu.be/mOSek0RKldQ&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Try it in the browser: &lt;a href="https://mohit-shirke.github.io/synapseguard/" rel="noopener noreferrer"&gt;https://mohit-shirke.github.io/synapseguard/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Code, benchmarks and raw results: &lt;a href="https://github.com/Mohit-shirke/synapseguard" rel="noopener noreferrer"&gt;https://github.com/Mohit-shirke/synapseguard&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The agent's whole context is one graph
&lt;/h2&gt;

&lt;p&gt;Everything the agent knows lives in FalkorDB:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the service call graph (the OpenTelemetry Demo's real topology), with live telemetry on each service;&lt;/li&gt;
&lt;li&gt;which host each service runs on;&lt;/li&gt;
&lt;li&gt;the change log: deploys, config changes and feature flags;&lt;/li&gt;
&lt;li&gt;the people: teams, owners, on-call rotations, who authored each change and who has worked on what;&lt;/li&gt;
&lt;li&gt;the agent's own memory of past incidents and the actions it proposed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When an incident arrives, the agent does five things that a table of rows can't.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It prunes by reachability.&lt;/strong&gt; It follows synchronous &lt;code&gt;CALLS&lt;/code&gt; edges from the alerting service, but
only into unhealthy services, one hop at a time, with one index-backed Cypher query per hop. A
database that is broken but unreachable from the symptom isn't the cause of &lt;em&gt;this&lt;/em&gt; symptom.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It scores candidates on evidence.&lt;/strong&gt; Inside that subgraph it asks: does anything below a candidate
explain it? How much of the degradation does the candidate explain? Did it degrade first, and did
its callers follow within a minute? Did a change land just before? Do several broken services share
a saturated host?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It names who to page, with proof.&lt;/strong&gt; Every person comes with a graph path, for example
&lt;code&gt;p-alice → ON_CALL → team-checkout → OWNS → payment&lt;/code&gt;, plus the author of the change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It acts on the structure.&lt;/strong&gt; It computes the blast radius and runs FalkorDB's &lt;code&gt;algo.maxFlow&lt;/code&gt; to
place the cheapest circuit breakers that cut users off from the fault.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It waits for a human.&lt;/strong&gt; Every action needs a person to approve it and then execute it. When the
agent isn't sure, it says so and flags the answer for verification.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the demo, a feature flag breaks the payment service while an unrelated frontend deploy lands as a&lt;br&gt;
red herring. One click gives: root cause &lt;strong&gt;payment&lt;/strong&gt;, at 94% relative confidence. The flag landed&lt;br&gt;
79 seconds before payment degraded. Page &lt;strong&gt;Alice&lt;/strong&gt;, the on-call owner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the LLM graph tools, not graph access
&lt;/h2&gt;

&lt;p&gt;The same capabilities are exposed as an MCP server, but as a &lt;strong&gt;fixed catalogue of human-written,&lt;br&gt;
parameterised Cypher tools&lt;/strong&gt;: &lt;code&gt;blast_radius&lt;/code&gt;, &lt;code&gt;who_to_page&lt;/code&gt;, &lt;code&gt;path_between&lt;/code&gt;, &lt;code&gt;recent_changes&lt;/code&gt;, and&lt;br&gt;
so on. Names are resolved against the graph before any query runs. Ask about &lt;code&gt;payments-gateway&lt;/code&gt;, which&lt;br&gt;
doesn't exist, and no query runs: the agent replies that the name isn't in the graph and asks whether&lt;br&gt;
you meant &lt;code&gt;payment&lt;/code&gt;. Free-form Cypher is off by default, and no tool can approve an action.&lt;/p&gt;

&lt;p&gt;A small local model (llama3.1:8b on a CPU) chose the right tool for 12 of 12 test questions. Its final&lt;br&gt;
sentence is rejected if it names anything the tools didn't return.&lt;/p&gt;

&lt;h2&gt;
  
  
  The results I expected, and the ones I got
&lt;/h2&gt;

&lt;p&gt;On 500 held-out synthetic incidents, with decoys, red-herring deploys and missing telemetry, the graph&lt;br&gt;
agent ranked the true root cause first &lt;strong&gt;95.2%&lt;/strong&gt; of the time. The strongest rows-only baseline, with&lt;br&gt;
the same signals, the same tuning and the relationships removed, managed &lt;strong&gt;81.6%&lt;/strong&gt;. The first version&lt;br&gt;
of my own project, which simply picked the "deepest failing service", managed &lt;strong&gt;25%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then I ran it on &lt;strong&gt;RCAEval&lt;/strong&gt;, a public benchmark of real fault injection: 645 cases across Online&lt;br&gt;
Boutique, Sock Shop and Train Ticket, with metrics from real clusters but no change logs and no host&lt;br&gt;
placement. For Train Ticket I learned the call graph from 574,479 real Jaeger spans; on Online&lt;br&gt;
Boutique, the same method confirmed every edge of my hand-written graph.&lt;/p&gt;

&lt;p&gt;The honest result: with my default settings, the graph's ranking is &lt;strong&gt;on par&lt;/strong&gt; with a strong no-graph&lt;br&gt;
scorer. It's better on some systems and worse on others, including 4 points worse on held-out Train&lt;br&gt;
Ticket. With weights learned on the &lt;em&gt;other&lt;/em&gt; real systems, the graph scorer won on 4 of 6 held-out&lt;br&gt;
system-suites, but I didn't switch the product default after seeing those results. The graph's ranking&lt;br&gt;
advantage comes from joining telemetry with changes and placement, and RCAEval doesn't have those&lt;br&gt;
joins, so there was nothing for the graph to exploit.&lt;/p&gt;

&lt;p&gt;Real data also caught a bug that synthetic data never would have: a severity score that saturated at&lt;br&gt;
1.0 and stopped telling services apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two FalkorDB bugs, found along the way
&lt;/h2&gt;

&lt;p&gt;Pushing FalkorDB 6.0.2 hard turned up two issues, both reproduced in the repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a query shape with two &lt;code&gt;MATCH … WHERE … IN $list&lt;/code&gt; clauses that silently returns no rows, unless you
put a &lt;code&gt;WITH&lt;/code&gt; between the clauses;&lt;/li&gt;
&lt;li&gt;a query with two &lt;code&gt;OPTIONAL MATCH&lt;/code&gt; clauses, an aggregation and &lt;code&gt;ORDER BY&lt;/code&gt; that crashed the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two more lessons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;WHERE n.id IN $list&lt;/code&gt; uses the index, while &lt;code&gt;UNWIND … MATCH (n {id: x})&lt;/code&gt; didn't. Switching made
investigations about 3.6× faster at 1,000 services.&lt;/li&gt;
&lt;li&gt;Results are capped at &lt;code&gt;RESULTSET_SIZE&lt;/code&gt; (10,000 rows) without a warning, so any query that "returns
everything" must be bounded.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A graph earns its place when the answer depends on joining structure with operational
context:&lt;/strong&gt; calls with changes, placement and time. Remove the relationships and the same signals
blame the wrong service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure on someone else's data.&lt;/strong&gt; My synthetic benchmark flattered me; real data told me where the
graph helps and where it doesn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give LLM agents graph tools, not graph write access.&lt;/strong&gt; Read-only access belongs in the database
and the tool design, not in a prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make every answer show its path.&lt;/strong&gt; It turns "trust me" into "check me", and that's what an on-call
engineer at 3 a.m. actually needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every answer comes with its path. The code, the benchmarks and the raw results are all in the&lt;br&gt;
repository: &lt;a href="https://github.com/Mohit-shirke/synapseguard" rel="noopener noreferrer"&gt;https://github.com/Mohit-shirke/synapseguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>falkordb</category>
      <category>ai</category>
      <category>graphdatabase</category>
      <category>sre</category>
    </item>
  </channel>
</rss>
