The vocabulary is data too
Last reviewed: July 2026.
Fuaran's founding decision is that the interface is data – a typed tree with one
canonical serialisation, not a rendering instruction. In July 2026 the same
decision was applied one level up, to the language itself: the wire vocabulary –
every node kind, spec record, binding, action, and enum – is now declared once, as
data, in a small typed interface definition (IDL) in the core substrate
(UiIdl.fs
in fuaran-core). A handful of type constructors – strings, numbers, enums,
discriminated unions (generics included), nodes, lists, required/optional – turn
out to be enough to express the entire ~40-kind vocabulary.
From that one declaration, a generator emits the F# structural layer: the types,
the canonical encoder, the structural decoder, and a constructor per kind. As of
Fuaran.UI 0.8.0, the F# reference host is the generated host. Its hand-written
type definitions became type abbreviations over the generated layer, and its
hand-written per-kind node encoder – 2,351 lines of carefully mirrored
serialisation code – was deleted outright (the file that remains is 632 lines of
op-envelope plumbing that splices the generated encoder's output).
The interesting part is how you prove a change like that. Replacing a serialiser wholesale is normally a leap of faith; here it was a byte-diff. The conformance corpus – every node round-trip, every rejection, every normalisation case – was regenerated at the landing and reproduced byte-identically: 242 fixtures, zero differences. Canonical bytes are what make an invasive internal inversion checkable at all. If the encoder's output were allowed to vary in key order or number spelling, "did the rewrite change anything?" would be a semantic review; with canonical bytes it is a string comparison, and the answer was no.
What changes going forward:
- Adding a kind is one IDL entry. The generator emits the type, encoder, decoder, and constructor together – there is no hand-written encoder to forget. The compiler then enumerates every host surface the new case must reach, which is the forward-coupling rule (§11 of the specification) with the mechanical half automated away.
- "Is this change breaking?" becomes computable. Two IDL snapshots diff structurally: no removed case means additive, any removal means breaking. The classification is a property of the delta, not a reviewer's judgement call.
- The definition is diffable, hashable, and reviewable the way any other Fuaran artefact is – which is the point of the title.
The honest boundaries. The IDL scopes the structural layer only: behaviour – event closures, rendering, each host's ergonomic authoring surface – stays hand-written per host, deliberately, because behaviour is exactly what the wire never carries. The swap was a breaking release for code that constructs or pattern-matches the wire vocabulary directly (field optionality and a few payload shapes moved to match the wire's own view of absence); the smart-constructor authoring surface kept its signatures, and the complete authored demo application crossed the swap with zero source changes. And today F# is the first generated host: the other conformant hosts still hand-maintain their mirrors against the shared corpus, with generation from the same IDL the direction rather than the fact.
The end state is worth stating plainly: the specification names the IDL as the single source for the structural layer, the corpus certifies every host against the same bytes, and the reference implementation no longer contains a hand-written opinion about what the language is. The language's definition survives its implementations – which is what "the interface is data" always implied.