Canonical form

There is exactly one way to format an Onus program, and the compiler enforces it. Diffs become semantic, style debates do not exist, and a model never spends effort on layout.

onus check reports non-canonical source as a diagnostic — E0001, with the canonical text as its fix — and onus fmt applies it. There is no configuration. Indentation is two spaces; one declaration per top-level item; one blank line between items; named arguments on the call line unless the call exceeds 100 columns, in which case one argument per line:

let who: auth.AuthedCustomer = try auth.require(
  service: auth,
  caller: req.caller,
  customer: req.customer,
  clock: clock
) else e: Unauthorised(detail: e)

The printer is the formatter, and there is only one printer. The compiler in Onus reproduces the TypeScript compiler’s output byte for byte on every source in the repository; that equality is the acceptance test for its front end.

Canonical form has a second job. Every definition has a canonical byte sequence and therefore a content hash, and that hash is what proof caching is keyed on: re-checking after an edit re-verifies only the obligations whose dependencies’ hashes changed. Comments are preserved by the printer but excluded from the hash, so a comment never invalidates a proof.

In the loop, canonical form is applied before the model ever sees a diagnostic; layout is never something it is asked to fix.

In the specification: spec §2.2.