<?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: Sai Ram Dash</title>
    <description>The latest articles on DEV Community by Sai Ram Dash (@ewwhardik).</description>
    <link>https://dev.to/ewwhardik</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%2F4109572%2F171c45ae-030a-4544-9128-282b34acdbd2.jpg</url>
      <title>DEV Community: Sai Ram Dash</title>
      <link>https://dev.to/ewwhardik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ewwhardik"/>
    <language>en</language>
    <item>
      <title>856,168 differential checks later: what it actually takes to delete your dependencies</title>
      <dc:creator>Sai Ram Dash</dc:creator>
      <pubDate>Fri, 04 Sep 2026 11:39:48 +0000</pubDate>
      <link>https://dev.to/ewwhardik/856168-differential-checks-later-what-it-actually-takes-to-delete-your-dependencies-4763</link>
      <guid>https://dev.to/ewwhardik/856168-differential-checks-later-what-it-actually-takes-to-delete-your-dependencies-4763</guid>
      <description>&lt;p&gt;Somewhere around check number three hundred thousand, my test harness stopped testing my code and started testing the code I was replacing.&lt;/p&gt;

&lt;p&gt;The check was &lt;code&gt;intersects('1.2.3-beta', '*')&lt;/code&gt;. Mine said false. &lt;code&gt;semver@7.8.5&lt;/code&gt; said false. Then the harness swapped the arguments, because a harness does not know that no reasonable person swaps the arguments, and the package said true.&lt;/p&gt;

&lt;p&gt;Same function, same two strings, opposite order, opposite answer. Intersection is symmetric in every definition of the word anybody has written down. One hundred and eighty-eight million weekly downloads disagree.&lt;/p&gt;

&lt;p&gt;I had built the harness to find my bugs. It found one of theirs, and then handed me a problem that no amount of testing solves: I had to decide which of us was right, and there is no authority to appeal to. That turned out to be the actual work. Not the typing.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;nirdep&lt;/code&gt;. &lt;strong&gt;nir&lt;/strong&gt; (Sanskrit निर्, "without") plus &lt;strong&gt;dep&lt;/strong&gt;. Say it "near-dep". It deletes your dependencies.&lt;/p&gt;

&lt;p&gt;It is two halves that only make sense together. The first is a runtime: five modules written against the Node standard library and nothing else, standing in for eleven packages people install without thinking about it, which is chalk, strip-ansi, supports-color, ansi-styles, semver, minimatch, glob, lodash, minimist, commander and yargs. The second is a codemod: a hand-written JavaScript lexer, a scope-aware binding resolver and a byte-range patcher, so that removing a dependency is a diff you read rather than a weekend you lose.&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%2F53mtn8eesx3b8kpqry3m.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%2F53mtn8eesx3b8kpqry3m.png" alt=" " width="800" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tool runs on its own runtime. Its help text is generated by the module that replaces commander, its colours come from the module that replaces chalk, and its version comparisons come from the module that replaces semver. That is the correctness argument, and it is a cheap one to check: if the replacements were bad, the tool would not start.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you would normally install, and what it actually took
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Normally installed&lt;/th&gt;
&lt;th&gt;What replaced it&lt;/th&gt;
&lt;th&gt;What it cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;chalk, strip-ansi, ansi-styles, supports-color&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;runtime/colour&lt;/code&gt;, 552 lines&lt;/td&gt;
&lt;td&gt;the escape codes are the easy part; capability detection is the work, and &lt;code&gt;FORCE_COLOR&lt;/code&gt; beating &lt;code&gt;NO_COLOR&lt;/code&gt; is a decision rather than a fact&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;semver&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;runtime/semver&lt;/code&gt;, 1,760 lines, no regular expressions&lt;/td&gt;
&lt;td&gt;507,316 differential checks, 72 audited disagreements, and 0.26 times the reference speed on &lt;code&gt;satisfies&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;minimatch, and the matching half of glob&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;runtime/glob&lt;/code&gt;, 1,149 lines, no regular expressions&lt;/td&gt;
&lt;td&gt;228,852 checks, 697 disagreements, every one bucketed by cause and pinned by count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;the seventeen lodash functions people actually reach for&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;runtime/collect&lt;/code&gt;, 994 lines&lt;/td&gt;
&lt;td&gt;120,000 comparisons over 8,000 seeded rounds, eleven pinned divergences&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;minimist, commander, yargs&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;runtime/args&lt;/code&gt;, 990 lines&lt;/td&gt;
&lt;td&gt;rewritten by hand at every call site on purpose, which I will come back to&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The four reference packages I could measure on disk install 2,085,975 bytes across 1,164 files. The five modules that replace them are 223,069 bytes in five files. That number is the good half of the trade. The bad half is that those five files are now mine to maintain forever, and the README says so in the same paragraph, because a write-up that reports only the good half is an advertisement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that shaped everything
&lt;/h2&gt;

&lt;p&gt;CVE-2022-25883 was a ReDoS in node-semver's range parser: hand it a range from an untrusted source and it hangs. CVE-2022-3517 was the same bug class in minimatch's brace expansion, inside the package semver itself depends on.&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%2Fwvj239jnql6v4z97mzwv.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%2Fwvj239jnql6v4z97mzwv.png" alt=" " width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Replace either one with my own regular expression and I would have shipped the same bug class with my name on it and called it progress. So the rule for both modules was: no regular expressions at all. Every scanner is a loop over character codes, and the matcher is two nested state-set simulations, one over path segments and one over the characters inside a segment. Work is positions times tokens. Backtracking is absent rather than patched.&lt;/p&gt;

&lt;p&gt;Claims like that rot, so the test does not trust me. &lt;code&gt;tests/repo/no-regex.test.mjs&lt;/code&gt; lexes both files with the project's own lexer, because &lt;code&gt;/&lt;/code&gt; is division, a comment and a regular expression, and only a tokeniser knows which one it is looking at. It fails if a single regexp literal survives, and it enforces a token floor, so a refactor that quietly deletes the matcher cannot pass by having nothing left to check.&lt;/p&gt;

&lt;p&gt;The price is on the invoice. &lt;code&gt;satisfies&lt;/code&gt; runs at 0.26 times the reference, it is in &lt;code&gt;bench.json&lt;/code&gt;, and I am not going to pretend a state machine beats a compiled regex at its own game. Two of the five went the other way and I did not plan either: the no-regex matcher runs at 1.37 times minimatch, and &lt;code&gt;cloneDeep&lt;/code&gt; at 1.40 times lodash. I would not have believed either claim without the numbers file, which is roughly why the numbers file exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  The difficulties, in the order they hurt
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The divergence audit was the project.&lt;/strong&gt; 507,316 checks against semver: 507,244 agreed and 72 did not. Every one of the 72 was then re-checked against the reference package's own &lt;code&gt;satisfies&lt;/code&gt;, and every one came back the same way, which is that the package contradicts itself. Fifty-six were &lt;code&gt;intersects&lt;/code&gt; cells and sixteen were &lt;code&gt;subset&lt;/code&gt;. Two more were crashes there and answers here.&lt;/p&gt;

&lt;p&gt;glob was 697 disagreements out of 228,852, and not one of them is a shrug. &lt;code&gt;print&lt;/code&gt; accounts for 576 of them, because their &lt;code&gt;[[:print:]]&lt;/code&gt; compiles as though it were &lt;code&gt;[[:cntrl:]]&lt;/code&gt;. &lt;code&gt;nonascii&lt;/code&gt; accounts for 91, because my POSIX classes are ASCII tables, which is a stated limit: &lt;code&gt;中&lt;/code&gt; is not &lt;code&gt;[[:alpha:]]&lt;/code&gt; here. &lt;code&gt;partial&lt;/code&gt; is 18 and &lt;code&gt;brace&lt;/code&gt; is 12. The counts are pinned, so a new disagreement lands in a bucket called &lt;code&gt;unknown&lt;/code&gt; and turns the suite red.&lt;/p&gt;

&lt;p&gt;The goal was never "it agrees with the package". The goal is that every place it does not agree is either a repaired bug or a decision somebody wrote down. A difference you cannot name is a gap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lodash taught &lt;code&gt;{}&lt;/code&gt; a new trick.&lt;/strong&gt; Try &lt;code&gt;_.set({}, 'toString.polluted', 'yes')&lt;/code&gt;. A blocklist of &lt;code&gt;__proto__&lt;/code&gt;, &lt;code&gt;constructor&lt;/code&gt; and &lt;code&gt;prototype&lt;/code&gt; does not save you, because &lt;code&gt;toString&lt;/code&gt; is not on the list. The walk follows an inherited property, materialises it on the object, and writes there. From then on every object in the program carries it, and &lt;code&gt;_.pick({}, 'toString')&lt;/code&gt; on a completely unrelated empty object hands the value straight back.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toString.polluted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// no error, nothing on the blocklist&lt;/span&gt;

&lt;span class="p"&gt;({}).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;polluted&lt;/span&gt;                   &lt;span class="c1"&gt;// 'yes', on every object in the program&lt;/span&gt;
&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pick&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toString&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="c1"&gt;// hands it back from an unrelated empty object&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix is not a longer list, it is a rule: a deep write never follows a property the object does not own. Which means my module behaves differently from the package it replaces, which means it belongs in the documented divergence list rather than being quietly described as compatible.&lt;/p&gt;

&lt;p&gt;lodash's dist runs in sloppy mode and an ESM module does not, so writes to frozen slots that silently did nothing there throw here. Every write now goes through &lt;code&gt;Reflect.set&lt;/code&gt; and every delete through &lt;code&gt;Reflect.deleteProperty&lt;/code&gt;: an impossible operation declines quietly with a lodash-compatible return value, and a dangerous one still throws. My first attempt swallowed the coercion complaints as well, which felt tidy and took the divergence count from three to eighty-seven. When the count goes up, put the change back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node ships no parser, and the honest door costs five hundred times the cheap one.&lt;/strong&gt; A codemod that writes a file it has not proved parses is a tool you use exactly once. There are three ways to reach a JavaScript parser without installing anything: &lt;code&gt;vm.Script&lt;/code&gt;, which rejects the word export and so cannot see modules at all; &lt;code&gt;vm.SourceTextModule&lt;/code&gt;, which needs a flag, and whose SyntaxError carries no position, so a failure has to be re-run through &lt;code&gt;node --check&lt;/code&gt; purely to learn which line broke; and spawning &lt;code&gt;process.execPath&lt;/code&gt; with &lt;code&gt;--check --input-type=module&lt;/code&gt;. The vm door costs 0.025ms and a function call. The spawn costs a process. Only the expensive one can see a module and tell you which line broke.&lt;/p&gt;

&lt;p&gt;Measured over 300 files: 8ms through the lexer pre-gate, 4,095ms through Node's real parser, one process per file. I kept the 4,095ms. The lexer is a free pre-filter that catches the obvious failures, and the spawn is the verdict. &lt;code&gt;bench.json&lt;/code&gt; prints both numbers side by side, so the price of being careful is visible rather than argued about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;const of = f(x)&lt;/code&gt; cost me an afternoon.&lt;/strong&gt; My binding resolver ends a declarator's pattern at &lt;code&gt;of&lt;/code&gt; or &lt;code&gt;in&lt;/code&gt;, because that is the shape of a for-of head. So &lt;code&gt;const of = f(x)&lt;/code&gt; ended before it began, no binding was recorded, and every later call to &lt;code&gt;of(item)&lt;/code&gt; was filed as a global. A rename would have missed every one of those sites and the diff would have looked fine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// pattern ends at `of`, so no binding is recorded&lt;/span&gt;
&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;// filed as a global, and a rename never touches it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What caught it was not a unit test of the resolver. It was a property test over the whole repository: every name the resolver leaves unresolved must be a real global in the running Node. Three leaked names, and the suite pointed straight at them. If I keep one habit from this project it is that one, because example-based tests only check the cases you already thought of.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The proof had to stay too blunt to fool.&lt;/strong&gt; &lt;code&gt;tools/verify.mjs&lt;/code&gt; reads every &lt;code&gt;.mjs&lt;/code&gt; file in the repository, extracts import specifiers by six different syntaxes, and fails unless every single one resolves to a relative path or to something &lt;code&gt;module.isBuiltin&lt;/code&gt; recognises. It deliberately does not read &lt;code&gt;package.json&lt;/code&gt;. An empty manifest says nobody declared a dependency; this says nobody imported one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ node tools/verify.mjs
nirdep -- zero-dependency proof
generated by: node tools/verify.mjs
node: v22.23.2   platform: linux

1. Manifest
PASS  package.json dependencies is empty (0 entries)
PASS  package.json devDependencies is empty (0 entries)
PASS  package.json peerDependencies is empty (0 entries)
PASS  package.json optionalDependencies is empty (0 entries)
PASS  no node_modules directory in the repository
PASS  no lockfile entries beyond the root package

2. Every import in the artifact resolves to a Node builtin or a relative path
PASS  540 import specifiers checked across 105 files

3. The standard library we actually use
      node:assert/strict   node:child_process   node:crypto   node:fs
      node:module          node:os              node:path     node:test
      node:url             node:util            node:vm       node:zlib
      12 builtin modules, 0 packages

RESULT: zero third-party runtime dependencies.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is also stupid on purpose, so it flags import-shaped text inside comments, strings and regular expression literals. The cost is real and slightly ridiculous: test fixtures live in JSON rather than in source, doc comments never write the word import followed by a quote, and one test builds its quote with &lt;code&gt;String.fromCharCode(39)&lt;/code&gt;. Adding an ignore pragma would have taken thirty seconds and destroyed the only thing the file is for. A blunt instrument nobody can fool is worth more than a clever one that can be.&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%2Faycku38qk5np9x4b0phl.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%2Faycku38qk5np9x4b0phl.png" alt=" " width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I am proudest of is a refusal
&lt;/h2&gt;

&lt;p&gt;Of the eleven packages, five are rewritable and six are advise-only, and a test asserts that the rewritable list stays shorter than the replaceable one, so the flattering ratio cannot quietly improve.&lt;/p&gt;

&lt;p&gt;minimist is advise-only even though &lt;code&gt;runtime/args&lt;/code&gt; replaces it outright. minimist hands back a flat bag of whatever it happened to find; &lt;code&gt;parse&lt;/code&gt; wants a declared spec. A codemod that treated those two as the same shape would print green and ship a broken program. supports-color, ansi-styles, commander, yargs and glob are advise-only for the same reason: the replacement exists, the shape differs, and no machine should be guessing at a call site.&lt;/p&gt;

&lt;p&gt;You can watch this land. The worked example declares six dependencies and installs twenty-three. &lt;code&gt;nirdep apply&lt;/code&gt; rewrites four files, and then the project will not start, because &lt;code&gt;Cannot find package 'minimist'&lt;/code&gt; is the correct output at that point rather than a bug. The walkthrough shows that error instead of cutting to the working version.&lt;/p&gt;

&lt;p&gt;One more refusal, and it is the one people ask about: nirdep never edits your &lt;code&gt;package.json&lt;/code&gt;. A tool that rewrites your manifest on your behalf is a tool you cannot trust with your imports.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one number that changed how I read tooling
&lt;/h2&gt;

&lt;p&gt;Removing glob from the example takes seven packages out of the tree. chalk takes six, semver takes three, lodash one, minimist one, and minimatch takes zero, because glob keeps minimatch alive.&lt;/p&gt;

&lt;p&gt;Add those up and you have accounted for eighteen of the twenty-two installed names. Remove all six together and all twenty-two go. The four that appear in nobody's column are minimatch and its own three children, shared by two dependencies, so owned alone by neither.&lt;/p&gt;

&lt;p&gt;Blast radius is a subtraction, not a sum: everything reachable from every root, minus everything still reachable from the roots that are staying. Any tool that reports it as a sum is overselling, and the honest version of that report is a worse-looking number.&lt;/p&gt;

&lt;p&gt;That minimatch row saying "removing it takes 0 packages out of the tree" is my favourite line in the whole output. It is the tool declining to round in its own favour.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Number&lt;/th&gt;
&lt;th&gt;What it counts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;third-party packages in the import graph, proved by reading imports rather than the manifest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Node builtins the entire project resolves to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;634&lt;/td&gt;
&lt;td&gt;tests in 55 files, on &lt;code&gt;node:test&lt;/code&gt;, with no test dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3,593&lt;/td&gt;
&lt;td&gt;conformance cases across the eleven packages replaced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;856,168&lt;/td&gt;
&lt;td&gt;differential checks against the packages being replaced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;769&lt;/td&gt;
&lt;td&gt;disagreements found on semver and glob, every one audited and given a cause&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14,287&lt;/td&gt;
&lt;td&gt;lines in 42 files under &lt;code&gt;src/&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;builds, byte for byte identical, both hashes published&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What seventy-two hours felt like
&lt;/h2&gt;

&lt;p&gt;Writing the modules was maybe a third of it. The rest went on the harnesses, and on the arguments the harnesses started.&lt;/p&gt;

&lt;p&gt;That ratio is the thing I did not expect. You do not get a replacement by writing a replacement. You get one by writing something whose job is to prove your replacement wrong, running it a few hundred thousand times, and then sitting with the disagreements one at a time until each has a name and a reason. Most of them will be your fault. A few will not be.&lt;/p&gt;

&lt;p&gt;A dependency is a promise about a stranger's future behaviour, and you cannot audit a promise. That is not a moral failing on anybody's part, it is just what the arrangement is. What you can audit is code you are able to read. Replacing a package does not delete the work, it moves the work somewhere your name is on it, and the only honest reason to do that is if you would rather own the bug than wait for the advisory.&lt;/p&gt;

&lt;p&gt;The 72 disagreements are the part I keep thinking about. Correctness is not really a property of code. It is a property of an argument somebody is prepared to make out loud. A package with 188 million weekly downloads has never had to make that argument about &lt;code&gt;intersects&lt;/code&gt;, because nobody swaps the arguments. I had to make it seventy-two times in one afternoon, and writing those arguments down turned out to be worth more than any of the code they were about.&lt;/p&gt;




&lt;p&gt;Repository: &lt;a href="https://github.com/ewwhardik/nirdep" rel="noopener noreferrer"&gt;https://github.com/ewwhardik/nirdep&lt;/a&gt;&lt;br&gt;
Playground, one HTML file, no network requests: &lt;a href="https://ewwhardik.github.io/nirdep/" rel="noopener noreferrer"&gt;https://ewwhardik.github.io/nirdep/&lt;/a&gt;&lt;br&gt;
Worked example, before and after: &lt;a href="https://github.com/ewwhardik/nirdep-example" rel="noopener noreferrer"&gt;https://github.com/ewwhardik/nirdep-example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Published by Nastik AI. Developed by Sai Ram Dash (Hardik).&lt;/p&gt;

</description>
      <category>hackathonraptors</category>
      <category>opensource</category>
      <category>security</category>
      <category>hardikdash</category>
    </item>
  </channel>
</rss>
