<?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: aurumflux20</title>
    <description>The latest articles on DEV Community by aurumflux20 (@aurumflux20).</description>
    <link>https://dev.to/aurumflux20</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%2F4072091%2F165c08c6-21da-4fcb-9eb2-9c127f9c71c7.png</url>
      <title>DEV Community: aurumflux20</title>
      <link>https://dev.to/aurumflux20</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aurumflux20"/>
    <language>en</language>
    <item>
      <title>I built a lie-detector for my AI coding agent. Its first run caught me.</title>
      <dc:creator>aurumflux20</dc:creator>
      <pubDate>Tue, 18 Aug 2026 00:29:59 +0000</pubDate>
      <link>https://dev.to/aurumflux20/i-built-a-lie-detector-for-my-ai-coding-agent-its-first-run-caught-me-5a98</link>
      <guid>https://dev.to/aurumflux20/i-built-a-lie-detector-for-my-ai-coding-agent-its-first-run-caught-me-5a98</guid>
      <description>&lt;p&gt;Your coding agent says "Done! All tests pass."&lt;/p&gt;

&lt;p&gt;Did anyone check?&lt;/p&gt;

&lt;p&gt;Not the summary it wrote — the actual exit code. Because there's a detail that turns out to matter enormously: &lt;strong&gt;the agent already wrote down everything it did.&lt;/strong&gt; Every command, every real exit code, sitting in a session transcript on your disk right now. Claude Code writes &lt;code&gt;.jsonl&lt;/code&gt;. Cursor, Devin, Copilot — they all keep a record.&lt;/p&gt;

&lt;p&gt;Nobody reads it.&lt;/p&gt;

&lt;p&gt;So I wrote something that does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea is embarrassingly simple
&lt;/h2&gt;

&lt;p&gt;Extract every checkable claim the agent made in prose ("tests pass", "pushed to main", "build succeeds"). Extract every command it actually ran, with the real exit code from the tool result. Then match them up.&lt;/p&gt;

&lt;p&gt;Four verdicts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;supported&lt;/strong&gt; — a matching command succeeded before the claim&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;weak&lt;/strong&gt; — it succeeded, but the evidence is a piped exit code (more on this below)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;unsupported&lt;/strong&gt; — no matching command found; the claim rests on nothing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;contradicted&lt;/strong&gt; — the last matching command &lt;em&gt;failed&lt;/em&gt;, and the agent claimed success anyway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is the interesting category.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then I pointed it at myself
&lt;/h2&gt;

&lt;p&gt;The first real run was on my own agent session — 51MB of transcript from a long day of building. I did not clean it up first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;audited: 743 commands, 79 checkable claims

  supported     20
  weak evidence 11   (piped exit codes)
  unsupported   46   (claims resting on nothing)
  CONTRADICTED   2   (claimed success; its own transcript says failure)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two of my own "done" messages were false, and my own transcript proved it. I just never looked.&lt;/p&gt;

&lt;p&gt;Here's the thing I didn't expect: &lt;strong&gt;the 11 "weak" ones were the most educational.&lt;/strong&gt; They're claims like "tests pass" where the only evidence is a command like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pytest &lt;span class="nt"&gt;-q&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That reports &lt;strong&gt;tail's&lt;/strong&gt; exit code, not pytest's. It is almost always 0. I had made exactly this mistake earlier in the very same session — declared a green test run that wasn't — which is why the detector flags the pattern at all. The scar became the feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Couldn't the agent just edit the transcript?"
&lt;/h2&gt;

&lt;p&gt;This was the first question everyone asked, and it's correct. If the thing being audited can rewrite the evidence, the audit is theatre.&lt;/p&gt;

&lt;p&gt;So the session file is hash-chained. Each entry's hash covers the fact &lt;em&gt;and&lt;/em&gt; the previous entry's hash. Edit any recorded fact, delete one, reorder them — every hash after it breaks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; coherence tamper-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Runs in a temp folder, ten seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. A check fails. No proof recorded.            → exit 1
2. The agent edits its session to claim it passed.
3. The check runs again.                        → exit 3, TAMPERED at entry 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The honest limit, stated plainly: this makes tampering &lt;strong&gt;detectable&lt;/strong&gt;, not impossible. It only holds if something the agent doesn't control runs the check — normally your CI, not the agent. Chaining catches the edit; it doesn't make the writer honest.&lt;/p&gt;

&lt;h2&gt;
  
  
  The harder question: what did it do that it never mentioned?
&lt;/h2&gt;

&lt;p&gt;"Did it lie about what it did" is one question. "Did it do something it never told me about" is the other one, and it's much harder, because you cannot prove a negative from a log.&lt;/p&gt;

&lt;p&gt;The usual responses are both bad: claim completeness anyway (a lie), or demand syscall-level sandboxing and ship nothing (which is where most of the industry sits).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;coherence scope&lt;/code&gt; takes a third road. It reports what it &lt;strong&gt;can&lt;/strong&gt; determine from the transcript — files written, hosts contacted, repos pushed, packages installed — and it reports what it &lt;strong&gt;cannot&lt;/strong&gt;, out loud, every time. A command like &lt;code&gt;bash deploy.sh&lt;/code&gt; or &lt;code&gt;eval "$X"&lt;/code&gt; can hide any effect in the world, so it gets marked &lt;strong&gt;OPAQUE&lt;/strong&gt; and counted.&lt;/p&gt;

&lt;p&gt;On my own session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;744 commands · 399 files touched · 20 hosts contacted
181 commands were OPAQUE — this report is bounded by them, and says so.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;181 out of 744. That's the honest answer, and a tool that told me "all clear" would have been lying.&lt;/p&gt;

&lt;p&gt;The rule underneath all of it: &lt;strong&gt;UNKNOWN never collapses into CLEAN.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I almost didn't write
&lt;/h2&gt;

&lt;p&gt;While preparing the numbers above, I archived the audit output to a JSON file so the article would cite verified data instead of remembered data.&lt;/p&gt;

&lt;p&gt;The archive was silently empty. A venv wasn't re-activated, the redirect swallowed the error, and the command exited 0.&lt;/p&gt;

&lt;p&gt;I caught it by checking the file's byte count instead of trusting the exit code.&lt;/p&gt;

&lt;p&gt;A tool about agents making unverified claims almost shipped an article full of unverified claims, because I trusted an exit code. I don't think that's ironic so much as instructive: this failure mode is not a character flaw in AI agents, it's what happens to anyone who doesn't check. That's why the numbers in this post come from an archived file committed to the repo, not from my memory of a terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it on your own agent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;coherence-check
coherence audit ~/.claude/projects/&amp;lt;your-project&amp;gt;/&amp;lt;session&amp;gt;.jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Free, Apache-2.0, no signup, no telemetry — it never phones home. It reads a file already on your disk.&lt;/p&gt;

&lt;p&gt;There's also a GitHub Action if you want claims gated at PR time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aurumflux20/coherence@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;prove&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;pytest -q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fair warning: I have not yet seen a report come back clean. Mine certainly didn't.&lt;/p&gt;

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

&lt;p&gt;If you run it and the verdicts are wrong, I'd genuinely like to know — the claim-matching is heuristic, and its false positives are its most interesting failure mode. It's an open repo; tell me where it's wrong.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>testing</category>
    </item>
    <item>
      <title>We scanned 671 MCP servers to see what happens when an agent retries</title>
      <dc:creator>aurumflux20</dc:creator>
      <pubDate>Tue, 11 Aug 2026 18:58:38 +0000</pubDate>
      <link>https://dev.to/aurumflux20/we-scanned-671-mcp-servers-to-see-what-happens-when-an-agent-retries-3pnc</link>
      <guid>https://dev.to/aurumflux20/we-scanned-671-mcp-servers-to-see-what-happens-when-an-agent-retries-3pnc</guid>
      <description>&lt;p&gt;Every timeout is a question nobody can answer: &lt;em&gt;did it happen?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An agent calls a tool. The call times out. The agent doesn't know whether the email sent, the invoice was created, the charge went through. So it retries — because that's what agents do. If nothing on either side of that call can tell the second attempt from the first, the effect happens twice.&lt;/p&gt;

&lt;p&gt;We wanted to know how common that is in practice, so we scanned the ecosystem: &lt;strong&gt;671 MCP servers, 27,153 declared tools.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What we found
&lt;/h2&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;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Servers scanned successfully&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;671&lt;/strong&gt; (of 755 attempted)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tools declared across them&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;27,153&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Servers performing real writes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;539 (80%)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Of those, with &lt;strong&gt;zero&lt;/strong&gt; visible idempotency guards&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;175 (32%)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Servers with retry logic &lt;em&gt;and&lt;/em&gt; zero guards&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Servers with money-adjacent tools and no visible guard&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Servers with no guard of any kind, anywhere&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;288 (42%)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The sharpest cut — servers that write, retry, and have no guard the scanner could see — is &lt;strong&gt;32 servers with 28,653 combined monthly downloads.&lt;/strong&gt; Those are the places where a timeout is most likely to become a duplicate.&lt;/p&gt;

&lt;p&gt;Among the 23 largest servers we scanned (10,000+ downloads/month), &lt;strong&gt;6 perform writes with no visible guard.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What this scan cannot see — read this before quoting the numbers
&lt;/h2&gt;

&lt;p&gt;This is the most important section, so it goes before the analysis rather than after.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A scanner reading a repository from the outside usually cannot prove a double-fire.&lt;/strong&gt; Three reasons, each of which we hit repeatedly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The guard often lives somewhere else.&lt;/strong&gt; Many servers call a backend that deduplicates on its own — a payment API keyed by a nonce, a database with a unique constraint. From the client repo, that protection is invisible. "No guard found" means &lt;em&gt;the scanner found none in this code&lt;/em&gt;, not "this software is unsafe."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A tool that looks like a write may not be one.&lt;/strong&gt; We found tools that appear to send payments but only return a link for a human to sign. Names lie in both directions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Our own scanner has been wrong.&lt;/strong&gt; An early version accused a repo of having zero idempotency guards while it shipped an entire module of them — a regex with no word boundary couldn't match &lt;code&gt;deriveIdempotencyKey&lt;/code&gt;. It hand-verified at 3 of 7 on its first real targets. Every pattern in the current version exists because an earlier one got something wrong.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So these numbers describe &lt;strong&gt;what is visible in public code&lt;/strong&gt;, not a safety verdict on any project. We're publishing aggregates and no names. If you want to know about a specific server, the honest answer is: read it, and ask the maintainer what the backend does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We also excluded failures rather than counting them as zeros:&lt;/strong&gt; 66 repositories failed to clone, 17 returned unparseable output, 1 crashed the scanner. A failed lookup is not a finding. Including them would have made every percentage look worse and been wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the pattern shows up so consistently
&lt;/h2&gt;

&lt;p&gt;Idempotency isn't hard because the code is hard. A lease, a key, a stored result — that's an afternoon. It's hard because it asks a question most systems never make explicit:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes two operations the same operation?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Get that answer too narrow and you get false duplicates: annoying, safe, loud. Get it too wide and you get silent data loss — two legitimately different actions collapsing into one, where the second silently returns the first one's receipt. That failure looks like success. Nobody investigates a transaction that appears to have worked.&lt;/p&gt;

&lt;p&gt;We learned this the expensive way. We proposed an idempotency key to a payments project derived from URL, amount, and wallet. A stranger pointed out it omitted payee, network, and asset — meaning two genuinely different purchases would have collapsed into one. Our fix would have been worse than the bug.&lt;/p&gt;

&lt;p&gt;MCP makes this sharper than ordinary API design, for a structural reason: &lt;strong&gt;the caller is a language model.&lt;/strong&gt; It doesn't know your retry semantics, it can't read your backend, and when a call fails ambiguously its instinct is to try again. In the servers we read, the tool schema is where that knowledge would have to live — and it's usually silent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually helps
&lt;/h2&gt;

&lt;p&gt;Three things, in order of effort:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Say it in the schema.&lt;/strong&gt; If a tool is unsafe to retry blindly, the description is the only place the model will read it. One sentence: &lt;em&gt;"if this times out, the operation may have completed — check before retrying."&lt;/em&gt; Costs nothing, and it's the single highest-leverage change we've seen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accept a caller-supplied key.&lt;/strong&gt; Let the caller mark two attempts as the same attempt. Don't derive it from the payload alone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make the choke point atomic.&lt;/strong&gt; Whatever admits the effect should also be what checks whether it already happened.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Check your own server
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx fencescan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero dependencies, no install, no account. It reports candidates and evidence, never verdicts, for the reasons above. If it flags something you know is guarded, that's a bug worth reporting to us — a false positive costs more than a miss.&lt;/p&gt;

&lt;p&gt;Methodology, the full pattern list, and the four failure modes we've fixed: &lt;a href="https://github.com/aurumflux20/fencescan" rel="noopener noreferrer"&gt;https://github.com/aurumflux20/fencescan&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to see the failure mode rather than read about it, here are 1,000 concurrent agents trying to charge the same card, with and without a guard: &lt;a href="https://aurumflux20.github.io/once-kernel-ts/" rel="noopener noreferrer"&gt;https://aurumflux20.github.io/once-kernel-ts/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;We build open-source retry-safety tooling (&lt;a href="https://github.com/aurumflux20/once-kernel-ts" rel="noopener noreferrer"&gt;once-kernel&lt;/a&gt;, &lt;a href="https://github.com/aurumflux20/effectfence" rel="noopener noreferrer"&gt;effectfence&lt;/a&gt;), which is why we had a scanner pointed at this in the first place. The numbers are the numbers either way — and the caveats above are what keep them worth reading.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I filed a bug report, got corrected by a stranger, and my "fix" would have made things worse</title>
      <dc:creator>aurumflux20</dc:creator>
      <pubDate>Mon, 10 Aug 2026 23:49:49 +0000</pubDate>
      <link>https://dev.to/aurumflux20/i-filed-a-bug-report-got-corrected-by-a-stranger-and-my-fix-would-have-made-things-worse-1hdi</link>
      <guid>https://dev.to/aurumflux20/i-filed-a-bug-report-got-corrected-by-a-stranger-and-my-fix-would-have-made-things-worse-1hdi</guid>
      <description>&lt;p&gt;I maintain a couple of open-source libraries for exactly-once execution — the problem where an agent retries a tool call after a timeout, doesn't know whether the first attempt landed, and ends up doing it twice. A charge, a message, a payment. Nothing crashes. It just happens twice.&lt;/p&gt;

&lt;p&gt;Part of the work is reading other people's MCP servers looking for this exact bug, and yesterday I found one: a payments tool that signs and sends a transaction on every call, with no idempotency key anywhere in its schema. I opened an issue. I proposed a fix: derive a default key from the URL, the amount, and the wallet, so a retried request collapses into one settlement.&lt;/p&gt;

&lt;p&gt;A stranger replied and told me my fix was wrong.&lt;/p&gt;

&lt;p&gt;Not wrong in a nitpick way. Wrong in a way that would have been worse than the bug I was reporting. My key was too narrow — it only looked at three fields. Two offers for the same resource, at the same price, from the same wallet, but with a &lt;strong&gt;different payee, network, or asset&lt;/strong&gt;, are different payments. My derivation would have collapsed them into one key. Which means: a legitimate second purchase would have silently returned the &lt;em&gt;first&lt;/em&gt; purchase's receipt.&lt;/p&gt;

&lt;p&gt;Sit with that for a second, because it's the part that made me actually stop and think. A double-charge is bad, but it's &lt;em&gt;visible&lt;/em&gt;. Someone sees two line items and files a dispute. A swallowed purchase looks like a &lt;strong&gt;success&lt;/strong&gt;. The buyer thinks they paid and got the thing. Nobody investigates a transaction that appears to have worked.&lt;/p&gt;

&lt;p&gt;I'd built a bug that hides better than the one I was fixing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I went wrong
&lt;/h2&gt;

&lt;p&gt;The actual mistake wasn't the three fields I chose. It's that I chose three fields &lt;em&gt;from a template&lt;/em&gt; instead of asking the only question that matters: &lt;strong&gt;what makes two operations the same operation, and what makes them different?&lt;/strong&gt; I pattern-matched to "amount + wallet + url" because that's what similar fixes usually look at. I never sat down and enumerated the full shape of "a payment" for this specific system.&lt;/p&gt;

&lt;p&gt;That's the actual lesson, and it's more general than payments: an idempotency key is a claim about identity. If you get the identity wrong in one direction, you get false duplicates (annoying, safe, loud). Get it wrong in the other direction, and you get silent data loss (dangerous, quiet, expensive). Most advice — mine included, until last week — only warns about the first kind.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually happened next
&lt;/h2&gt;

&lt;p&gt;I could tell you I gracefully updated my proposal and moved on. What I did was rewrite the PR with the wider key (adding &lt;code&gt;payTo&lt;/code&gt;, &lt;code&gt;network&lt;/code&gt;, and &lt;code&gt;asset&lt;/code&gt;), credit the person who caught it by name, and say plainly in the pull request that my original suggestion was wrong. Not because it's noble — because the alternative is worse. Silently fixing it and hoping nobody checks the diff against the original issue is how you end up with a reputation for being defensively wrong instead of gracefully wrong, and defensively wrong is the expensive kind.&lt;/p&gt;

&lt;p&gt;The PR is open now: &lt;a href="https://github.com/CryptoAPIs-io/cryptoapis-mcp-x402-pay/pull/2" rel="noopener noreferrer"&gt;https://github.com/CryptoAPIs-io/cryptoapis-mcp-x402-pay/pull/2&lt;/a&gt;. Whether it gets merged is a separate question from whether the correction was right. It was.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tool, if you want to check your own code
&lt;/h2&gt;

&lt;p&gt;I built a small scanner — &lt;code&gt;fencescan&lt;/code&gt; — that looks for tool calls in a codebase that could fire the same effect twice, and reports &lt;strong&gt;candidates with evidence&lt;/strong&gt;, never a verdict. No install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx fencescan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I built it partly &lt;em&gt;because&lt;/em&gt; of this experience. An outsider reading a repo usually can't prove a double-fire — the guard often lives in a service the repo calls, and a function that looks like a write might only build a payload for someone else to sign. The scanner's job is to point at the ten places worth reading closely, not to accuse anyone of anything. That restraint isn't modesty; an earlier, cruder version of this scanner was wrong on 4 of its first 7 real targets, for reasons that are genuinely interesting if you like that kind of postmortem (mostly: a regex with no word boundary couldn't match camelCase, so it accused a repo of having zero idempotency guards when it shipped an entire module of them).&lt;/p&gt;

&lt;p&gt;If it flags something in your code and you think it's wrong, that's worth an issue. A false positive here costs more than a miss — I'd rather know.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update, the day before publishing:&lt;/strong&gt; the first maintainer merge landed — the &lt;a href="https://github.com/TocharianOU/mcp-server-kibana" rel="noopener noreferrer"&gt;Kibana MCP server&lt;/a&gt; took the retry-safety note, and the maintainer's reply did two things at once: corrected an endpoint mixup in my own docstring (create-with-id is POST, not PUT — my slip, their catch), and then extended my finding one line further than I had — their 409 error message was advising callers to do the exact thing the new docs warn against. They asked if I wanted to fix that too. I did, same day. Which means this article's thesis held all the way through its own publication: the corrections flowed both directions, and both parties' code got safer. That's the whole point.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Repos: &lt;a href="https://github.com/aurumflux20/effectfence" rel="noopener noreferrer"&gt;effectfence&lt;/a&gt; (Rust), &lt;a href="https://github.com/aurumflux20/once-kernel-ts" rel="noopener noreferrer"&gt;once-kernel&lt;/a&gt; (TypeScript, with a Python twin), &lt;a href="https://github.com/aurumflux20/fencescan" rel="noopener noreferrer"&gt;fencescan&lt;/a&gt;. All MIT/Apache, no strings.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>typescript</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
