Warm-up · in progress

freediag Port — Overview

freediag is an open-source OBD-II / K-line diagnostics stack that most teams stopped touching years ago. The code still compiled against old toolchains, but the documentation, tests, and build tooling around it had gone dormant right along with the commit history. We picked it as a warm-up run for the agent-squad pipeline behind Boro's legacy-modernization engagements: a smaller, lower-stakes codebase to shake out the process before pointing it at paying work.

The run ported roughly 32,000 lines of C to a Rust workspace under a lead / implementer / reviewer model. Along the way it did something a build recovery alone never would. Translating the code line by line turned into a thorough audit of it, and that audit is the part worth publishing.

What the port found

Seventy distinct findings were recorded and, with two exceptions, each was independently re-derived from the C source by a second reviewer before being logged. They sort into four groups:

  • 14 memory-safety / undefined-behavior bugs — unclamped memcpy of a wire-derived length, uninitialized reads trusted as data, a use-after-free.
  • 26 logic bugs — wrong arithmetic, mis-framed lengths, dropped error returns.
  • 4 data-file defects in the shipped simulator databases.
  • 26 design quirks — dead code, latent hazards, and comments that contradict the code beneath them.

The headline is a wire-derived length copied into a 7-byte buffer with no bound check. ISO 9141 is the only protocol that happens to be safe, because its frames are capped at exactly 7 bytes; the five other protocols share the same storage without inheriting that cap, and one of them is already exercised with real traffic in the project's own test corpus.

What Rust did, and did not, buy

This is the honest centre of the report, and it resists the triumphal version. Three whole classes of bug cannot survive a straightforward Rust port: unclamped memcpy, uninitialized reads, and resource-lifecycle leaks. For those, the language does the work and a naive translation is simply immune.

But the narrowing-cast class survives verbatim. Rust's as truncates exactly as C's implicit conversion does, so a line-by-line translation reproduces every one of those bugs unless a human or agent stops at each cast site. And pure logic and documentation defects, a multiplier that should be 256, a comment that names its two modes backwards, are exactly as hard to get right in Rust as in C. Those were caught by review, not by the compiler. Rust converts an entire tier of findings from silent corruption into a loud failure. The tier below it, intent, was carried entirely by process.

Read the full report

  • Whitepaper — the complete findings report, print-ready, with every citation linked to the source.
  • Findings browser — all 70 findings, filterable by taxonomy and severity, each linked to the exact line in the frozen C tree.
  • Timeline & cost — how the way of working changed over six days, and the token economics of the run.
  • Source browser — the frozen C reference, 86 files rendered line-addressable with findings flagged in the gutter.

This run started in 2026 and is still in progress. The findings above are real work product from the warm-up, not a client engagement or a third-party result. The blog covers the week-by-week story as it continues.

Wabi-sabi — beauty in the mend

Let’s stitch your systems into something that holds.

Book an assessment