!!id:"https://tson.io/2026/37/m/meta.tn?sha256=568b589bdb162f5390ca46f6a941339d7b92ecb236bf233f8ed992b359b47a90" !!meta:"https://tson.io/2026/37/m/meta-kernel.tn?sha256=f2c2b278405f4c02ae327f70df07d5778744916da613a814104af6a312fcc145" !!import:"https://tson.io/2026/37/m/meta-kernel.tn?sha256=f2c2b278405f4c02ae327f70df07d5778744916da613a814104af6a312fcc145" @doc:""" TSON meta-schema (2026 Revision 37 draft). The canonical meta-schema for user schemas: a schema governed by the meta-kernel that adds the type constructors the core type library (core.tn) instantiates. Type constructors are a meta-schema concern: user schemas use them and by convention define none, a convention the grammar does not enforce. User schemas normally chain to this file via `!!meta`. The meta-kernel is reachable but not typically referenced directly — schemas that chain to meta-kernel are either alternative type libraries replacing meta, or extensions of the meta layer itself. Hash pins here are real digests over the bytes of this copy; see meta-kernel.tn's note. Three families of declarations live here: 1. Structural constructors: `bytes_type` (with the `bytes_encoding` enum selecting its text spelling), whose instance in core is `bytes`; and `scoped` (with the `scope_kind` enum), whose instances in core are `declared`, `extern` and `dynamic` and whose applications are `extern_of` and `extern_type`, with `schema_identity` typing the schemas it names. Fixed-size arrays have no constructor of their own: `[T; N]` is the spelling. 2. The `set` template — the `set` spelling of the kernel's `set_type` constructor, declared here for meta-layer extensions; core declares a sibling for user schemas. 3. Constraint vocabulary constructors for atom families that the kernel itself doesn't need: numeric (`float_type` for the approximate tier, with the `ieee_format` enum; `decimal_type` for the exact tier; `rational_type`; `complex_type`, with the `complex_component` enum), temporal (`date_type`, `time_type`, `datetime_type`, `duration_type`, `period_type`), identifier (`uuid_type`, `uri_type`), network (`ipv4_type`, `ipv6_type`, `cidr4_type`, `cidr6_type`, `mac_type`), and text (`email_type`). Plus annotation types — the classifying markers `ordering`, `bounded`, `exact`, `numeric`; the checked assertion `disjoint`; and the documentary `deprecated`, `title`, `comment`, `examples`, `read_only`, `write_only`. Annotation types must reside in the governing target's namespace ([TSON-SCHEMA] §6); placing them in meta makes them reachable from core and from every schema that meta governs. An annotation never changes a value, its type, or whether it is valid: validation is over values, and a schema with every annotation erased admits exactly the same values. [TSON-SCHEMA] §6 admits two further things within that rule — a load-time check, and a directive over how a class of encodings represents a value — and the annotations declared here use the first alone. The same stance governs the type docs: a value space is described without reference to any encoding, and where a doc mentions how TSON text spells a value it says so by name. Constructors that bind to a governing specification compose with the kernel's atom_specification mixin and pin the spec field with `=`. Their instances in core are empty, `float_type` aside, whose instances select a `format`. Constraint fields whose values are of an atom meta declares the constructor of but not the instance — a bound of the constrained atom's own family, or a network list of the `cidr4`/`cidr6` family on the address types — use the kernel's `value` escape hatch; the resolver reads each such token under the atom it stands for once that atom is in scope. A field that counts something — a length, a digit count, a prefix length, a precision — is typed by the kernel's `non_negative_integer`, and one that may be negative by `integer`; both arrive through this schema's kernel import. The ordered numeric families state their bounds as field groups ([TSON-SCHEMA] §5.11): one inclusive-or-exclusive group per side, so an inclusive and an exclusive bound on the same side is unrepresentable. Value-level coherence (the lower bound not exceeding the upper) is a schema-load check. `multiple_of`, wherever it appears (`decimal_type`, `rational_type`, `duration_type`, `period_type`, and the kernel's `integer_type`), follows one rule: the step is strictly positive — zero or a negative step is a schema-load error — the test ignores the sign of the value, a refinement may only tighten the step to an integer multiple of the inherited one, and the step composes with every other facet present. `members`, where it appears, is likewise uniform in what it admits: every member satisfies the other facets on the same body or the schema fails to load. Refinement differs by tier — the numeric tiers shrink the set, `text_type` sets it once. """ { @doc:""" The set spelling an author writes: `set` where the bare construction is `!set_type { element_type: text }`. A §5.10 template, not a constructor: it composes with nothing and so is not IS-A `top`. This copy serves meta-layer extensions. Core declares a sibling under the same name, so that user schemas reach it through their core import rather than through the governing namespace. """ set => !set_type { element_type: T } @doc:""" The base encodings of RFC 4648 that a text encoding may spell a `bytes` value in (HEX is §8's base16). """ bytes_encoding => !enum [BASE64 BASE64URL BASE32 HEX] @doc:""" Octet-sequence constraint vocabulary. Instance is `bytes` in core. The value is the octets: equality, identity, content addressing and the length facets are all over octets, never over a spelling — `length: 32` is a 32-byte digest whether it arrives as 64 hex characters, 44 base64 characters, or 32 raw bytes — so a round trip through any encoding preserves the value. `encoding` is a selector ([TSON-SCHEMA] §5.7): it picks which RFC 4648 alphabet the text class of encodings — TSON text, JSON, and any encoding whose values are character sequences — spells the octets in, and an encoding whose values are octets ignores it. A selector picks a spelling, so it never changes what two values compare as. It defaults to BASE64 (§4, padded), so a `bytes` position is base64 in every text encoding. `encoding` is not refinable. Another alphabet is another type, declared as its own instance: `hexdigest => !bytes_type { encoding: HEX length: 4 }`. Refining for length inherits the alphabet: `sha256 => !bytes ^ { length: 32 }` is a base64 sha256. """ bytes_type => atom & { encoding?: bytes_encoding ~ BASE64 length?: non_negative_integer min_length?: non_negative_integer max_length?: non_negative_integer } @doc:""" Which namespace a value's type may be drawn from. LOCAL is the governing namespace — the schema's own declarations and its imports ([TSON-SCHEMA] §2.2.3); EXTERN is a foreign schema, whose identity the value carries with it (in TSON text, a nested !!schema on the value; [TSON-DATA] §2.3). """ scope_kind => !enum [LOCAL EXTERN] @doc:"The non-empty set of namespaces a scoped instance admits." scope_set => !set_type { element_type: scope_kind min_items: 1 } @doc:""" Constructor for open sum types: the value names its own type, and the instance names the namespaces that name may be resolved in. `scope` says which namespaces are admitted. `schemas` narrows the foreign ones: absent is any foreign schema, a keyed map is those schemas, and a key's void value is every type that schema declares where a list is those types. The map is keyed by schema identity, so one schema cannot be listed twice, and keys are compared by canonical identity ([TSON-DATA] §2.2.1) so a pinned key and an unpinned !!schema in the data match; each pin is verified by the loader on its own. One coherence rule: `schemas` requires EXTERN in `scope`. """ scoped => sum & { scope: scope_set schemas?: {schema_identity => [type_name; 1..]?; 1..} } @doc:""" A schema's identity as a reference names it ([TSON-DATA] §2.2.1): an IRI-reference, so a host or path may carry characters beyond US-ASCII and a path-only reference names a library entry, and never a fragment. """ schema_identity => !iri_type { allow_fragment: false } @doc:""" IEEE 754-2019 interchange formats, both radices. Selects the representable grid of an approximate (`float_type`) value. The binary formats are the familiar base-2 floats; the decimal formats (decimal32/64/128) are base-10 *floating-point* — still approximate, with their own special values — and are NOT the exact fixed-point decimals of `decimal_type`. """ ieee_format => !enum [ BINARY16 BINARY32 BINARY64 BINARY128 BINARY256 DECIMAL32 DECIMAL64 DECIMAL128 ] @doc:""" Approximate-numeric constraint vocabulary (SQL's approximate tier; ISO/IEC 11404 approximate real). Instances in core are `float32` and `float64`. An approximate value is not stored as written: the receiver rounds it onto the discrete IEEE 754-2019 grid named by `format`, so precision may be lost and equality comparison is unsafe (ordering is PARTIAL — NaN is unordered). The `format` radix (binary or decimal) is the ISO 11404 radix characteristic of the type. The value set is that grid together with signed zeros, subnormals, the two infinities, and the canonical quiet NaN ([TSON-DATA] §5.6); `allow_nan`, `allow_infinity`, `allow_subnormal`, and `allow_negative_zero` default to true (`~ true` — the format's full set) and may be narrowed to false to exclude those representation artifacts. The bounds are optional domain restrictions validated against the value as written, before rounding; they do not bound the special values. Not a narrowing of the exact tier: infinities and NaN are not exact numbers. Bounds follow the header's field-group rule. There is no `multiple_of`; use the exact tier (`decimal_type`) when a step is required. A text-class token that does not land on the grid is rounded to nearest, ties to even (IEEE 754-2019 roundTiesToEven), the default across the format; loss of precision is expected, not an error. An encoding that carries the format's bits delivers a grid value directly and rounds nothing. """ float_type => atom & atom_specification & { spec?: = "https://ieeexplore.ieee.org/document/8766229" format: ieee_format ( min: value | exclusive_min: value )? ( max: value | exclusive_max: value )? allow_nan?: boolean ~ true allow_infinity?: boolean ~ true allow_subnormal?: boolean ~ true allow_negative_zero?: boolean ~ true } @doc:"The members of a decimal_type." decimal_member_set => !set_type { element_type: value min_items: 1 } @doc:""" Exact-numeric constraint vocabulary (SQL's exact tier; ISO/IEC 11404 `scaled`, radix 10). Instance in core is `number` — the unrestricted exact number, which is also the JSON Schema `number` mapping (arbitrary magnitude and precision, finite, no special values). Nothing is rounded on the way in, so equality is safe and ordering is TOTAL. Scale is not part of the value — `1`, `1.0` and `1.00` are one value, and whether a spelling's trailing zeros survive a round trip is an encoding's promise, not the type's. `total_digits`/`fraction_digits` are the ISO `scaled` precision and scale (SQL `DECIMAL(precision, scale)`): total significant digits and digits after the point. Bounds follow the header's field-group rule. `multiple_of` is exact here (e.g. `multiple_of` 0.05 admits only nickel steps). `fraction_digits` and `multiple_of` overlap but are not equivalent: `fraction_digits` 2 admits any hundredth, `multiple_of` 0.05 only multiples of a nickel. `members` enumerates the admitted values. The resolver reads each member under the constrained atom before the set is formed, so `1` and `1.0` are one member and a duplicate rather than two, and a member that does not parse as a decimal fails at schema load. The header's uniform `members` rule applies. """ decimal_type => atom & { ( min: value | exclusive_min: value )? ( max: value | exclusive_max: value )? multiple_of?: value total_digits?: non_negative_integer fraction_digits?: non_negative_integer members?: decimal_member_set } @doc:""" Rational constraint vocabulary. Instance is `rational` in core. Exact (ℚ; ISO/IEC 11404 `rational`), so bounds and `multiple_of` are exact. Bounds follow the header's field-group rule. Constraints operate on the value, not the written token: tokens are not normalized, so `"2/4"` and `"1/2"` satisfy the same constraints. """ rational_type => atom & { ( min: value | exclusive_min: value )? ( max: value | exclusive_max: value )? multiple_of?: value } @doc:""" Allowed component types for a complex value. A closed vocabulary of numeric types (naming their core counterparts): exact `INTEGER` (Gaussian integers ℤ+ℤi), `NUMBER` (exact arbitrary precision), `RATIONAL` (ℚ+ℚi); approximate `FLOAT32`, `FLOAT64`. The members are a partial order, not a chain, and a refinement may move `component` only to a member whose value set is a subset of the source's: `INTEGER ⊂ NUMBER ⊂ RATIONAL` are the exact tiers and `FLOAT32 ⊂ FLOAT64` the approximate ones, and the two families are incomparable. So `!complex ^ { component: INTEGER }` narrows and its IS-A holds, while `!complex ^ { component: FLOAT64 }` is refused: a float64 complex is not a `complex`, and is declared as its own type, `!complex_type { component: FLOAT64 }`. """ complex_component => !enum [INTEGER NUMBER RATIONAL FLOAT32 FLOAT64] @doc:""" Complex constraint vocabulary. Instance is `complex` in core. A complex value is a pair of components (real and imaginary parts). `component` selects the type of both parts from the closed `complex_component` vocabulary; it defaults to `NUMBER` (a DEFAULT, §5.2), so a bare complex has exact components — a defaulted selector. Complex has no useful total order (`@ordering:NONE`), so the order-based facets of the other numeric tiers do not apply here. Exactness is inherited from `component` rather than fixed: `INTEGER`/`NUMBER`/`RATIONAL` components give an exact complex, `FLOAT32`/`FLOAT64` an approximate one, so `complex` carries no `@exact` marker of its own. """ complex_type => atom & { component?: complex_component ~ NUMBER } @doc:"Date constraint vocabulary. Instance is `date` in core." date_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc3339" ( min: value | exclusive_min: value )? ( max: value | exclusive_max: value )? } @doc:""" Time constraint vocabulary. Instance is `time` in core. `precision` is a constraint on the value, not on a spelling: `precision: N` admits a value that is a whole number of 10^-N seconds, so `precision: 3` is millisecond resolution and `precision: 0` whole seconds. The atom is exact — nothing is truncated; a value off the grid is rejected ([TSON-SCHEMA] §5.5). Reading admits any spelling of an admitted value, trailing zeros included, so `12:00:00.500` is admitted under `precision: 1`; a text encoding writing the value writes at most N fractional digits, `12:00:00.5`. """ time_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc3339" ( min: value | exclusive_min: value )? ( max: value | exclusive_max: value )? precision?: non_negative_integer } @doc:""" Datetime constraint vocabulary. Instance is `datetime` in core. `precision` as for `time_type`: the value is a whole number of 10^-N seconds, a constraint on the value ([TSON-SCHEMA] §5.5). """ datetime_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc3339" ( min: value | exclusive_min: value )? ( max: value | exclusive_max: value )? precision?: non_negative_integer } @doc:""" Elapsed-time constraint vocabulary. Instance is `duration` in core. Lexical form is the RFC 3339 Appendix A `duration` production with three extensions and one restriction: an optional leading `-`; a fraction on the seconds component only, written with `.` (`PT0.5S`, never `PT1.5H` or `PT0,5S`); any subset of D, H, M, S may be omitted provided at least one component is present and order is kept (`PT1H30S` is admitted); and the Y and month-M components are not admitted — `P1M` is one month and belongs to `period`; a minute is `PT1M`. `PnW` stands alone, as in the ABNF (`P1W2D` is an error). A day is exactly 86400 s and a week 7 days. The value is a signed exact decimal number of seconds — `number`'s value space, in seconds: nothing is rounded. So `PT90M`, `PT1H30M` and `P0DT5400S` are one value, `PT0S`, `P0D` and `-PT0S` are one value, and ordering is TOTAL. Bounds compare the value, not the token. Both ends of that space are fixed at a signed 64-bit count of nanoseconds. The seconds component admits at most nine fractional digits, and a magnitude may not exceed 2^63 - 1 nanoseconds (about 292 years) — stated as a magnitude, so negating an admitted duration always yields an admitted one. A processor MUST represent every value in that range and MUST reject one outside it whether or not its own representation could hold it. `precision` as for `time_type`, and it is `fraction_digits` on the seconds count: the value is a whole number of 10^-N seconds, so `precision: 0` admits whole seconds only and `precision: 9` is the nanosecond grid. A constraint on the value and not on a spelling — `PT0.50S` is a whole number of tenths — and it may not exceed 9. `multiple_of` is `number`'s `multiple_of` on that same count, under the header's uniform rule: `PT15M` admits only quarter-hour values. """ duration_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc3339#appendix-A" ( min: value | exclusive_min: value )? ( max: value | exclusive_max: value )? precision?: non_negative_integer multiple_of?: value } @doc:""" Calendar-span constraint vocabulary. Instance is `period` in core. Lexical form is the RFC 3339 Appendix A `duration` production restricted to an optional leading `-`, then `P` followed by a Y component, an M component, or both in that order; no fraction, no W or D component and no `T` part (`P1M15D`, `P1Y0D` and `P1YT1H` are errors — use `duration`, or a record with a `period` field and a `duration` field, for mixed spans). The value is a signed integer number of months, so `P1Y` and `P12M` are equal, `P0Y`, `P0M` and `-P0M` are equal, and ordering is TOTAL. Bounds compare the value, not the token. `multiple_of` is a period under the header's uniform rule: `P3M` admits only whole quarters. """ period_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc3339#appendix-A" ( min: value | exclusive_min: value )? ( max: value | exclusive_max: value )? multiple_of?: value } @doc:"UUID constraint vocabulary. Instance is `uuid` in core." uuid_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc9562" version?: non_negative_integer } @doc:""" URI constraint vocabulary per RFC 3986. Instances are `uri` and `uri_reference` in core. The facets are the kernel's iri_type's, over RFC 3986's grammar: `schemes` lists the admitted schemes as scheme_name values, which fold case; `allow_relative` admits a relative reference (§4.2) beside a URI (§3), so its default is a URI-reference (§4.1); `allow_fragment` admits a fragment (§3.5), and withdrawing it beside `allow_relative` leaves an absolute-URI (§4.3). A URI is US-ASCII (§2), and its text as written, as an IRI is. """ uri_type => text_type & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc3986" schemes?: scheme_set allow_relative?: boolean ~ true allow_fragment?: boolean ~ true normalization?: = NONE } @doc:""" Email constraint vocabulary. Instance is `email` in core. An address is its text as written: a mailbox's local part is case-sensitive (RFC 5321 §2.4), so a form over the whole text could merge two mailboxes. """ email_type => text_type & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc5322" normalization?: = NONE } @doc:""" IPv4 address constraint vocabulary. Instance is `ipv4` in core. The spec pin cites RFC 3986 for its `IPv4address` production — the normative dotted-quad grammar ([TSON-DATA] §5.5). `within` and `excluding` list IPv4 networks in CIDR text (quoted — the form contains `/`): the address must lie inside at least one `within` network when the field is present, and inside no `excluding` network. `excluding` carves holes out of `within`. """ ipv4_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc3986" within?: [value] excluding?: [value] } @doc:""" IPv6 address constraint vocabulary. Instance is `ipv6` in core. `within` and `excluding` list IPv6 networks in CIDR text (quoted): the address must lie inside at least one `within` network when the field is present, and inside no `excluding` network. """ ipv6_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc4291" within?: [value] excluding?: [value] } @doc:""" IPv4 network constraint vocabulary. Instance is `cidr4` in core. `min_prefix`/`max_prefix` narrow the prefix length within the family range 0-32; bounds outside that range are invalid at the schema level. `within` lists IPv4 networks in CIDR text (quoted): the value must be a subnet of at least one. `excluding`: the value must not overlap any listed network — overlap, not containment. """ cidr4_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc4632" min_prefix?: non_negative_integer max_prefix?: non_negative_integer within?: [value] excluding?: [value] } @doc:""" IPv6 network constraint vocabulary. Instance is `cidr6` in core. `min_prefix`/`max_prefix` narrow the prefix length within the family range 0-128. `within` and `excluding` list IPv6 networks in CIDR text (quoted), with the semantics of `cidr4_type`: subnet-of for `within`, non-overlap for `excluding`. """ cidr6_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc4291" min_prefix?: non_negative_integer max_prefix?: non_negative_integer within?: [value] excluding?: [value] } @doc:"MAC address (EUI-48) constraint vocabulary. Instance is `mac` in core." mac_type => atom & atom_specification & { spec?: = "https://www.rfc-editor.org/rfc/rfc9542" } @doc:""" Ordering classification (ISO/IEC 11404 / XSD fundamental facet): whether the value space has an order relation. Not a container's `ordered` facet, which says whether element order is part of a value. """ ordering => @annotation !enum [NONE PARTIAL TOTAL] @doc:""" Boundedness classification (ISO/IEC 11404 / XSD fundamental facet): true when the value space has a finite least and greatest value. """ bounded => @annotation boolean @doc:""" Exactness classification (ISO/IEC 11404 characterizing property): true for exact types (values preserved as written), false for approximate types (values rounded to a representation grid). """ exact => @annotation boolean @doc:"Numeric type marker annotation." numeric => @annotation void @doc:""" Author's assertion that a choice's variants are distinguishable by an encoding's form resolution — discrimination-class distinctness, not disjointness of inhabitance — checked against the resolver's derived `disjoint` fact in the `!choice` body ([TSON-SCHEMA] §5.4, §8.1). The fact is class-stable: a variant whose forms straddle classes (an approximate atom still admitting NaN or the infinities, a map with a compound key) has no class, so the untagged values of a choice are one set in every encoding. A void-targeted presence marker like `@numeric`: written bare, and presence is the assertion. Carries no decode force — the resolver computes disjointness whether or not the annotation is present. The derivation is total: present and refuted is a schema-load error; present and verified, or absent, is silent. """ disjoint => @annotation void @doc:""" Marks a definition or field as deprecated. A bare presence marker like `@numeric`; the reason, where there is one, is `@doc`'s to give. """ deprecated => @annotation void @doc:"Short human-readable name for a definition or field." title => @annotation text @doc:""" A note for a schema's maintainers rather than its readers (JSON Schema's `$comment`): where `@doc` is what a documentation tool shows, `@comment` is what it leaves out. """ comment => @annotation text @doc:""" Example values for a definition or field, each the text a reader is shown: conventionally the value written in TSON notation, so a record's example is a string such as `"{ x: 1 }"`. Nothing parses or checks an example against the type it illustrates; the annotation is documentation only. """ examples => @annotation [text] @doc:""" Marks a field an encoding's consumers may read but not write. A bare presence marker like `@numeric`: absence is the default, so there is no false to write (JSON Schema's `readOnly: false` maps to no annotation). `@read_only` and `@write_only` on one field is a schema-load error. """ read_only => @annotation void @doc:""" Marks a field an encoding's consumers may write but not read. A bare presence marker, on `@read_only`'s terms. """ write_only => @annotation void }