Canonical bytes
Last reviewed: July 2026.
Most "UI as JSON" systems specify a schema: which fields exist and what they mean. Fuaran additionally specifies the bytes: one canonical serialisation with ordinal-sorted keys, a canonical number layout, and omit-when-absent optionals. Encode the same tree in any conformant host – F#, TypeScript, Python, Go, Rust – and you get byte-identical output, certified by a shared, executable conformance corpus that every host runs in CI.
This looks like pedantry until you list what it unlocks. Byte-determinism is the foundation under every trust property the language offers:
- Hashing. A content hash of a tree means something only if the same tree always produces the same bytes. Canonical bytes make hash-chained edit histories possible – each operation links to its predecessor, so a corrupted or casually altered history breaks the chain instead of replaying quietly. The digest is unkeyed, so this is corruption detection rather than tamper evidence: anyone who can write the store can recompute every digest that follows an edit. Catching that needs signing, a separate seam that is not shipped.
- Diffing. Two trees can be compared line-by-line without false differences from key order or number spelling. A diff between branches of a UI is meaningful.
- Round-trip proof.
encode(decode(wire))must equal the input, byte for byte. Every conformant host proves this against the shared corpus – including the normalisation cases, where a lenient shorthand input must re-encode to the identical canonical form in every host. - Cache keys, dedup, notarisation. Anywhere "is this the same artefact?" matters, canonical bytes turn a hard semantic question into a string comparison.
The cross-host claim is not aspirational; it is the certification model. The wire format is specified language-neutrally, and the conformance corpus (round-trips, typed rejections, normalisation cases) is the shared oracle: an implementation is conformant because it passes the corpus, not because it shares code. You can watch the proof run live in the playground: two independent renderers – one compiled from F#, one TypeScript – decode the same wire and report byte-identical re-encodings.
Schema-only formats can bolt validation on later; canonicality is much harder to retrofit, because every existing producer becomes a source of non-canonical bytes the moment the rule is written down. It has to be day-one law. That is the quiet, structural difference between a UI format you can render and a UI format you can reason about.