Unfix — we unfix your fix, to prove it

Unfix

8 min read Original article ↗

The second key for AI-written C/C++ and firmware

Your AI agent says it's fixed. Unfix doesn't write code — it reproduces the bug, applies the fix, re-runs the evidence, then pulls the fix back out and checks the bug returns. Then it gives one deterministic verdict: VERIFIED, REJECTED or NOT VERIFIABLE (when the evidence can't decide).

unfix · nucleo-demo

Unfix terminal showing REJECTED: the fix weakens the test that catches the bug

Real run: the "fix" turned a failing test into a pass. Unfix caught it.

Watch it on real hardware

AI wrote a fix. Is it real?

1 min 46 s · sound on · recorded under the working name cplus

  1. 01 · A REAL BUG

    Unfix builds the firmware, flashes the NUCLEO board and runs the test. It fails 3 of 3: the counter should be 42, it's 41.

  2. 02 · A FAKE FIX

    The "fix" turns unity_fail into unity_pass. CI would go green. Unfix says REJECTED and points to the line.

  3. 03 · AN HONEST FIX

    Eight independent checks on the board — bug before, gone after 3 of 3, nothing else broken, back on revert. VERIFIED.

The problem

Green tests are not proof. In C and C++, a "fix" can hide the bug and still pass.

Memory errors, races and flaky failures are exactly where AI coding agents — and tired humans — take shortcuts. The agent reports success; the bug ships.

Sanitizers switched off

The crash disappears because ASan or TSan no longer runs — not because the memory error is gone.

Tests weakened

An assertion is loosened or a failing case is skipped, so the suite turns green around the bug.

Delays instead of fixes

A sleep makes a race rarer on one machine. It still fails in the field, on the real board.

How it works

A verifier that is independent of whoever wrote the fix.

  1. 01

    Reproduce

    Build in a clean sandbox and confirm the bug fails on the base version — every run, not once.

  2. 02

    Apply the fix

    Take the patch from the PR or the agent and re-run the reference tests with sanitizers on.

  3. 03

    Revert check

    Remove the fix and make sure the failure comes back. If it doesn't, the test never proved anything.

  4. 04

    Anti-masking scan

    Flag disabled sanitizers, weakened assertions and added delays in the diff.

VERIFIED — the bug is fixed, with evidence REJECTED — not fixed, or masked NOT VERIFIABLE — evidence can't decide; said so plainly

See it run

One real bug, on a real board, from first run to verdict.

A firmware project on an STM32 NUCLEO-F401RE. Unedited screenshots of the terminal app.

01 · OPEN THE PROJECT

It finds your project, your board and your tests.

Project type, connected board, ST-Link probe and the sandbox are checked before anything runs. One key to start.

Unfix start screen: project nucleo-f401re-demo, board NUCLEO-F401RE detected, Docker ready

02 · REPRODUCE THE BUG

Build, flash, fail. Three times out of three.

Firmware is built for ARM in a container and flashed to the board. The bug must fail every run — otherwise there is nothing to prove.

Unfix /bug: firmware built, board flashed, counter test failed in 3 of 3 runs

03 · CHECK THE FIX

Eight independent checks, live on the board.

Tests not weakened. Bug there before, gone after. Everything else still passes. And the bug comes back when the fix is pulled out.

Unfix checking a fix: 8 checks, running tests on the board

04 · THE VERDICT

In the demo: VERIFIED in 31 seconds — with the proof attached.

Apply it to your folder, make a branch, or export an HTML report. If the fix had cheated, you'd see REJECTED instead — like at the top of this page.

Unfix VERIFIED in the demo: the fix removes the bug, proven by 8 independent checks in 31 seconds

Where it runs

Inside the tools your team already uses.

GitHub Action (demo)

On pull requests in our demo repository

In our demo repository, a GitHub check posts the verdict and the evidence right in the PR, so a reviewer can see whether the fix is real before merging.

The PR check runs in our demo repository today; partner integration is in preparation.

Real comments from our demo repository (posted under the working name cplus).

See the real pull requests: #1 (VERIFIED), #2 (REJECTED).

Unfix GitHub PR comment: REJECTED, the patch disables memory and thread checking, which masks the bug

In your AI agent

An MCP tool for Claude Code, Codex and other agents. The agent fixes; Unfix decides whether it's done.

In the terminal

A simple command-stream app with /bug, /fix and /check — for setup, investigation and demos.

On the real board

Flash, run and check on your hardware rig — for teams that test on the board, not on a host.

Public benchmark

We tested 10 AI-generated C/C++ patches against real bugs. Unfix verified 4 and rejected 6.

We took real bugs from well-known open-source C/C++ projects, let Codex CLI fix them, and had Unfix judge each fix against the maintainers' own reference tests — hidden from the agent. The rule for picking those tests is fixed before the agent runs (one documented exception, fmt-4960), and anti-cheat tests guard against gaming.

fmt spdlog zlib-ng cpp-peglib

Cases, patches and verdicts on GitHub

Bug types covered: memory errors under ASan, a concurrent-flush race under TSan, edge cases and logic errors — including a pure-C case close to firmware code.

STM32 NUCLEO-F401RE board connected over USB, status LEDs lit
The NUCLEO-F401RE our demos run on.

Firmware

Verified on your board, not just on a laptop.

Most embedded teams test on hardware. Unfix drives your existing flashing and test tooling on the real rig and separates outcomes that usually blur together.

Running today on STM32 NUCLEO boards via ST-Link.

Per-test verdicts on your rig (/check)

FIXED The test failed before the change and passes now.

BROKEN The test passed before and fails with the change.

FLAKY ON THE BENCH The test is unstable without the change too; fix the rig before trusting any result.

FLAKY, WORSE It was flaky before, and the change makes it significantly worse.

For a single bug fix, /fix gives one verdict: VERIFIED, REJECTED or NOT VERIFIABLE.

Built for regulated teams

For medtech and other teams where "the agent said so" is not an answer.

Deterministic

The verdict comes from builds, tests and sanitizers — no language model decides it. Deterministic rules, no LLM in the verdict. Flaky and race bugs are judged by repeated runs, not a single pass.

Evidence you can file

Each run leaves a report: what was reproduced, what was run, what changed. Useful for an IEC 62304-style change record.

Runs in your environment

Built for closed networks. No cloud, no LLM — Unfix runs entirely on your machines. After a one-time setup, builds and tests run with the network off.

Questions

Frequently asked

What is Unfix?

Unfix is an independent verifier for bug fixes in C, C++ and firmware. It does not write code. It checks whether a fix — written by a developer or an AI coding agent — really removes the bug, and returns VERIFIED, REJECTED or NOT VERIFIABLE (when the evidence can't decide).

How does Unfix verify a fix?

It reproduces the bug on the base version (it must fail every run), applies the fix and re-runs the tests with sanitizers, checks that other tests still pass, then removes the fix and confirms the bug comes back. It also scans the diff for masking: disabled sanitizers, weakened or deleted tests, added delays.

Why "unfix"?

Because the strongest proof that a fix works is to take it out again: if the bug does not come back when the fix is removed, the test never proved anything.

Does Unfix use an LLM to decide the verdict?

No. The verdict comes from builds, tests, sanitizers and hardware runs. Deterministic rules, no LLM in the verdict. Flaky and race bugs are judged by repeated runs, not a single pass.

Does it work with firmware and real boards?

Yes. Unfix can build firmware, flash a real board (today STM32 NUCLEO via ST-Link) and run the tests on the hardware. /check gives per-test verdicts on your rig: FIXED (failed before the change, passes now), BROKEN (passed before, fails with the change), FLAKY ON THE BENCH (unstable without the change too; fix the rig before trusting any result) and FLAKY, WORSE (flaky before, significantly worse with the change). For a single bug fix, /fix gives one verdict: VERIFIED, REJECTED or NOT VERIFIABLE.

Where does Unfix run?

As an MCP tool inside AI coding agents such as Claude Code and Codex, as a GitHub pull request check that posts the verdict as a comment (shown on our demo repository; not yet available for partner repositories), in the terminal, and on your hardware rig. Built for closed networks. No cloud, no LLM — Unfix runs entirely on your machines. After a one-time setup, builds and tests run with the network off.

What did the public benchmark show?

We tested 10 AI-generated C/C++ patches against real bugs from open-source projects (fmt, spdlog, zlib-ng, cpp-peglib). Judged against the maintainers' own hidden reference tests, Unfix verified 4 and rejected 6.

Who is Unfix for?

C/C++ and embedded teams of roughly 20–200 engineers, starting with medtech and other regulated products where "the agent said so" is not an acceptable answer.

Design partner program

Bring one real bug. We'll verify the fix with you.

We're working with a small number of C/C++ and embedded teams — 20 to 200 engineers — to run Unfix on their own code and hardware.