<?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: beTheNoob</title>
    <description>The latest articles on DEV Community by beTheNoob (@bethenoob).</description>
    <link>https://dev.to/bethenoob</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%2F3707529%2Fec1809ad-f9b0-409b-96b6-4b58aeaafc29.png</url>
      <title>DEV Community: beTheNoob</title>
      <link>https://dev.to/bethenoob</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bethenoob"/>
    <language>en</language>
    <item>
      <title>Building Raptor: A Hackathon Judging Platform That Checks Its Own Homework</title>
      <dc:creator>beTheNoob</dc:creator>
      <pubDate>Wed, 30 Sep 2026 22:05:16 +0000</pubDate>
      <link>https://dev.to/bethenoob/building-raptor-a-hackathon-judging-platform-that-checks-its-own-homework-28ab</link>
      <guid>https://dev.to/bethenoob/building-raptor-a-hackathon-judging-platform-that-checks-its-own-homework-28ab</guid>
      <description>&lt;p&gt;&lt;em&gt;A collaboration between Four Eyed Gens and beTheNOOB.&lt;/em&gt;&lt;/p&gt;

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




&lt;h2&gt;
  
  
  🦅 Building Raptor: A Hackathon Judging Platform That Checks Its Own Homework
&lt;/h2&gt;

&lt;p&gt;Most hackathon platforms trust the submission form and move on. We built Raptor to question that. If a platform decides who wins money and recognition, every step of that decision should be something you can actually check, not just something you have to trust.&lt;/p&gt;

&lt;p&gt;Here is what we actually built, and how it works under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  🗺️ The Full Journey, Start to Finish
&lt;/h2&gt;

&lt;p&gt;Before getting into each piece separately, here is the whole pipeline in one picture. Every stage below is a real, checked state on the server, never just something implied by which screen someone happens to be looking at. The dashed amber path shows what happens when verification flags something instead of approving it automatically, and once an organizer approves it, it simply rejoins the normal pipeline at the same step it would have reached anyway. The two boxes at the end, voting and certificates, both run after results are published, not one after the other in a strict order.&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%2Ft5rheez999oa8uistjnz.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%2Ft5rheez999oa8uistjnz.png" alt="Flow diagram showing a submission's full journey through Raptor: register, form a team, submit, verify, assign, score, normalize, and publish results, with a branch showing a flagged submission going to organizer review before rejoining the pipeline, and a second branch showing voting and certificates both running in parallel after results are published." width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each of these stages gets its own section below, so this is just the map. Keep it in mind while reading the rest, since the order here is the actual order the platform enforces, not just the order this post happens to explain things in.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Catching Problems Before a Judge Ever Sees Them
&lt;/h2&gt;

&lt;p&gt;Every submitted project gets checked against its own GitHub commit history before a judge ever opens it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check result&lt;/th&gt;
&lt;th&gt;What happens next&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;✅ Commits fall inside the event window&lt;/td&gt;
&lt;td&gt;Auto approved, moves straight to judging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚠️ Some commits outside the window&lt;/td&gt;
&lt;td&gt;Flagged for organizer review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🚫 Repo is private or not on GitHub&lt;/td&gt;
&lt;td&gt;Flagged for organizer review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❌ Organizer disqualifies it&lt;/td&gt;
&lt;td&gt;Must attach a written reason, permanently&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nothing gets removed from a competition without a real explanation sitting right next to it, forever.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧮 How a Score Actually Gets Built
&lt;/h2&gt;

&lt;p&gt;A judge does not just type one number. Here is the actual chain:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1️⃣ Criteria scores&lt;/td&gt;
&lt;td&gt;Each rubric criteria, weighted&lt;/td&gt;
&lt;td&gt;Functionality (60%) × 90 + Quality (40%) × 80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2️⃣ Judge raw total&lt;/td&gt;
&lt;td&gt;Weighted sum, plus bonus added on top&lt;/td&gt;
&lt;td&gt;86 + 5 bonus = 91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3️⃣ Average raw total&lt;/td&gt;
&lt;td&gt;Average across every judge who actually finished&lt;/td&gt;
&lt;td&gt;Judges who never submitted are excluded, not counted as zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4️⃣ Final score&lt;/td&gt;
&lt;td&gt;Scaled to the event's display scale&lt;/td&gt;
&lt;td&gt;e.g. out of 5 ⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🎯 &lt;strong&gt;The key design choice:&lt;/strong&gt; bonus points get added &lt;em&gt;after&lt;/em&gt; the weighted average, in full units, not blended proportionally in. That keeps the math honest. A small bonus can nudge a project up. It cannot let a weak project beat a strong one just because the bonus was generous.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚖️ Normalization: Why It Exists, and What the Data Actually Showed
&lt;/h2&gt;

&lt;p&gt;Different judges score differently. Some are naturally generous, some are naturally strict, and that has nothing to do with the quality of the work in front of them.&lt;/p&gt;

&lt;p&gt;So every judge has a personal scoring profile, built from their history across every event they have judged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Judge's raw score  →  compare to their own average and spread  →  normalized score
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tough judge's 4/5 stops meaning something different from a generous judge's 4/5.&lt;/p&gt;

&lt;p&gt;📊 &lt;strong&gt;What we actually tested:&lt;/strong&gt; we ran a real simulation on real fixture data (30 judges, 40 projects) to see how well this correction recovers a true ranking.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Judges seeing many projects each&lt;/th&gt;
&lt;th&gt;Judges seeing only a few each&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Normalization clearly helps&lt;/td&gt;
&lt;td&gt;Effect shrinks, sample size matters more&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is the kind of finding you only get by testing your own formula against real numbers instead of trusting it because it looks correct on paper.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 One Leaderboard, Every Event
&lt;/h2&gt;

&lt;p&gt;Wins do not live inside a single event. Raptor keeps a platform wide leaderboard tracking one person across everything they have ever competed in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🥇 1st place finishes&lt;/li&gt;
&lt;li&gt;🥈 2nd place finishes&lt;/li&gt;
&lt;li&gt;🥉 3rd place finishes&lt;/li&gt;
&lt;li&gt;🌟 Special award wins&lt;/li&gt;
&lt;li&gt;🗳️ Audience choice wins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of it feeds one running total, so someone who quietly placed well across five small events gets the same visibility as someone who won one big one.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ The Infrastructure Underneath
&lt;/h2&gt;

&lt;p&gt;We wanted this to run anywhere with zero cloud dependency. Five containers, two networks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 host-exposed ports
                        │
        ┌───────────────┴───────────────┐
        │                                 │
     web (Next.js)                    api (NestJS)
        │                                 │
        └────────── app network ──────────┤
                                           │
                                       worker (BullMQ) ── on both networks
                                           │
                                     data network
                                           │
                              ┌────────────┴────────────┐
                          postgres                    redis
&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%2Fn3gamn7qaj3q30iwwg0v.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%2Fn3gamn7qaj3q30iwwg0v.png" alt="Diagram of Raptor's five Docker containers split across two isolated networks, showing the api and web containers with host-exposed ports on the app network, and postgres and redis on a data network with zero exposed ports. A dashed red line shows the web container being blocked from reaching postgres directly, while solid blue lines show the allowed path through the api container instead." width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Container&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Why it exists&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🌐 &lt;code&gt;web&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Next.js frontend&lt;/td&gt;
&lt;td&gt;The only thing a browser talks to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚙️ &lt;code&gt;api&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;NestJS backend&lt;/td&gt;
&lt;td&gt;Every rule, every permission check, lives here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔄 &lt;code&gt;worker&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Background jobs (BullMQ)&lt;/td&gt;
&lt;td&gt;Handles slow work: GitHub checks, leaderboard recomputes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🗄️ &lt;code&gt;postgres&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;The single source of truth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚡ &lt;code&gt;redis&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Cache and rate limiting&lt;/td&gt;
&lt;td&gt;Login limits, gallery limits, queue storage&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🔒 &lt;strong&gt;The network isolation is the important part.&lt;/strong&gt; &lt;code&gt;postgres&lt;/code&gt; and &lt;code&gt;redis&lt;/code&gt; sit on a data-only network with &lt;strong&gt;zero exposed ports to the outside world&lt;/strong&gt;, not even to your own machine. &lt;code&gt;web&lt;/code&gt; cannot reach the database directly at all, even if it wanted to. Every single thing a browser does has to go through &lt;code&gt;api&lt;/code&gt;, which is the only place permission checks happen. If someone compromised the frontend, they would hit a dead end trying to reach the database.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker compose up&lt;/code&gt; and that is the whole stack. No cloud account, no external API calls, no signup anywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧑‍💻 Five Accounts, Five Jobs
&lt;/h2&gt;

&lt;p&gt;Before going role by role in detail, here is the full picture in one image. Every row below is a completely separate account type, and none of them can act outside what their own row shows, a judge cannot publish results and an organizer cannot score a project.&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%2Fferzay87ni8865k0rz5r.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%2Fferzay87ni8865k0rz5r.png" alt="Vertical diagram showing five stacked rows, one per account type on Raptor: visitor, user, judge, organizer, and admin, each row showing that role's real sequence of tasks from start to finish." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A visitor never needs an account just to look around. A user is the one actually building something. A judge only ever sees what they are assigned. An organizer runs their own event end to end. An admin can step into any event platform wide, but every single time they do, it gets written to a permanent log.&lt;/p&gt;

&lt;h3&gt;
  
  
  For a judge
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Invited → Accept / Decline → Assigned queue of projects → Scoring screen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once accepted, a judge gets a queue of assigned projects. The scoring screen brings the rubric, bonus tracks, and written feedback together in one place, and a review can be revised as many times as needed right up until judging closes.&lt;/p&gt;

&lt;h3&gt;
  
  
  For an organizer
&lt;/h3&gt;

&lt;p&gt;One dashboard, one event at a time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📨 Invite judges&lt;/li&gt;
&lt;li&gt;🔍 Review flagged submissions&lt;/li&gt;
&lt;li&gt;🧑‍⚖️ Assign projects to judges&lt;/li&gt;
&lt;li&gt;📈 Watch judging progress live&lt;/li&gt;
&lt;li&gt;⚖️ Run normalization&lt;/li&gt;
&lt;li&gt;📋 Draft and publish results&lt;/li&gt;
&lt;li&gt;🎓 Issue certificates&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For an admin
&lt;/h3&gt;

&lt;p&gt;Same toolkit, platform wide instead of event wide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step into any event to help&lt;/li&gt;
&lt;li&gt;Export data across every event at once&lt;/li&gt;
&lt;li&gt;See the full audit trail for everything that happened&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🕵️ Every time an admin uses that wider access, it gets logged automatically. The power exists for real operational need, but it is never invisible.&lt;/p&gt;




&lt;p&gt;Built with a self-hosted first mindset, because the tools deciding who wins should be something you can actually run and check yourself, not something you have to trust blindly. 🦅&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Check out the full code:&lt;/strong&gt; &lt;a href="https://github.com/DhruvP2205/raptor" rel="noopener noreferrer"&gt;github.com/DhruvP2205/raptor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A collaboration between Four Eyed Gens and beTheNOOB.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>opensource</category>
      <category>docker</category>
      <category>typescript</category>
    </item>
    <item>
      <title>I Ported cJSON to Rust, and My Own Test Suite Lied to My Face</title>
      <dc:creator>beTheNoob</dc:creator>
      <pubDate>Fri, 07 Aug 2026 06:22:02 +0000</pubDate>
      <link>https://dev.to/bethenoob/i-ported-cjson-to-rust-and-my-own-test-suite-lied-to-my-face-534o</link>
      <guid>https://dev.to/bethenoob/i-ported-cjson-to-rust-and-my-own-test-suite-lied-to-my-face-534o</guid>
      <description>&lt;p&gt;I did a dumb thing on purpose: took a real, 8-year-old, still-in-production C library — &lt;a href="https://github.com/DaveGamble/cJSON" rel="noopener noreferrer"&gt;cJSON&lt;/a&gt; — and rewrote it in Rust. Not "inspired by." A &lt;em&gt;port&lt;/em&gt;. Same test suite, same weird edge cases, same bugs if I wasn't careful.&lt;/p&gt;

&lt;p&gt;This was for &lt;strong&gt;Port Mortem&lt;/strong&gt;, a hackathon whose entire personality is "prove it, don't just say it." You take the &lt;em&gt;original&lt;/em&gt; test suite — hashed at kickoff so you can't sneak-edit it later — and make it pass against your rewrite, untouched. One edited test file = automatic zero. No vibes-based grading.&lt;/p&gt;

&lt;p&gt;So here's the honest version: four real bugs, one unsafe block I genuinely couldn't remove, and a benchmark where C beat me and I'm not hiding it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's cJSON and why bother
&lt;/h2&gt;

&lt;p&gt;A small, zero-dependency C library that parses/prints JSON, ~2,500 lines, used everywhere from embedded firmware to random C tools. It manages its own tree with raw pointers and hand-rolls its own growable print buffer — exactly the kind of code where "just rewrite it safely" sounds easy until you try. Bonus: it has a real, disclosed CVE, &lt;strong&gt;CVE-2025-57052 (CVSS 9.8)&lt;/strong&gt; — so I wasn't just porting code, I was porting a bug on purpose, then un-porting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Original C headers get SHA-256 hashed at kickoff, never touched again. My Rust compiles to the exact same C ABI, so the original C test suite (Unity framework) links straight against my Rust binary with no idea it's not talking to C. One wrinkle: 13 of 20 original test files call cJSON's &lt;em&gt;internal&lt;/em&gt; (non-public) functions directly — I handled that with a thin C shim (not hashed/pinned) that just forwards to the real ported logic. Not a mock, same logic, just re-exposed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug #1: CI said "100% passed." It ran 1 out of 22 tests.
&lt;/h2&gt;

&lt;p&gt;The most embarrassing one, and the one I'm proudest of catching. CI printed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100% tests passed, 0 tests failed out of 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Out of &lt;strong&gt;1&lt;/strong&gt;. Not 22. cJSON gates its whole real test suite behind a CMake flag:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="c1"&gt;# adapter/CMakeLists.txt — this line was missing&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ENABLE_CJSON_TEST ON&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Upstream's own build sets this automatically; my from-scratch CMake file didn't. So the &lt;code&gt;if(ENABLE_CJSON_TEST)&lt;/code&gt; block silently defined zero real tests, and &lt;code&gt;ctest&lt;/code&gt; was truthfully reporting 100% of &lt;em&gt;one leftover test&lt;/em&gt;. I only caught it by not trusting the green checkmark and running the build locally myself. One line fixed it — and immediately surfaced 2 more bugs (a missing preamble in my test shim, and &lt;code&gt;cJSON_ParseWithOpts&lt;/code&gt; silently dropping its error-position output on failure) that had been hiding behind the disabled suite the whole time.&lt;/p&gt;


&lt;h2&gt;
  
  
  Bug #2: my fuzzer found a bug in under a minute
&lt;/h2&gt;

&lt;p&gt;Port Mortem wants a &lt;em&gt;differential fuzzer&lt;/em&gt; — same input, both builds, diff the output. Mine found &lt;strong&gt;192,619 divergences&lt;/strong&gt; on its first real run, all from string-printing unicode escapes:&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="c1"&gt;// port/src/print.rs — print_string_ptr()&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="c1"&gt;// C's `for` loop increments the pointer once per iteration on top of&lt;/span&gt;
    &lt;span class="c1"&gt;// this branch's own advance. My manual Rust loop has no implicit&lt;/span&gt;
    &lt;span class="c1"&gt;// increment, so it must add that missing +1 explicitly: add(5), not 4.&lt;/span&gt;
    &lt;span class="nn"&gt;libc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nb"&gt;c_char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="s"&gt;"u%04x"&lt;/span&gt;&lt;span class="nf"&gt;.as_ptr&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;c_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The C &lt;code&gt;for&lt;/code&gt; loop's increment clause was quietly adding one extra byte of advance every iteration — a language feature I forgot to account for by hand. One-line fix, zero divergences after. Best proof I have that differential fuzzing actually works: it caught a subtle off-by-one that unit tests never would've hit.&lt;/p&gt;


&lt;h2&gt;
  
  
  The unsafe block I couldn't get rid of
&lt;/h2&gt;

&lt;p&gt;Grepping the port shows 155 hits of "unsafe." Scary out of context, so here's the real breakdown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What it actually is&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;unsafe extern "C" fn&lt;/code&gt; — public FFI entry points&lt;/td&gt;
&lt;td&gt;89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;unsafe fn&lt;/code&gt; — internal helper signatures&lt;/td&gt;
&lt;td&gt;61&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual &lt;code&gt;unsafe { }&lt;/code&gt; blocks inside safe code&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;SAFETY:&lt;/code&gt; comments explaining why&lt;/td&gt;
&lt;td&gt;121&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;89 of 91 public functions are &lt;code&gt;unsafe extern "C" fn&lt;/code&gt; — not laziness, structurally required, since every one takes a raw pointer from C that Rust's compiler can't verify. Marking them &lt;code&gt;safe fn&lt;/code&gt; wouldn't remove the risk, just mislabel it. The number that actually reflects my code quality is the &lt;strong&gt;1&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="c1"&gt;// port/src/hooks.rs&lt;/span&gt;
&lt;span class="c1"&gt;// SAFETY: reads the `static mut global_hooks` — matches the original's&lt;/span&gt;
&lt;span class="c1"&gt;// own thread-safety characteristics (none), required for compatibility.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HookSnapshot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;global_hooks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;HookSnapshot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;allocate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="py"&gt;.allocate&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;libc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;deallocate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="py"&gt;.deallocate&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;libc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;reallocate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="py"&gt;.reallocate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;cJSON lets any C caller globally swap the allocator via &lt;code&gt;cJSON_InitHooks&lt;/code&gt;, with zero synchronization — that's just how the original works, and tests depend on it. The borrow checker can't reason about a C caller mutating a global from a function it can't see, so this one spot is explicitly marked and explained. Everything else — parsing, tree walks, JSON Pointer logic, string escaping — is plain safe Rust behind that one FFI wall.&lt;/p&gt;
&lt;h2&gt;
  
  
  The CVE, ported on purpose
&lt;/h2&gt;

&lt;p&gt;CVE-2025-57052 (CVSS 9.8): resolving a JSON Pointer like &lt;code&gt;/1A&lt;/code&gt; as an array index, the original C loop kept re-checking the &lt;em&gt;first&lt;/em&gt; character instead of advancing — so &lt;code&gt;"1A"&lt;/code&gt; got folded into a valid index and returned a real element for what should've been rejected.&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="c1"&gt;// port/src/utils.rs — fixed&lt;/span&gt;
&lt;span class="c1"&gt;// Original checked pointer[0] (always the first byte) here forever.&lt;/span&gt;
&lt;span class="c1"&gt;// We check pointer[position] — the byte actually being consumed.&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="sc"&gt;b'0'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="sc"&gt;b'9'&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;parsed_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parsed_index&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;b'0'&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;usize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I kept the original buggy C build as a permanent fuzzing oracle to prove the fix, not just claim it — real output from &lt;code&gt;fuzz/log.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pointer: "/1A" (malformed)
  C-original(v1.7.18) -&amp;gt; accepted (bug: folded '1A' into index 27), returned element 127
  Rust-port -&amp;gt; rejected (NULL, CVE-2025-57052 fix)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  The benchmark that mildly hurt my feelings
&lt;/h2&gt;

&lt;p&gt;Same 500-record, ~50KB JSON workload, 2,000 iterations, real percentiles (not just an average):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;th&gt;Winner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;p50 latency&lt;/td&gt;
&lt;td&gt;0.895 ms&lt;/td&gt;
&lt;td&gt;0.767 ms&lt;/td&gt;
&lt;td&gt;Rust, ~14% faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p99 latency&lt;/td&gt;
&lt;td&gt;2.575 ms&lt;/td&gt;
&lt;td&gt;2.044 ms&lt;/td&gt;
&lt;td&gt;Rust, ~21% faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throughput&lt;/td&gt;
&lt;td&gt;892 ops/s&lt;/td&gt;
&lt;td&gt;1,037 ops/s&lt;/td&gt;
&lt;td&gt;Rust, ~16% more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6.90 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.44 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;C&lt;/strong&gt;, by a hair&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peak RSS&lt;/td&gt;
&lt;td&gt;2,656 KB&lt;/td&gt;
&lt;td&gt;2,656 KB&lt;/td&gt;
&lt;td&gt;tie&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rust wins where it matters most — median, p99, throughput, identical memory. But C beat me on max latency, and I'm leaving that row in the table instead of quietly cropping it out. One-off outlier on a shared machine, not a trend — but "honest numbers over confident claims" is the whole point of this track.&lt;/p&gt;


&lt;h2&gt;
  
  
  Watch it live
&lt;/h2&gt;

&lt;p&gt;Full Docker build, all 22 tests, live differential fuzz including the CVE case, no cuts on the parts that matter.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/-ROQhIIsLWY"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;
&lt;h2&gt;
  
  
  All the numbers, in one place
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;22/22&lt;/strong&gt; original Unity tests pass, byte-for-byte unmodified, hash-verified&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;70M+&lt;/strong&gt; differential fuzz comparisons in a 60s run, &lt;strong&gt;0 unexpected divergences&lt;/strong&gt; (exact count varies by machine — it's a time budget, not an iteration count; two real runs hit 77.9M and 115.9M, both clean)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1&lt;/strong&gt; real internal &lt;code&gt;unsafe {}&lt;/code&gt; block in ~4,000 lines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1&lt;/strong&gt; real CVE (CVSS 9.8), fixed and faithfully reproduced for proof, not just asserted&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4&lt;/strong&gt; real bugs found and fixed — including one about how confidently I thought I'd already verified this thing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Go poke at it yourself
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/DhruvP2205" rel="noopener noreferrer"&gt;
        DhruvP2205
      &lt;/a&gt; / &lt;a href="https://github.com/DhruvP2205/cjson-rust-port" rel="noopener noreferrer"&gt;
        cjson-rust-port
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🦀 C→Rust port of DaveGamble/cJSON — 🧪 22/22 original tests unmodified, 🐛 70M+ fuzz comparisons/0 divergences, 🎯 CVE-2025-57052 fixed. 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🔀 cJSON ⇄ 🦀 Rust&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Port Mortem 2026 · Track A (C → Rust)&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;&lt;em&gt;A byte-for-byte faithful, memory-safe Rust port of a real, popular C library —&lt;/em&gt;
&lt;em&gt;proven against the original's own unmodified test suite, not a rewritten one.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-track-criteria-checklist" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6137caac1e2c9d8922bc597fa415be2209f92ab541fe964903a6ccbdcbc8ac46/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d3232253246323225323070617373696e672d627269676874677265656e3f7374796c653d666f722d7468652d6261646765266c6f676f3d636865636b6d617278266c6f676f436f6c6f723d7768697465" alt="Tests"&gt;&lt;/a&gt; &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-fuzz--benchmark-evidence" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f4d435071247581912b01c3c6f86436f8c8f183afb9f96ef29d63572f917ff81/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f66757a7a2d30253230646976657267656e63657325323025324625323037304d2532422d627269676874677265656e3f7374796c653d666f722d7468652d6261646765266c6f676f3d6669726573686970266c6f676f436f6c6f723d7768697465" alt="Fuzz"&gt;&lt;/a&gt; &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-why-cjson" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1c6a9bd46a2f5ff63f97ea70b8ae2222d62b33271c2afb57db301efa72d6efbc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4356452d2d323032352d2d35373035322d66697865642d6f72616e67653f7374796c653d666f722d7468652d6261646765266c6f676f3d736869656c6473646f74696f266c6f676f436f6c6f723d7768697465" alt="CVE"&gt;&lt;/a&gt; &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-license" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7b032738aeb4a8dd7ec78c4402e078ca8c196b0e528c117bbd78088c9a036988/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75653f7374796c653d666f722d7468652d6261646765" alt="License"&gt;&lt;/a&gt; &lt;a href="https://www.youtube.com/watch?v=-ROQhIIsLWY" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c6312ea796af160435853e286b8bf78e7e5c2d32f1e67afdb362826853ac34d2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f64656d6f2d766964656f2d4646303030303f7374796c653d666f722d7468652d6261646765266c6f676f3d796f7574756265266c6f676f436f6c6f723d7768697465" alt="Demo Video"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/61bf5c828a3b545fad6251b32c564dd9f65ea13554f93a295a756b1cc671a3d7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f527573742d3030303030303f7374796c653d666c61742d737175617265266c6f676f3d72757374266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/61bf5c828a3b545fad6251b32c564dd9f65ea13554f93a295a756b1cc671a3d7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f527573742d3030303030303f7374796c653d666c61742d737175617265266c6f676f3d72757374266c6f676f436f6c6f723d7768697465" alt="Rust"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/da826194dacce950cb70ff6e5d897531cc761517795c1e687479fb6121a30e46/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f432d3030353939433f7374796c653d666c61742d737175617265266c6f676f3d63266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/da826194dacce950cb70ff6e5d897531cc761517795c1e687479fb6121a30e46/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f432d3030353939433f7374796c653d666c61742d737175617265266c6f676f3d63266c6f676f436f6c6f723d7768697465" alt="C"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/49436deb02ed796af8d0358d930cd37cc93ed0104a00b5d196d39d39ba04c443/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f434d616b652d3036344638433f7374796c653d666c61742d737175617265266c6f676f3d636d616b65266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/49436deb02ed796af8d0358d930cd37cc93ed0104a00b5d196d39d39ba04c443/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f434d616b652d3036344638433f7374796c653d666c61742d737175617265266c6f676f3d636d616b65266c6f676f436f6c6f723d7768697465" alt="CMake"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/60eb2b57aa706fb9f82149695e18d28a1a47450cc80e3a74b15060f4d47c18d0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446f636b65722d3234393645443f7374796c653d666c61742d737175617265266c6f676f3d646f636b6572266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/60eb2b57aa706fb9f82149695e18d28a1a47450cc80e3a74b15060f4d47c18d0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446f636b65722d3234393645443f7374796c653d666c61742d737175617265266c6f676f3d646f636b6572266c6f676f436f6c6f723d7768697465" alt="Docker"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/adee56051ecd820e37c1849de2b1b6a5140ee01e1eca716183c31ab70c1635c3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f476974487562253230416374696f6e732d3230383846463f7374796c653d666c61742d737175617265266c6f676f3d676974687562616374696f6e73266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/adee56051ecd820e37c1849de2b1b6a5140ee01e1eca716183c31ab70c1635c3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f476974487562253230416374696f6e732d3230383846463f7374796c653d666c61742d737175617265266c6f676f3d676974687562616374696f6e73266c6f676f436f6c6f723d7768697465" alt="GitHub Actions"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/3df355069631fba98c9f38c9381b4f0453dd1d026dbdb599376e5970213c7343/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646570656e64656e636965732d7a65726f2d6465613538343f7374796c653d666c61742d737175617265266c6f676f3d72757374266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/3df355069631fba98c9f38c9381b4f0453dd1d026dbdb599376e5970213c7343/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646570656e64656e636965732d7a65726f2d6465613538343f7374796c653d666c61742d737175617265266c6f676f3d72757374266c6f676f436f6c6f723d7768697465" alt="No external crates"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-alert markdown-alert-tip"&gt;
&lt;p class="markdown-alert-title"&gt;Tip&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rewrite real code. Prove the port works.&lt;/strong&gt; No new tests written against the new implementation — the &lt;em&gt;original's own&lt;/em&gt; unmodified Unity suite runs straight against the Rust build.&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🧭 Contents&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;🎥 &lt;a href="https://www.youtube.com/watch?v=-ROQhIIsLWY" rel="nofollow noopener noreferrer"&gt;Demo video&lt;/a&gt;
📊 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-at-a-glance" rel="noopener noreferrer"&gt;At a glance&lt;/a&gt;
🤔 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-why-cjson" rel="noopener noreferrer"&gt;Why cJSON&lt;/a&gt;
🔬 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-how-this-port-actually-proves-equivalence" rel="noopener noreferrer"&gt;How this port proves equivalence&lt;/a&gt;
🚀 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-build--run" rel="noopener noreferrer"&gt;Build &amp;amp; run&lt;/a&gt;
🧑‍💻 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-try-it-yourself" rel="noopener noreferrer"&gt;Try it yourself&lt;/a&gt;
📁 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-repository-layout" rel="noopener noreferrer"&gt;Repository layout&lt;/a&gt;
✅ &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-track-criteria-checklist" rel="noopener noreferrer"&gt;Track criteria&lt;/a&gt;
🧪 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-fuzz--benchmark-evidence" rel="noopener noreferrer"&gt;Fuzz &amp;amp; benchmark evidence&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📊 At a glance&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;


&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;📦 &lt;strong&gt;Source project&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/DaveGamble/cJSON" rel="noopener noreferrer"&gt;&lt;code&gt;DaveGamble/cJSON&lt;/code&gt;&lt;/a&gt; @ &lt;code&gt;v1.7.18&lt;/code&gt; (MIT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🦀 &lt;strong&gt;Ported&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;~4,600 LOC — &lt;code&gt;cJSON.c&lt;/code&gt; + &lt;code&gt;cJSON_Utils.c&lt;/code&gt; → Rust, &lt;strong&gt;zero external crates&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧪 &lt;strong&gt;Test suite&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Original Unity suite, &lt;strong&gt;unmodified&lt;/strong&gt;, hash-pinned, linked against the Rust build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ &lt;strong&gt;Test result&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;🟢 &lt;code&gt;22 / 22&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DhruvP2205/cjson-rust-port" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Every number above is a committed file in the repo — fuzz logs, benchmark JSON, and &lt;code&gt;DECISIONS.md&lt;/code&gt; (20 sections of reasoning, zero jokes, all receipts).&lt;/p&gt;

&lt;p&gt;This was my Track A (C → Rust) submission for &lt;strong&gt;Port Mortem 2026&lt;/strong&gt;. If you're doing a language port for anything — hackathon, work, fun — my one piece of advice is the whole post in one line: don't trust the green checkmark, run it yourself, count the tests, and if something doesn't add up, go find out why before you ship it.&lt;/p&gt;

&lt;p&gt;Thanks for reading. 🦀&lt;/p&gt;

</description>
      <category>rust</category>
      <category>c</category>
      <category>opensource</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Twelve-Factor App: 5 Surprising Truths About Modern Software</title>
      <dc:creator>beTheNoob</dc:creator>
      <pubDate>Mon, 12 Jan 2026 20:09:44 +0000</pubDate>
      <link>https://dev.to/bethenoob/the-twelve-factor-app-5-surprising-truths-about-modern-software-55le</link>
      <guid>https://dev.to/bethenoob/the-twelve-factor-app-5-surprising-truths-about-modern-software-55le</guid>
      <description>&lt;p&gt;Developers today face a common set of challenges: building applications that are portable, scalable, and maintainable across a variety of environments, from on-premises servers to cloud platforms like GCP, AWS, and Azure. To address these issues, developers at Heroku created the "Twelve-Factor App" methodology—a set of guiding principles for architecting robust, modern applications.&lt;/p&gt;

&lt;p&gt;This article explores five of the most impactful and potentially counter-intuitive principles from this methodology. Understanding these factors can fundamentally change how you build and deploy software, leading to more resilient and scalable systems.&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.amazonaws.com%2Fuploads%2Farticles%2Fs4f5w3vw0u2joulq0oip.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.amazonaws.com%2Fuploads%2Farticles%2Fs4f5w3vw0u2joulq0oip.png" alt="12 Factors" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Your Processes Must Be Stateless (and Sticky Sessions Are a Trap)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A core tenet of the Twelve-Factor methodology is that application processes should be "stateless and share-nothing." This means that no single process should hold onto data that is required by another process for a subsequent request.&lt;/p&gt;

&lt;p&gt;Consider a simple login session. If your application is running across three server instances, a user might log in and have their session information stored on the first instance. If their next request is routed to a different instance by the load balancer, the second instance, having no memory of the user's session, treats them as an unauthenticated visitor, forcing them to log in again.&lt;/p&gt;

&lt;p&gt;A common but incorrect fix for this is using "sticky sessions," which configure the load balancer to always route a specific user back to the same instance. This is a direct violation of the Twelve-Factor methodology. The architecturally sound solution is to externalize any persistent data, like user session information, into a stateful backing service. By using a database or a caching service like Redis, any process on any instance can access the session data. This decoupling of state from process is the key to true horizontal scalability; it allows any number of identical processes to handle any user request, enabling the system to scale out effortlessly in response to load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Logs Aren't Files, They're Event Streams&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The traditional approach to logging involves an application writing its output to a local file, such as logFile.txt. In a modern, containerized world, this practice is deeply flawed. When a container is destroyed, whether during scaling, deployment, or a crash, its local filesystem is wiped out, and any logs stored there are lost forever.&lt;/p&gt;

&lt;p&gt;A Twelve-Factor app never concerns itself with the routing or storage of its logs. Instead, it treats logs as an event stream, writing all log output to standard output. The execution environment, not the application, is responsible for capturing this stream. This transforms logs from a passive debugging file into a rich, queryable source of real-time business intelligence. The execution environment can now route these streams to powerful, centralized platforms like the ELK Stack (Elasticsearch, Logstash, Kibana) or Splunk for aggregation, analysis, and alerting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. One Project Can Mean Multiple Codebases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first factor, "Codebase," emphasizes tracking all code in a version control system like Git to facilitate collaboration. However, it introduces a rule that might seem counter-intuitive: if a single project consists of multiple distinct application services—such as a payment service, an order processing service, and a web app—sharing a single codebase is a violation of the methodology.&lt;/p&gt;

&lt;p&gt;The correct architecture dictates that each of these distinct services should be separated into its own individual codebase. Each codebase should have its own separate deployments for each environment, such as development, staging, and production. This principle aligns perfectly with modern microservice architectures. It enforces architectural boundaries, allowing the payment service team to deploy updates multiple times a day without any risk of disrupting or being blocked by work on the order processing service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Your App Must Be Ready to Be Shut Down at Any Moment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The "Disposability" factor states that an application's processes must be designed to be started or stopped instantly. This capability is essential for achieving rapid elastic scaling, fast deployments, and overall system resilience.&lt;/p&gt;

&lt;p&gt;To facilitate this, a Twelve-Factor app must support graceful shutdowns. When a process manager (like Docker) issues a stop command, it first sends a SIGTERM signal. This signal tells the application to finish its current request and shut down cleanly within a given grace period. If the process does not terminate in time, the manager sends a SIGKILL signal to forcefully terminate it. An application must be built to handle these signals properly to ensure clean shutdowns without data loss or corruption. This disposability is not just a best practice; it is a prerequisite for modern cloud-native platforms like Kubernetes, which rely on the ability to terminate and replace processes at will to perform rolling updates, manage load, and maintain system health.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Stop Saying "It Works on My Machine" with Dev/Prod Parity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The classic developer excuse, "It works on my machine," is a symptom of a deeper architectural problem: environmental drift. The concept of "Dev/Prod Parity" is designed for continuous deployment and aims to keep the gap between development and production environments as small as possible, providing a disciplined cure for that drift. To achieve this parity, the methodology prescribes several key practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent Backing Services: Developers should resist the urge to use different backing services between development and production (e.g., using a lightweight local database in dev but a robust one in prod).&lt;/li&gt;
&lt;li&gt;Identical Tooling: The tools used to build, test, and run the application should remain the same across all environments.&lt;/li&gt;
&lt;li&gt;Developer Involvement: Developers should be involved in the deployment process to bridge the gap between writing code and seeing it run in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While some of these principles may seem strict or require rethinking traditional development habits, they provide a proven roadmap for building modern applications. By embracing concepts like statelessness, event stream logging, and dev/prod parity, you can create systems that are highly resilient, scalable, and portable across any infrastructure.&lt;/p&gt;

&lt;p&gt;As you look at your own projects, which of these factors presents the biggest opportunity for improvement?&lt;/p&gt;

</description>
      <category>twelvefactorapp</category>
      <category>systemdesign</category>
      <category>devops</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
