﻿---
title: Safety
description: Curb verifies every file before writing it. What is checked, and why unknown syntax is never at risk.
url: https://docs-v3-preview.elastic.dev/design-principles/safety
---

# 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.

## What is checked


| 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](https://docs-v3-preview.elastic.dev/design-principles/syntax-and-semantic) 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](https://docs-v3-preview.elastic.dev/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.

## Unknown syntax is not at risk

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.
```sh
curb check ./src --coverage
```

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

## Files that opt out

```ini
[Generated/*.cs]
generated_code = true

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

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

## What is gated in CI

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.


## When verification fails

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.