<?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: Anish Prakash</title>
    <description>The latest articles on DEV Community by Anish Prakash (@anish_prakash1).</description>
    <link>https://dev.to/anish_prakash1</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%2F4072430%2F3aec6781-e149-4b11-aeeb-1ab57700e54e.jpg</url>
      <title>DEV Community: Anish Prakash</title>
      <link>https://dev.to/anish_prakash1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anish_prakash1"/>
    <language>en</language>
    <item>
      <title>Everything Was Working Exactly As Documented. The Answer Was Still Wrong.</title>
      <dc:creator>Anish Prakash</dc:creator>
      <pubDate>Sun, 30 Aug 2026 16:35:21 +0000</pubDate>
      <link>https://dev.to/anish_prakash1/everything-was-working-exactly-as-documented-the-answer-was-still-wrong-42a6</link>
      <guid>https://dev.to/anish_prakash1/everything-was-working-exactly-as-documented-the-answer-was-still-wrong-42a6</guid>
      <description>&lt;p&gt;I spent a weekend building a supply-chain auditor for dependency lockfiles. It has no dependencies. That part is a gimmick — it was the rule of the &lt;a href="https://zerodepshack.com/" rel="noopener noreferrer"&gt;Zero Dependency Hackathon&lt;/a&gt;, where the whole event is one constraint: your dependency manifest ships empty, standard library only.&lt;/p&gt;

&lt;p&gt;The gimmick is not what I want to write about.&lt;/p&gt;

&lt;p&gt;What I want to write about is that almost every bug I hit that weekend had the same shape. A mechanism was working exactly as its documentation said it would, and the answer coming out the other end was wrong anyway. Not broken — &lt;em&gt;working&lt;/em&gt;, and wrong. By Sunday I'd seen it four times, and by the fourth I realised it was also a decent description of how supply-chain attacks get past everybody.&lt;/p&gt;

&lt;p&gt;Here's the tour.&lt;/p&gt;




&lt;h2&gt;
  
  
  The rule that cried wolf
&lt;/h2&gt;

&lt;p&gt;The tool is called &lt;code&gt;stranger&lt;/code&gt;. You point it at a &lt;code&gt;package-lock.json&lt;/code&gt;, &lt;code&gt;Cargo.lock&lt;/code&gt;, or &lt;code&gt;requirements.txt&lt;/code&gt; and it reconstructs the transitive dependency graph and tells you what's in there: how much of the tree nobody chose, what runs code during &lt;code&gt;install&lt;/code&gt;, what arrived without an integrity hash, and which names sit one keystroke away from something popular.&lt;/p&gt;

&lt;p&gt;That last one is the reason the project exists. Roughly &lt;a href="https://www.usenix.org/conference/usenixsecurity25" rel="noopener noreferrer"&gt;19.7% of packages suggested by AI coding models don't exist&lt;/a&gt;, the invented names repeat, and attackers pre-register them. It's a supply-chain attack where the victim never even makes a typo — the model does it for them.&lt;/p&gt;

&lt;p&gt;So: bounded Damerau-Levenshtein against a list of widely-installed package names, flag anything within two edits. Damerau rather than plain Levenshtein because the most common typo is a transposition — &lt;code&gt;axois&lt;/code&gt;, &lt;code&gt;lodahs&lt;/code&gt;, &lt;code&gt;python-dotnev&lt;/code&gt; — and Levenshtein charges 2 for a swap, the same as two unrelated edits, which puts real squats outside a distance-1 ball.&lt;/p&gt;

&lt;p&gt;I ran it against a real 665-package tree. It reported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;etag&lt;/code&gt; is 2 edits from &lt;code&gt;tar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;depd&lt;/code&gt; is 2 edits from &lt;code&gt;del&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exit&lt;/code&gt; is 2 edits from &lt;code&gt;next&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bser&lt;/code&gt; is 2 edits from &lt;code&gt;bson&lt;/code&gt;
Every one of those is true. Every one is worthless. Those are Express's own dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The edit-distance implementation was correct. The corpus was fine. The rule was doing precisely what I wrote it to do, and the output was garbage — because "within two edits" is a meaningless threshold when the name is four characters long. Two edits on &lt;code&gt;etag&lt;/code&gt; is half the string.&lt;/p&gt;

&lt;p&gt;Three gates fixed it, and only one of them is interesting:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Distance relative to length.&lt;/strong&gt; &lt;code&gt;d=1&lt;/code&gt; needs ≥5 characters, &lt;code&gt;d=2&lt;/code&gt; needs ≥8. Two edits on &lt;code&gt;python-dotenv&lt;/code&gt; is a typo; two edits on &lt;code&gt;etag&lt;/code&gt; is a different word.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare like with like.&lt;/strong&gt; &lt;code&gt;@jest/core&lt;/code&gt; is not a near-miss for &lt;code&gt;@types/node&lt;/code&gt; just because &lt;code&gt;core&lt;/code&gt; and &lt;code&gt;node&lt;/code&gt; are two apart.&lt;/li&gt;
&lt;li&gt;The third one is the next section.
After the fix, that same 665-package tree reports &lt;strong&gt;zero&lt;/strong&gt; high-severity findings, which is the correct answer for an ordinary project. I later ran it across every real lockfile on my machine — about 1,030 packages across two Next.js projects it had never seen — and got zero false positives.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The lesson isn't "tune your thresholds." It's that &lt;strong&gt;for a security tool, precision beats recall, badly&lt;/strong&gt;. A rule that fires on Express's own dependencies is a rule people turn off, and a disabled rule catches nothing. A scanner at 100% recall and 5% precision protects no one, because after the third false alarm nobody reads the output. I knew that in the abstract. I did not act like I knew it until I saw &lt;code&gt;etag&lt;/code&gt; accused of impersonating &lt;code&gt;tar&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you reach for when you can't reach the network
&lt;/h2&gt;

&lt;p&gt;Gate three is the one I'd keep if I could only keep one, and it exists purely because the hackathon rules wouldn't let me have a network.&lt;/p&gt;

&lt;p&gt;The obvious way to know whether &lt;code&gt;safer-buffer&lt;/code&gt; is a real package or a squat is to ask the registry for its download count. I couldn't. The rules put "projects that need a running third-party service" out of scope — and honestly, an auditor that phones a registry to tell you your registry is dangerous has a credibility problem anyway.&lt;/p&gt;

&lt;p&gt;So what popularity signal exists inside a lockfile?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In-degree.&lt;/strong&gt; How many packages in this tree independently depend on that one.&lt;/p&gt;

&lt;p&gt;A typosquat gets pulled in by one mistaken import — the developer, or the model, that reached for the wrong name. &lt;code&gt;safer-buffer&lt;/code&gt; gets pulled in by half the registry. So: if a suspicious-looking name has three or more independent dependents, demote the finding to informational. Not delete it — the evidence is weaker, not absent — but stop shouting.&lt;/p&gt;

&lt;p&gt;Here's what I didn't expect. &lt;strong&gt;In-degree is a better signal than download counts would have been.&lt;/strong&gt; A typosquat has a download count too; that's the entire point of registering it. What a squat cannot manufacture is thirty unrelated packages, maintained by different people, choosing to depend on it. Download counts measure how many people got fooled. In-degree measures how many maintainers made an independent judgement.&lt;/p&gt;

&lt;p&gt;I would never have written that rule with a network available. I'd have called the API, gotten a number, shipped it, and had a worse tool. The constraint didn't tax the design; it produced the design.&lt;/p&gt;

&lt;p&gt;That's the honest version of "constraints breed creativity," which I've always found a slightly smug thing to say. The mechanism isn't mystical. Removing the obvious option forces you to actually look at your problem, and sometimes the second-best-looking option turns out to be first.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three layers of a deterministic build that wasn't
&lt;/h2&gt;

&lt;p&gt;The event offered a +5 bonus for a reproducible build: compile twice, produce byte-identical output, publish both hashes.&lt;/p&gt;

&lt;p&gt;On Linux it worked first try. ELF carries no link timestamp; with &lt;code&gt;codegen-units=1&lt;/code&gt; and stripped symbols, two builds matched. I wrote "verified byte-identical" in the README and moved on.&lt;/p&gt;

&lt;p&gt;Then I ran the same check on Windows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer one.&lt;/strong&gt; &lt;code&gt;DIFFER&lt;/code&gt; at byte 249 — the COFF &lt;code&gt;TimeDateStamp&lt;/code&gt;. PE executables embed a link timestamp. Obvious, documented, and there's a documented fix: MSVC's &lt;code&gt;/Brepro&lt;/code&gt;, which replaces that field with a hash of the file contents instead of the clock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer two.&lt;/strong&gt; With &lt;code&gt;/Brepro&lt;/code&gt;, the builds &lt;em&gt;still&lt;/em&gt; differed. 69 bytes, across three sites, and the differing values weren't clock-shaped — &lt;code&gt;0x5E131510&lt;/code&gt; versus &lt;code&gt;0x87A635AA&lt;/code&gt;. Those are hashes. &lt;code&gt;/Brepro&lt;/code&gt; was working.&lt;/p&gt;

&lt;p&gt;It took me longer than I'd like to admit to see it. MSVC also emits a CodeView debug directory containing a PDB GUID, and that GUID is &lt;strong&gt;regenerated on every link&lt;/strong&gt;. &lt;code&gt;/Brepro&lt;/code&gt; hashes the whole file. Including the random GUID.&lt;/p&gt;

&lt;p&gt;The deterministic timestamp was faithfully, correctly reflecting a nondeterministic input.&lt;/p&gt;

&lt;p&gt;That's the sentence I keep coming back to. &lt;code&gt;/Brepro&lt;/code&gt; did not malfunction. It computed exactly the hash it promised to compute, of exactly the bytes it was given, and the result was garbage because one of those bytes was noise. &lt;code&gt;/DEBUG:NONE&lt;/code&gt; drops the debug directory, and both builds settle byte-identical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer three.&lt;/strong&gt; Fixed, committed, and I sent myself the verification command. It failed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;LINK : fatal error LNK1181: cannot open input file 'C:\Program Files\Git\Brepro.obj'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git Bash. MSYS rewrites any argument that looks like a Unix path into a Windows path before the program sees it, so &lt;code&gt;-C link-arg=/Brepro&lt;/code&gt; reached &lt;code&gt;link.exe&lt;/code&gt; as &lt;code&gt;C:/Program Files/Git/Brepro&lt;/code&gt;. The flag was correct. The shell edited it in transit. &lt;code&gt;MSYS_NO_PATHCONV=1&lt;/code&gt; turns that off, and the Makefile now exports it so nobody else has to find out.&lt;/p&gt;

&lt;p&gt;Three layers. Three mechanisms — a linker flag, a hash function, a shell — each doing exactly what its documentation says, composing into a wrong answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The pattern, and why it's the same problem the tool is about
&lt;/h2&gt;

&lt;p&gt;Somewhere in layer two it occurred to me that I was debugging the exact failure mode my program is supposed to detect.&lt;/p&gt;

&lt;p&gt;An integrity hash in a lockfile is a &lt;code&gt;/Brepro&lt;/code&gt;. It is a correct hash, honestly computed, over content that nobody pinned. When &lt;a href="https://www.sonatype.com/blog/npm-chalk-and-debug-packages-hit-in-software-supply-chain-attack" rel="noopener noreferrer"&gt;chalk and debug were compromised in September 2025&lt;/a&gt; — utilities with 2.6 billion combined weekly downloads — the attacker phished a maintainer and published through the front door. Every hash matched. Every signature verified. The mechanism worked perfectly and told you nothing, because it was measuring the wrong thing: not "is this the code you reviewed" but "is this the code the registry served."&lt;/p&gt;

&lt;p&gt;Same shape as the GUID. Same shape as &lt;code&gt;etag&lt;/code&gt; being two edits from &lt;code&gt;tar&lt;/code&gt; — a true statement, correctly computed, that answers a question nobody asked.&lt;/p&gt;

&lt;p&gt;This is, I think, the actually useful thing I took from the weekend, and it's why I stopped trying to make &lt;code&gt;stranger&lt;/code&gt; a scanner that tells you a package is bad. It can't. It has no CVE feed and no advisory database, because both need a network. What it can tell you is the &lt;em&gt;shape&lt;/em&gt; of your exposure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        665  packages in the tree
         22  you chose
        643  arrived with them

  #######################################. 97% of your tree is code nobody chose

  max depth 9  ·  1 run install scripts  ·  32 duplicated  ·  8 cycles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing there is a vulnerability. All of it is true whether or not anything has gone wrong yet, and none of it depends on a mechanism that might be faithfully reporting a value someone else controls.&lt;/p&gt;

&lt;p&gt;My favourite output from the whole build came from running it on my own Next.js project — nine hops from a single dev dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eslint-config-next → eslint-plugin-import → array-includes → es-abstract
  → typed-array-byte-offset → reflect.getprototypeof → which-builtin-type
  → is-async-function → async-function@1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nobody chose &lt;code&gt;async-function&lt;/code&gt;. Nobody reviewed it. Nobody is watching its releases. It ships anyway.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the standard library made painful
&lt;/h2&gt;

&lt;p&gt;The honest accounting, because a post that says the constraint was free is lying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing a JSON parser is easy. Writing a correct one is not.&lt;/strong&gt; 569 lines to replace &lt;code&gt;serde_json&lt;/code&gt; — and &lt;code&gt;serde_json&lt;/code&gt; doesn't arrive alone, it brings &lt;code&gt;serde&lt;/code&gt;, &lt;code&gt;serde_derive&lt;/code&gt;, &lt;code&gt;syn&lt;/code&gt;, &lt;code&gt;quote&lt;/code&gt;, &lt;code&gt;proc-macro2&lt;/code&gt;: five crates and two procedural macros that execute arbitrary code in your build, to read a text file.&lt;/p&gt;

&lt;p&gt;The parser was maybe two hours. The &lt;em&gt;strictness&lt;/em&gt; was the rest of the day, and it's where hand-rolled parsers quietly go wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Surrogate pairs.&lt;/strong&gt; &lt;code&gt;"\ud83d\ude00"&lt;/code&gt; is one emoji. A lone &lt;code&gt;\ud800&lt;/code&gt; must be an error, not U+FFFD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raw control characters&lt;/strong&gt; inside strings are invalid JSON. Accepting them means accepting input other parsers reject — which is a fun way to disagree with your own CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The number grammar.&lt;/strong&gt; &lt;code&gt;01&lt;/code&gt; is not a number. Neither is &lt;code&gt;.5&lt;/code&gt;, &lt;code&gt;1.&lt;/code&gt;, or &lt;code&gt;+1&lt;/code&gt;. Leading zeros in particular are how an octal reading gets smuggled past a lenient reader.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A depth cap&lt;/strong&gt;, because a recursive-descent parser meeting 100,000 nested &lt;code&gt;[&lt;/code&gt; is a stack overflow, and this program reads files an attacker may have written.
I tested it against a 30-case must-reject corpus modelled on JSONTestSuite. Getting the &lt;code&gt;n_&lt;/code&gt; cases right is the entire difference between "reads my file" and "is a JSON parser."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;serde_json&lt;/code&gt; is also faster than mine, and has a &lt;code&gt;Deserialize&lt;/code&gt; derive so every field access isn't an explicit &lt;code&gt;get("version").and_then(as_str)&lt;/code&gt;. I'd still use it in production. That isn't the same as needing it here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where I stopped, and said so.&lt;/strong&gt; The &lt;code&gt;Cargo.lock&lt;/code&gt; reader is not a TOML implementation — no inline tables, no dotted keys, no datetimes. It's the subset Cargo emits, and where the subset ends it returns &lt;code&gt;"inline tables are outside the Cargo.lock subset this reader implements"&lt;/code&gt; rather than guessing. A parser that silently mis-reads input it doesn't understand is worse than one that refuses it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where I just lost.&lt;/strong&gt; The report is a fixed 78 columns. Terminal width detection needs either an &lt;code&gt;unsafe&lt;/code&gt; ioctl — the file is &lt;code&gt;#![forbid(unsafe_code)]&lt;/code&gt; — or shelling out to &lt;code&gt;stty&lt;/code&gt;, which is a hidden dependency on an external binary. So it doesn't adapt. That's a real limitation, not a solved problem, and it's in the README as one.&lt;/p&gt;




&lt;h2&gt;
  
  
  The package I made look unnecessary
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;serde_json&lt;/code&gt;, for the reasons above. But the one that actually surprised me was &lt;code&gt;chalk&lt;/code&gt; — 319 million weekly downloads.&lt;/p&gt;

&lt;p&gt;ANSI colour is &lt;code&gt;\x1b[31;1m&lt;/code&gt;. Those escape codes have been stable since 1979. They are four characters.&lt;/p&gt;

&lt;p&gt;What &lt;code&gt;chalk&lt;/code&gt; actually sells is not the codes. It's the answer to &lt;em&gt;when to emit them&lt;/em&gt;, because writing colour into a pipe corrupts every downstream &lt;code&gt;grep&lt;/code&gt;. That's a real problem, and it's worth something. It is worth about three lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="nf"&gt;.value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"always"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"never"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;var_os&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"NO_COLOR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.is_some&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.is_terminal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicit flag wins, then &lt;code&gt;NO_COLOR&lt;/code&gt;, then TTY detection. &lt;code&gt;IsTerminal&lt;/code&gt; has been in &lt;code&gt;std&lt;/code&gt; since Rust 1.70. Three hundred and nineteen million weekly downloads for a decision tree with three branches.&lt;/p&gt;

&lt;p&gt;I'm not being smug about it — I've installed &lt;code&gt;chalk&lt;/code&gt; without thinking, too. That's the point. The registry is full of packages that exist because at some moment it was easier to add a line to a manifest than to think for ninety seconds, and each one is a maintainer account, a publish token and a release pipeline you've quietly agreed to trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  The bug my own evidence caught
&lt;/h2&gt;

&lt;p&gt;One more, because it's the most embarrassing and therefore probably the most useful.&lt;/p&gt;

&lt;p&gt;Before submitting, I ran the tool across every real lockfile on my machine and committed the output as a field test — the idea being that rules tuned on two fixtures are a weak basis for claiming precision.&lt;/p&gt;

&lt;p&gt;Reading my own evidence file, I found &lt;code&gt;stranger&lt;/code&gt; reporting:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;core-js&lt;/code&gt; is a one-liner carried as a dependency&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;core-js&lt;/code&gt; is a polyfill suite of roughly 150,000 lines.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;advice&lt;/em&gt; was defensible — modern runtimes make it unnecessary — but that's a different argument from the one the rule was making, and the rule was making its argument in a way I couldn't defend. &lt;code&gt;core-js&lt;/code&gt; and &lt;code&gt;es6-promise&lt;/code&gt; came off the list, the finding got retitled to "is a standard-library call carried as a dependency," and there's now a test that fails if any large library gets added back.&lt;/p&gt;

&lt;p&gt;A rule is worth as much as its least defensible entry. &lt;code&gt;core-js&lt;/code&gt; was going to be the line a reviewer quoted.&lt;/p&gt;

&lt;p&gt;The field test wasn't confirmation. It was the thing that caught the defect — which is the only reason to run one.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's actually in the box
&lt;/h2&gt;

&lt;p&gt;4,549 lines of Rust in a single file, 64 tests on the standard-library harness, no test crate. Ten sections: an RFC 8259 JSON parser, a Cargo.lock reader, a &lt;code&gt;requirements.txt&lt;/code&gt; reader, bounded Damerau-Levenshtein with confusable-glyph folding (&lt;code&gt;cha1k&lt;/code&gt; and &lt;code&gt;chalk&lt;/code&gt; reduce to the same skeleton), an embedded corpus of 454 npm names and 50 genuinely-trivial packages, a graph engine that reproduces Node's own resolution algorithm, nine offline rules, an ANSI reporter, an argument parser, and the tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cargo tree
&lt;span class="go"&gt;stranger v1.0.0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole tree. &lt;code&gt;Cargo.lock&lt;/code&gt; has one &lt;code&gt;[[package]]&lt;/code&gt; block and it's this program. The tool audits itself as part of the dependency proof and reports zero packages, which is a slightly smug thing to put in a CI job and I did it anyway.&lt;/p&gt;

&lt;p&gt;Repo: &lt;strong&gt;&lt;a href="https://github.com/AnishPrakash/stranger" rel="noopener noreferrer"&gt;github.com/AnishPrakash/stranger&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The thing I'd tell past-me on Friday
&lt;/h2&gt;

&lt;p&gt;Not "avoid dependencies." I'm not against libraries, and neither is the event — the rules say as much. &lt;code&gt;serde_json&lt;/code&gt; is better than what I wrote. &lt;code&gt;chalk&lt;/code&gt; solves a real problem.&lt;/p&gt;

&lt;p&gt;What I'd say is: &lt;strong&gt;the mechanisms you're trusting are almost never lying to you, and that's exactly why they're dangerous.&lt;/strong&gt; &lt;code&gt;/Brepro&lt;/code&gt; computed an honest hash of a random number. &lt;code&gt;npm audit&lt;/code&gt; returns clean on a package that was compromised this morning through the front door. An integrity hash matches a tarball that was republished under the same version. Edit distance correctly reports that &lt;code&gt;etag&lt;/code&gt; is two characters from &lt;code&gt;tar&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every one of those is a correct answer. Whether it's a &lt;em&gt;useful&lt;/em&gt; one depends entirely on whether the question it answers is the question you were asking — and that's not something the mechanism can tell you. You have to go and look.&lt;/p&gt;

&lt;p&gt;Which, incidentally, is the whole argument for occasionally building the thing yourself. Not because your version will be better. Because you can't inspect a question you never had to ask.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for the &lt;a href="https://zerodepshack.com/" rel="noopener noreferrer"&gt;Zero Dependency Hackathon&lt;/a&gt; run by Hackathon Raptors, August 2026. Track A, Rust, standard library only.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Tag:&lt;/strong&gt; &lt;a href="https://dev.to/raptorsdev"&gt;@raptorsdev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>security</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Ported QOI to Rust. Here's What Almost Broke It.</title>
      <dc:creator>Anish Prakash</dc:creator>
      <pubDate>Tue, 11 Aug 2026 06:50:49 +0000</pubDate>
      <link>https://dev.to/anish_prakash1/i-ported-qoi-to-rust-heres-what-almost-broke-it-2g0</link>
      <guid>https://dev.to/anish_prakash1/i-ported-qoi-to-rust-heres-what-almost-broke-it-2g0</guid>
      <description>&lt;p&gt;The &lt;a href="https://github.com/phoboslab/qoi" rel="noopener noreferrer"&gt;PortMortem hackathon&lt;/a&gt; asked participants to choose a track and then within the track pick a library and port it — cleanly, correctly, and provably. I picked &lt;strong&gt;QOI&lt;/strong&gt; (the "Quite OK Image Format" by phoboslab), a fast lossless image codec in a single 649-line header file.&lt;/p&gt;

&lt;p&gt;QOI looked deceptively simple. It wasn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why QOI
&lt;/h2&gt;

&lt;p&gt;Most libraries have layers. QOI is a single header: &lt;code&gt;qoi.h&lt;/code&gt;. One encoder, one decoder, ~650 lines, no dependencies. That sounds easy to port.&lt;/p&gt;

&lt;p&gt;What it actually means is there's nowhere to hide. Every line has to be correct. Every edge case in the C has to be made explicit in Rust. That's the whole game.&lt;/p&gt;

&lt;p&gt;Final numbers: &lt;strong&gt;0 unsafe blocks, 0 core library dependencies, byte-for-byte identical output to the C reference, 22 integration tests, 27,966,810 fuzz iterations — zero divergences.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Decision That Mattered Most: Ditching the Union
&lt;/h2&gt;

&lt;p&gt;The central type in QOI's C source is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;qoi_rgba_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;v&lt;/code&gt; field is load-bearing. It lets the encoder check &lt;code&gt;px.v == px_prev.v&lt;/code&gt; — one 32-bit integer compare to detect if all four channels are unchanged. Clean, clever, and completely &lt;code&gt;unsafe&lt;/code&gt; in Rust if you try to replicate it literally.&lt;/p&gt;

&lt;p&gt;My translation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Copy,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;Default,&lt;/span&gt; &lt;span class="nd"&gt;Debug)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Pixel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;#[derive(PartialEq)]&lt;/code&gt; generates a four-field comparison. At &lt;code&gt;-O2&lt;/code&gt;, LLVM folds that into a single 32-bit integer compare — &lt;em&gt;the exact same machine code&lt;/em&gt; as &lt;code&gt;px.v == px_prev.v&lt;/code&gt;. The compiler does the work a human would otherwise do unsafely. Zero &lt;code&gt;unsafe&lt;/code&gt; needed.&lt;/p&gt;

&lt;p&gt;That was the cleanest decision in the whole port.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Edge Case That Will Eat You Alive
&lt;/h2&gt;

&lt;p&gt;The decoder maintains a 64-slot running index array of recently-seen pixels. When a new chunk is decoded, the index is updated. When a RUN chunk is processed (repeating the previous pixel N times), the index is &lt;em&gt;not&lt;/em&gt; updated.&lt;/p&gt;

&lt;p&gt;In C:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;chunks_len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// decode chunk...&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;QOI_COLOR_HASH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// ← INSIDE this block&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This seems obvious when you read it slowly. At 2am with a test that's almost passing, it's invisible. Placing that index update &lt;em&gt;outside&lt;/em&gt; the &lt;code&gt;else if&lt;/code&gt; — so it also runs during run-length repetitions — will produce output that looks correct on simple images and breaks on anything that mixes RUN and INDEX chunks.&lt;/p&gt;

&lt;p&gt;I got this right on the first pass only because I was reading the C spec annotation carefully. The subtlety is documented as Decision #7 in my DECISIONS.md, but naming it doesn't convey how easy it is to get wrong. This is the one I'd warn every QOI porter about.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Actually Broke: The Fuzz Harness
&lt;/h2&gt;

&lt;p&gt;My plan was to use &lt;code&gt;cargo-fuzz&lt;/code&gt; with &lt;code&gt;libfuzzer-sys&lt;/code&gt; — the obvious Rust equivalent of the original &lt;code&gt;qoifuzz.c&lt;/code&gt;. The harness compiled fine. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STATUS_DLL_NOT_FOUND (exit code: 0xc0000135)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;libFuzzer on Windows (MINGW64) requires runtime DLLs — &lt;code&gt;vcruntime140.dll&lt;/code&gt; etc. — that simply aren't present in the Git Bash environment. &lt;code&gt;cargo-fuzz&lt;/code&gt; is effectively Linux-only outside of WSL or a full MSVC setup.&lt;/p&gt;

&lt;p&gt;I replaced it with a standalone binary fuzzer using an &lt;strong&gt;xorshift64 PRNG&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;Xorshift64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// seeded from SystemTime&lt;/span&gt;
&lt;span class="c1"&gt;// ~470,000 iterations/second&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fuzzer mirrors &lt;code&gt;qoifuzz.c&lt;/code&gt;'s invariants exactly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First 4 bytes select &lt;code&gt;channels&lt;/code&gt; (0, 3, or 4)&lt;/li&gt;
&lt;li&gt;Remaining bytes are the payload passed to &lt;code&gt;decode()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A successful decode must roundtrip: &lt;code&gt;decode → encode → decode → same pixels&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: &lt;strong&gt;27,966,810 decode iterations and 2,296,853 roundtrip iterations in 60 seconds — zero panics, zero divergences.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The tradeoff is real: PRNG fuzzing has no coverage-guided corpus evolution. What it has is throughput — roughly 12× more iterations per second than a typical libFuzzer run. For a 60-second run, that's not nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Arithmetic: The One You Can't Skip
&lt;/h2&gt;

&lt;p&gt;QOI's diff encoding does this in C:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;signed&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;vr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;px_prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;b1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x03&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;C's unsigned char arithmetic wraps silently. Rust doesn't — in debug mode, it panics. In release mode it wraps, but invisibly.&lt;/p&gt;

&lt;p&gt;The fix isn't hard, but it has to be intentional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;vr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="py"&gt;.r&lt;/span&gt;&lt;span class="nf"&gt;.wrapping_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;px_prev&lt;/span&gt;&lt;span class="py"&gt;.r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;i8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="py"&gt;.r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="py"&gt;.r&lt;/span&gt;&lt;span class="nf"&gt;.wrapping_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dr&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Casting &lt;code&gt;i8(-2)&lt;/code&gt; to &lt;code&gt;u8&lt;/code&gt; gives &lt;code&gt;254&lt;/code&gt;. &lt;code&gt;wrapping_add(254u8)&lt;/code&gt; is subtracting 2 modulo 256. Same two's-complement behavior as C, made visible in the source. A future reader — or a security auditor — can verify the arithmetic without knowing C's implicit conversion rules.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Decision I'd Take Back
&lt;/h2&gt;

&lt;p&gt;The module split into &lt;code&gt;types.rs&lt;/code&gt;, &lt;code&gt;encode.rs&lt;/code&gt;, &lt;code&gt;decode.rs&lt;/code&gt;, &lt;code&gt;io.rs&lt;/code&gt; was the right call for readability. But I put all 22 integration tests in a single &lt;code&gt;tests/integration_test.rs&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;That file is long. It works, it's comprehensive, but it should have been split by module the same way the source is. &lt;code&gt;tests/encode_test.rs&lt;/code&gt;, &lt;code&gt;tests/decode_test.rs&lt;/code&gt;, &lt;code&gt;tests/roundtrip_test.rs&lt;/code&gt;. The test file ended up harder to navigate than any of the source files it was testing — which is exactly backwards.&lt;/p&gt;

&lt;p&gt;If I were starting over, test structure mirrors source structure, from day one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Behavioral Equivalence: How I Actually Proved It
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;22 integration tests&lt;/strong&gt; — all encoding paths (RUN, INDEX, DIFF, LUMA, RGB, RGBA chunks), RUN boundary conditions (63 vs 62 pixels), wrapping arithmetic on deliberate overflow inputs, channel override semantics, error paths.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Byte-for-byte diff against C reference&lt;/strong&gt; — compile &lt;code&gt;qoiconv.c&lt;/code&gt; with gcc, encode a corpus of PNGs with both, &lt;code&gt;diff&lt;/code&gt; the outputs. Every image passes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;27M+ fuzz iterations&lt;/strong&gt; — roundtrip invariant on pseudo-random byte streams. If the encoder and decoder disagree on anything, the harness finds it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these alone is sufficient. The fuzz harness won't find a bug that only appears on your specific test image. The integration tests won't find a bug that only appears on random inputs. You need all three layers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Port:&lt;/strong&gt; &lt;a href="https://github.com/AnishPrakash/qoi-rust" rel="noopener noreferrer"&gt;github.com/AnishPrakash/qoi-rust&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Original:&lt;/strong&gt; &lt;a href="https://github.com/phoboslab/qoi" rel="noopener noreferrer"&gt;github.com/phoboslab/qoi&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DECISIONS.md:&lt;/strong&gt; 15 architectural divergences, each with the C source, Rust translation, and why it matters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hackathon:&lt;/strong&gt; &lt;a href="https://coderesurrection.com/2026/" rel="noopener noreferrer"&gt;PortMortem&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tag:&lt;/strong&gt; &lt;a href="https://dev.to/raptorsdev"&gt;@raptorsdev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hackathonraptors</category>
      <category>portmortem</category>
      <category>c</category>
      <category>rust</category>
    </item>
  </channel>
</rss>
