Conformance
DXN has four implementations and one specification. Two parts of the specification exist so that they can be compared exactly: a canonical text form for every value, and a category for every error. A shared suite of cases holds each implementation to both.
The canonical form
Every value has exactly one canonical form: a .dxn rendering fixed down to the byte. Every implementation must be able to produce it, and parsing it gives back an equal value. It is also what defines when two map keys are the same.
- No header, no comments, no
@_; one space between items or entries, none inside the brackets, no commas, no newlines. - Maps and sets are written in canonical order: their entries’ or items’ canonical forms compared by Unicode code point. Ordered maps and structs keep their own order.
- Nothing is normalised:
1.50Mstays1.50M,2/4stays2/4. - Floats are written as the shortest digits that read back as the same double, with ECMAScript’s thresholds for when to use an exponent,
.0on whole numbers and no+in exponents. - Strings escape
",\, newline, tab and carriage return as\",\\,\n,\t,\r, every other control character as\x{…}in lowercase hex, and nothing else. - Times drop trailing zeros from their fraction; UUIDs are lowercase; bytes are standard base64 with padding; a duration that is all zero is
PT0S; a struct carries(N)when its version is known.
%{b: 2, a: 1, "z" => 3}%{"z" => 3 a: 1 b: 2}[1e3 1e21 1.5e-7 0.000001 -0.0 1.50M 2/4 ~T[12:30:00.500] @duration "P0D"]
[1000.0 1.0e21 1.5e-7 0.000001 -0.0 1.50M 2/4 ~T[12:30:00.5] @duration "PT0S"]
Error categories
Implementations report errors in their own way, but every error a reader, writer or schema compiler raises belongs to exactly one category, and the implementation must expose it on the error value. Categories are compared exactly; messages are not part of the specification.
| Category | Raised when |
|---|---|
syntax | text does not parse |
binary | a .dxnb document is malformed: magic, version, a tag’s payload |
key/not-allowed | a map or extra-field key has a type that may not be a key |
encode/unsupported | a host value has no DXN meaning, or no form in the text being written |
schema/compile | a .dxns document is not a valid schema |
schema/duplicate-version | a name and version are loaded twice |
schema/not-loaded | a replace names a version that is not loaded |
schema/unknown-version | a struct’s version is older than the latest loaded and not loaded itself |
schema/no-materializer | an older version arrives and no materializer is registered |
schema/field-count | a positional struct has the wrong number of items for its version |
schema/missing-field | a required field is absent, or a positional form has no value for an optional field without a default |
schema/type-mismatch | a field’s value does not match its declared type |
schema/undeclared-field | a strict decode meets a field the schema does not declare |
schema/shadowed-field | an extra field has the name of a declared field |
schema/materializer | a materializer refuses, or returns a value the latest schema rejects |
schema/version-discipline | the compatibility check finds changed content under the same version, or a version going down |
The conformance suite
The Dextrin Conformance Suite is a set of cases, each naming an operation, its input and the one outcome it expects: a canonical form, exact bytes, a document’s text or an error category. Its cases cover scalars, floats, map keys, structs, extra fields, schemas, binary and documents. Each implementation ships an adapter that answers a batch of cases — in dextrin, mix dextrin.conformance REQUEST ANSWER — and every answer is compared exactly.
Requests and answers are JSON, and values under test stay DXN text or .dxnb bytes, so the suite depends on no implementation of DXN — not even one of the four. It lives in the Praxis workspace for now and is meant to move to a repository of its own.