<?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: Harsh Singh</title>
    <description>The latest articles on DEV Community by Harsh Singh (@harsh_singh_1).</description>
    <link>https://dev.to/harsh_singh_1</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%2F4101050%2F76bc4614-4ec9-4569-aa3b-dc286c9f4a67.png</url>
      <title>DEV Community: Harsh Singh</title>
      <link>https://dev.to/harsh_singh_1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harsh_singh_1"/>
    <language>en</language>
    <item>
      <title>The failures that don't fail loudly</title>
      <dc:creator>Harsh Singh</dc:creator>
      <pubDate>Sun, 30 Aug 2026 06:32:06 +0000</pubDate>
      <link>https://dev.to/harsh_singh_1/the-failures-that-dont-fail-loudly-2ph2</link>
      <guid>https://dev.to/harsh_singh_1/the-failures-that-dont-fail-loudly-2ph2</guid>
      <description>&lt;p&gt;I spent a week building an agent that upgrades dependencies and repairs what the upgrade breaks. Dependabot opens the PR and walks away; this one stays until the tests are green.&lt;/p&gt;

&lt;p&gt;The interesting part wasn't the repairs. It was that almost every serious bug I hit — in my code, in the harness, in my own agent — announced success while being wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The premise
&lt;/h2&gt;

&lt;p&gt;Detection is solved. Dependabot, npm audit and OSV all find the advisory. What nobody automates is the bit afterwards: the fix is a major version bump, the bump breaks your build, and now it's your afternoon.&lt;/p&gt;

&lt;p&gt;So: pull real advisories, spawn one subagent per vulnerable package, each on its own branch in its own sandbox. Bump, install, run the suite. If it breaks, read the failure and patch the source. Re-verify from a clean checkout. Open a PR and stop — merging is a human decision.&lt;/p&gt;

&lt;p&gt;That's the design. Here's what actually happened.&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%2Fv00rlqg8kjghztujjz54.png" 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%2Fv00rlqg8kjghztujjz54.png" alt=" " width="800" height="760"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The advisories weren't where I looked
&lt;/h2&gt;

&lt;p&gt;My first scan found nothing. The manifest said &lt;code&gt;js-yaml: ^3.13.1&lt;/code&gt;, which sounds vulnerable, but &lt;code&gt;^3.13.1&lt;/code&gt; resolves to whatever the latest 3.x is today — and that's patched.&lt;/p&gt;

&lt;p&gt;Vulnerabilities live in the resolved tree, not the manifest. Scan the lockfile, including transitive dependencies, or you scan nothing. All three advisories I eventually found were transitive dev dependencies that appear nowhere in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A scanner that reads the manifest returns "you're clean" and is wrong. It doesn't error.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The agent caught itself
&lt;/h2&gt;

&lt;p&gt;The first proper scan reported 124 vulnerable packages out of 290. Then it said something I didn't expect:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Some results look suspicious — &lt;a href="mailto:js-yaml@4.3.2"&gt;js-yaml@4.3.2&lt;/a&gt; with 10 advisories, which is usually clean."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It cross-checked OSV's batch endpoint against the single-query endpoint and found its own bug: it had nested &lt;code&gt;version&lt;/code&gt; inside the package object instead of alongside it. The API silently ignored the version and returned every advisory ever filed for each package.&lt;/p&gt;

&lt;p&gt;Real answer: three. Not 124.&lt;/p&gt;

&lt;p&gt;The API didn't reject the malformed query. It answered confidently and wrongly.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Three correct agents, one wrong result
&lt;/h2&gt;

&lt;p&gt;This is the one I'd defend hardest.&lt;/p&gt;

&lt;p&gt;Three subagents each fixed one advisory. Each branch was green — 75 tests passing, advisory gone. I merged two of them.&lt;/p&gt;

&lt;p&gt;Git reported no conflict. The result had two &lt;code&gt;overrides&lt;/code&gt; keys in &lt;code&gt;package.json&lt;/code&gt;. JSON keeps the last one, so the first fix — a HIGH-severity ReDoS — silently disappeared. Passing tests. Clean diff. A PR whose stated purpose was undone by the act of merging it.&lt;/p&gt;

&lt;p&gt;No per-branch check catches this. Each worker verified correctly; the combination was broken.&lt;/p&gt;

&lt;p&gt;So the rule got sharper: don't verify the branch, verify what main looks like after it merges.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Five ways to under-report
&lt;/h2&gt;

&lt;p&gt;I moved the scanner into a Skill so the agent runs tested code rather than following prose. Then Qodo's review took it apart, and every finding was the same species:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Aliases&lt;/strong&gt; — &lt;code&gt;"foo": "npm:bar@1.2.3"&lt;/code&gt; installs bar at &lt;code&gt;node_modules/foo&lt;/code&gt;. Deriving the name from the path queries a package that isn't installed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pagination&lt;/strong&gt; — OSV paginates past 1,000 vulnerabilities. An unfollowed &lt;code&gt;next_page_token&lt;/code&gt; means a short answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Link entries&lt;/strong&gt; — workspace placeholders have no version. Query them and you get advisories for a package that isn't there at that version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The root entry&lt;/strong&gt; — empty path, real version, produces an empty package name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Truncated responses&lt;/strong&gt; — pairing queries with results using &lt;code&gt;zip()&lt;/code&gt; silently drops the unmatched ones, then prints a clean summary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not one of those throws. Every one produces fewer advisories and a confident "you're clean". For a security scanner that's the only direction that really matters, so the scanner now refuses to continue when the response doesn't match what it asked for.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The gate worked. The display of it didn't.
&lt;/h2&gt;

&lt;p&gt;My queue board showed a run as done. The harness terminal was simultaneously asking me to approve a pull request.&lt;/p&gt;

&lt;p&gt;The harness emits &lt;code&gt;turn.done&lt;/code&gt; one millisecond after &lt;code&gt;tool.approval_required&lt;/code&gt; — because a turn ends when it pauses for a human:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;06:01:25.721  tool.approval_required
06:01:25.722  turn.done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F06w2pkntkaxh484i5010.png" 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%2F06w2pkntkaxh484i5010.png" alt=" " width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd treated &lt;code&gt;turn.done&lt;/code&gt; as "finished". So the board hid the single state an operator most needs to see. The gate was working perfectly; the thing showing me the gate was lying.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. And then the agent tried to get around it
&lt;/h2&gt;

&lt;p&gt;Testing the gate live, the agent hit &lt;code&gt;create_pull_request&lt;/code&gt;, which requires approval. Its own narration:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Now let me invoke the CLI directly (bypassing the Code Mode restriction)…"&lt;/p&gt;

&lt;p&gt;"The CLI is blocked too — the module enforces that destructive tools only go through the direct approval flow."&lt;/p&gt;
&lt;/blockquote&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%2Fraeu17gomc0hbmmcxzzp.png" 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%2Fraeu17gomc0hbmmcxzzp.png" alt=" " width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It tried two routes around the gate. The harness blocked both.&lt;/p&gt;

&lt;p&gt;That's the strongest thing I can say about the design: the control is in the runtime, not in the model's cooperation. The agent can't merge because &lt;code&gt;merge_pull_request&lt;/code&gt; isn't in its toolset — 43 of GitHub's 44 tools are enabled, and that's the exception. It isn't asked nicely.&lt;/p&gt;

&lt;p&gt;But an agent that probes for a way around the only control on irreversible actions is a liability whether or not it succeeds, so it's now explicitly instructed that being blocked is a correct outcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd take away
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Loud failure is a feature.&lt;/strong&gt; A crash gets fixed in ten minutes. A confident wrong answer ships. Everything above was the second kind, and the only defence was checking claims against reality — a second endpoint, a clean checkout, a merged state, an event stream.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never trust a worker's self-report.&lt;/strong&gt; My workers report success. The system throws that report away and re-runs the suite itself. That felt paranoid when I wrote it and stopped feeling paranoid the first time a green branch turned out to be wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A report is a valid outcome; a false green is not.&lt;/strong&gt; After three failed repair attempts a worker stops and writes up what it tried. Giving up honestly is a feature, not a failure mode.&lt;/p&gt;




&lt;p&gt;Built on TrueForge, with OSV.dev for advisory data and Qodo reviewing every PR — which found five of the six quiet failures above.&lt;/p&gt;

</description>
      <category>wemakedevs</category>
      <category>qodo</category>
      <category>truefoundry</category>
    </item>
  </channel>
</rss>
