<?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: crsvt</title>
    <description>The latest articles on DEV Community by crsvt (@crsvt_7bcbef1ef88d38a72b2).</description>
    <link>https://dev.to/crsvt_7bcbef1ef88d38a72b2</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%2F4192602%2Fdc6d0461-06d1-460a-8b60-5e0d75767417.png</url>
      <title>DEV Community: crsvt</title>
      <link>https://dev.to/crsvt_7bcbef1ef88d38a72b2</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crsvt_7bcbef1ef88d38a72b2"/>
    <language>en</language>
    <item>
      <title>Cordon: the late message may be the only record that someone is alive</title>
      <dc:creator>crsvt</dc:creator>
      <pubDate>Sun, 18 Oct 2026 18:11:37 +0000</pubDate>
      <link>https://dev.to/crsvt_7bcbef1ef88d38a72b2/cordon-the-late-message-may-be-the-only-record-that-someone-is-alive-k79</link>
      <guid>https://dev.to/crsvt_7bcbef1ef88d38a72b2/cordon-the-late-message-may-be-the-only-record-that-someone-is-alive-k79</guid>
      <description>&lt;p&gt;&lt;em&gt;Revanth, team CMB · Graph Hacks (WeMakeDevs × FalkorDB) · Track 2&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://cordon-crsvt.vercel.app" rel="noopener noreferrer"&gt;https://cordon-crsvt.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/crsvt/Cordon" rel="noopener noreferrer"&gt;https://github.com/crsvt/Cordon&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/PexaFdd-GFI" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Exercise only. A fictional earthquake on real OpenStreetMap streets of Lajpat Nagar, New Delhi. Synthetic data, victim counts only, no names. Not for operational use, and not affiliated with INSARAG, UN OCHA, NDRF, NDMA or DDMA.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The problem nobody fences correctly
&lt;/h2&gt;

&lt;p&gt;When an earthquake hits, rescue teams lose their radios, but their tablets keep writing. Reports pile up offline and sync hours later. By then, the worksite they describe may have been handed to another team.&lt;/p&gt;

&lt;p&gt;Picture it. At 10:30, team XSA11 finds two people alive under a slab at worksite C-5 and logs it on a tablet with no signal. At 12:40, XSA11 has been silent for two hours, so a coordinator reassigns C-5 to XCF10. At 14:10, XSA11's tablet finally syncs: &lt;em&gt;"RESCUE, two confirmed live, north-east corner."&lt;/em&gt; It still claims the lease it held at 10:30.&lt;/p&gt;

&lt;p&gt;A shared memory for agents has three choices:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Write policy&lt;/th&gt;
&lt;th&gt;What happens to C-5&lt;/th&gt;
&lt;th&gt;Stale team took control&lt;/th&gt;
&lt;th&gt;Report of two survivors&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Overwrite&lt;/strong&gt; (last writer wins)&lt;/td&gt;
&lt;td&gt;reopened under XSA11&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;yes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;kept, but nobody is told&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Reject&lt;/strong&gt; (textbook fencing)&lt;/td&gt;
&lt;td&gt;stays with XCF10&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;lost&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Cordon&lt;/strong&gt; (fence and keep)&lt;/td&gt;
&lt;td&gt;stays with XCF10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;no&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;kept and escalated to a person&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The textbook fix for stale writers, fencing tokens, solves the first problem by creating the second: the only record that two people are alive gets thrown away. Cordon keeps both truths.&lt;/p&gt;

&lt;h2&gt;
  
  
  One atomic Cypher statement
&lt;/h2&gt;

&lt;p&gt;Every coordination decision in Cordon is a single Cypher statement on FalkorDB that checks, decides, writes, audits and appends its own outbox event, all at once. Here is the heart of &lt;code&gt;Q_REPORT&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The fence: is this writer still the lead,&lt;/span&gt;
&lt;span class="c1"&gt;// at the worksite's current epoch?&lt;/span&gt;
&lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'UNKNOWN_LEASE'&lt;/span&gt;
     &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;l.state&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'ACTIVE'&lt;/span&gt;
       &lt;span class="ow"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;l.epoch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;w.epoch&lt;/span&gt;
       &lt;span class="ow"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;l.epoch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;$epoch&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'STALE_EPOCH'&lt;/span&gt;
     &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;l.expires_at&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'LEASE_EXPIRED'&lt;/span&gt;
     &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;l.role&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'lead'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'NOT_LEAD'&lt;/span&gt;
     &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;fence_fail&lt;/span&gt;
&lt;span class="n"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// 1. The report is always kept&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:REPORTED&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;o:&lt;/span&gt;&lt;span class="n"&gt;Observation&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:ABOUT&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Only the current holder can move the status&lt;/span&gt;
&lt;span class="k"&gt;FOREACH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;IN&lt;/span&gt; &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;ctl_ok&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt; &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="ss"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;w.status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;$status&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// 3. A stale status change is refused, on the record&lt;/span&gt;
&lt;span class="k"&gt;FOREACH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;IN&lt;/span&gt; &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;$status&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="ow"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="ow"&gt;AND&lt;/span&gt; &lt;span class="ow"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;ctl_ok&lt;/span&gt;
               &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt; &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="ss"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:CAUSED&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:RejectedWrite&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;reason:&lt;/span&gt; &lt;span class="n"&gt;fence_fail&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
             &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:AGAINST&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="ss"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// 4. New information reaches a person&lt;/span&gt;
&lt;span class="k"&gt;FOREACH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;IN&lt;/span&gt; &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;escalate&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt; &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="ss"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;MERGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;a:&lt;/span&gt;&lt;span class="n"&gt;Alert&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;key:&lt;/span&gt; &lt;span class="s1"&gt;'RETRIAGE:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;w.id&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:EVIDENCE&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="ss"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three rules come out of it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fence the control write.&lt;/strong&gt; A status change counts only if the writer's lease is active, unexpired, the lead, and at the worksite's current epoch. Otherwise a &lt;code&gt;RejectedWrite&lt;/code&gt; is recorded against the worksite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the evidence.&lt;/strong&gt; The observation is always stored. If it contradicts the current fact, it's linked &lt;code&gt;CONFLICTS_WITH&lt;/code&gt; and raised as a re-triage alert for a person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silence is a welfare event, never a silent reassignment.&lt;/strong&gt; A quiet team goes amber, then red. A reassignment waits in an approval queue for a human.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is why a graph fits: the proof of every decision is a path. &lt;code&gt;Q_WHY&lt;/code&gt; walks from the rejected observation through the fenced lease to the current holder in five hops, so the "why" is a query, not a log search.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F575ddbqt4ana7nqezykm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F575ddbqt4ana7nqezykm.jpg" alt="The fence in 3D on the real Lajpat Nagar streets" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  We tried to break it: 2,000 exercise days
&lt;/h2&gt;

&lt;p&gt;One scenario proves nothing. The benchmark runs &lt;strong&gt;2,000 seeded exercise days&lt;/strong&gt; with 40 team agents: radios fail at random, teams keep writing offline, a person decides each reassignment after a delay, dark teams sync later, and devices resend. Every one of the &lt;strong&gt;127,890 writes&lt;/strong&gt; is judged by all three policies against the true lease state:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Overwrite&lt;/th&gt;
&lt;th&gt;Reject&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cordon&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A team no longer in charge changed a worksite&lt;/td&gt;
&lt;td&gt;3,730&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A report of someone alive was lost&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4,269&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A report of someone alive reached nobody&lt;/td&gt;
&lt;td&gt;4,269&lt;/td&gt;
&lt;td&gt;4,269&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A resent report was counted twice&lt;/td&gt;
&lt;td&gt;695&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first 25 days were replayed through the real statements on FalkorDB: 9,734 decisions agree with a pure-Python reference model, and 0 disagree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eight AI agents. No messages. One memory.
&lt;/h2&gt;

&lt;p&gt;Then we gave every free rescue team a language model. Each step, the agents read the shared memory and choose the worksite they'll lead, &lt;strong&gt;at the same moment, without talking to each other&lt;/strong&gt;, weighing collapse type, building use, size and travel. When two choose the same building, the lease grant settles it: exactly one wins. The loser is told who got there first, remembers it in its own session in the graph, and chooses again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe97csied5cenx8gy8dfu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe97csied5cenx8gy8dfu.jpg" alt="Round 08:50: each arc is one agent's choice; a red ring marks the building two agents wanted" width="799" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the run above, XSA10 and XIB10 both chose A-2 ("4-story apartments, pancake collapse, high life-safety priority"). XIB10 got the lease; XSA10 took A-1 one step later. The models choose what to write; the database decides whether it counts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvh8hfpm4hdcxw35lvesx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvh8hfpm4hdcxw35lvesx.jpg" alt="Agent cards: each team's model, its reason in its own words, and what the graph decided" width="799" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bring your own agent.&lt;/strong&gt; Cordon serves MCP over streamable HTTP. Point a desktop assistant, an IDE agent or your own script at &lt;code&gt;/mcp/&lt;/code&gt;, call &lt;code&gt;join_exercise&lt;/code&gt;, and it becomes a rescue team, fenced exactly like everyone else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rewind: what did the memory know, and when?
&lt;/h2&gt;

&lt;p&gt;Every observation carries two times: when it was seen (&lt;code&gt;observed_at&lt;/code&gt;) and when the memory learned it (&lt;code&gt;received_at&lt;/code&gt;). Scrub the exercise day and Cordon shows the memory as it stood at that minute, next to what was already true but had not arrived yet.&lt;/p&gt;

&lt;p&gt;At 12:40, while a person is deciding whether to reassign C-5, the memory shows XSA11 silent. The report of two people alive, seen at 10:30, only reaches it at 14:10: &lt;strong&gt;220 minutes&lt;/strong&gt; during which the memory could not have known.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fszpuhw6ftmdxrhe4gqyu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fszpuhw6ftmdxrhe4gqyu.jpg" alt="Rewind at 12:40: already true, not yet known" width="799" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pull the plug. Lose nothing.
&lt;/h2&gt;

&lt;p&gt;Every write commits exactly one event in the same atomic statement: query id, parameters, the server's &lt;code&gt;now&lt;/code&gt;, a gapless sequence number. So the log &lt;em&gt;is&lt;/em&gt; the memory.&lt;/p&gt;

&lt;p&gt;The crash test copies the outbox, &lt;strong&gt;deletes the live graph&lt;/strong&gt;, rebuilds it by replaying every event through the same named statements, and compares digests. On a full exercise day, 493 events replayed and the rebuilt memory was &lt;strong&gt;byte-for-byte identical&lt;/strong&gt; to the one that was lost. Then the devices that missed the crash resend their last reports: each comes back as a retry, and nothing is counted twice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx0nadgu1yqttpsommx6u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx0nadgu1yqttpsommx6u.jpg" alt="Crash test: copy the outbox, pull the plug, replay, compare, resend" width="799" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try to break it yourself
&lt;/h2&gt;

&lt;p&gt;The terminal on the site sends real attacks through the same fenced statement a team's tablet uses, on the running exercise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;attack stale&lt;/code&gt;: a team that lost a worksite sends "CLOSED" with its old epoch → &lt;code&gt;STALE_EPOCH&lt;/code&gt;, refused, report kept&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;attack intruder&lt;/code&gt;: a forged lease → &lt;code&gt;UNKNOWN_LEASE&lt;/code&gt;, refused, kept, escalated&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;attack replay&lt;/code&gt;: the same report twice → stored once, the second send is a retry&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;attack silence&lt;/code&gt;: a team goes dark → nothing is reassigned until a person decides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then the storm: &lt;strong&gt;120 hostile writes in about three seconds&lt;/strong&gt;. Not one gets through, and FalkorDB answers each in milliseconds (the fenced report statement runs at about 2.5 ms p95 inside FalkorDB).&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory that outlives the exercise
&lt;/h2&gt;

&lt;p&gt;When an exercise ends, Cordon distils what it taught into a separate memory graph that no reset touches: how long a silent team's worksite waited for a person, and how late the report arrived. The lessons are derived from the graph's own record, never written by a model, and the agents recall them over MCP.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's built
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FalkorDB 4.22.&lt;/strong&gt; Every statement is a named Cypher constant that passes a lint: writes anchored on indexed keys, exactly one clock bump and one event per write, time only from the server clock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python + FastAPI&lt;/strong&gt; for the API, with &lt;strong&gt;MCP&lt;/strong&gt; tools for agents. No agent has a tool to approve a reassignment; that stays with a person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Groq&lt;/strong&gt; models (&lt;code&gt;openai/gpt-oss-120b&lt;/code&gt;, &lt;code&gt;qwen/qwen3.8-27b&lt;/code&gt;) for the field agents, the swarm and the coordinator's assistant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React + three.js&lt;/strong&gt; for the site: the fence in 3D on the real district, the swarm's arcs, and the crash test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real map data:&lt;/strong&gt; 3,068 OpenStreetMap buildings of Lajpat Nagar, with fictional damage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://cordon-crsvt.vercel.app" rel="noopener noreferrer"&gt;https://cordon-crsvt.vercel.app&lt;/a&gt;. Start with &lt;em&gt;Swarm&lt;/em&gt;, then &lt;em&gt;Rewind&lt;/em&gt;, then &lt;em&gt;Crash test&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/crsvt/Cordon" rel="noopener noreferrer"&gt;https://github.com/crsvt/Cordon&lt;/a&gt; (MIT)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP:&lt;/strong&gt; add Cordon to any MCP client:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cordon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://cordon-api-ukja.onrender.com/mcp/"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API runs on a free instance, so the first request after a quiet spell can take up to a minute to wake it.&lt;/p&gt;

&lt;p&gt;Rescue coordination is one place where "last writer wins" and "reject the stale writer" are both wrong. The late message may be the only record that someone is alive. Cordon fences the ownership and keeps the evidence.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built for Graph Hacks by WeMakeDevs × FalkorDB.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>falkordb</category>
      <category>ai</category>
      <category>database</category>
      <category>hackathon</category>
    </item>
  </channel>
</rss>
