Loading

Safety

A formatter that rewrites your source automatically — inside your build, without being asked — has to be unable to damage it.

Curb verifies every file in memory before anything is written to disk. A file that fails verification is reported and left exactly as it was. It is never partially written, and the build tells you rather than continuing quietly.

Check What it catches On failure
Token stream unchanged Spaces and newlines moved; nothing else Reported as CURB0002, file left untouched
Output re-parses A printer bug that welds two tokens together Same
Formatting is idempotent format(format(x)) = format(x) Caught by the test suite and the CI corpus gate
All #if branches covered One file can have several token streams Each symbol set is verified independently

For syntax style rules, which change tokens deliberately, the verifier is told exactly which rewrite was requested. Each is allowed for specifically. Everything else is still a failure, so opting into a rewrite widens the check by exactly one thing rather than switching it off.

The re-parse is conditional: the printer tracks whether it did anything capable of moving a token boundary. Where it did not, the check is skipped. That is a deliberate saving — it is also why Curb does not need the unconditional re-parse that costs other formatters a second parse per file. See Design principles for the full reasoning.

Idempotency matters more than it sounds. A formatter that does not converge makes curb check fail on files curb format just wrote, which turns a build integration into an infinite loop of diffs.

Curb does not have a dedicated printer for every construct in C#. Anything it does not recognise is emitted verbatim from the original source. Coverage grows without ever putting code at risk.

curb check ./src --coverage
		

This reports which syntax kinds are still being emitted verbatim, and how often.

[Generated/*.cs]
generated_code = true

[Legacy/*.cs]
dotnet_diagnostic.IDE0055.severity = none
		

Files carrying an <auto-generated> header are skipped as well.

These are enforced on every push, against a 1,196-file, 6.5 MB corpus:

  • Zero failed files and zero unparsable files.
  • Two format passes produce identical output.
  • Byte-identical to dotnet format whitespace with reflow off, and 100% with reflow on; 99.9% with reflow on and csharp_keep_existing_linebreaks = true.
  • A native-AOT publish on all five supported platforms, each smoke-tested before packing.
  • An allocation-ratio ceiling, measured on the AOT binary rather than the JIT build.

Curb reports the file, leaves it untouched, and exits non-zero. In a build, that is CURB0002 — an error regardless of your warning settings, because a formatter that could not verify its own work has verified nothing.

If you hit one, it is a bug worth reporting: it means Curb found a construct it would have mangled, and stopped itself.