Mosaic one model, many lenses

ADR 0001: The spec is data with a closed vocabulary

  • Status: accepted
  • Date: 2026-09-23

Context

Many DSLs grew expression languages: rule expressions, policy expressions, workflow expressions — each with its own parser, evaluator, sandbox, and error model. They became second programming languages: powerful, unlintable, and impossible to reason about exhaustively.

Decision

The spec files contain no expressions. Types are a closed vocabulary of nine primitives (string, bool, i64, i32, u64, u32, f64, uuid, datetime), declared entities and enums, and one level of lists. Behavior is expressed by referencing a hand-written Rust function; middleware is a closed vocabulary (v0: cache). Anything outside the vocabulary is a parse error, not a runtime surprise.

An expression language (a small CEL-like one) is explicitly deferred: it may come in a later version, as an ADR, when a concrete need exists.

Consequences

  • The parser is serde itself; there is no grammar to maintain.
  • mosaic schema can describe the entire input precisely.
  • Features are added one vocabulary word at a time, each visible in the schema and the goldens.

Proof

cargo test -p mosaic-grammar → ty::tests::rejects_option_and_nested_arrays (optional types, nested arrays, and empty types are rejected at parse time) and ty::tests::accepts_both_list_spellings.