Summary

  • JSON Type Definition checks an instance against one intentionally limited structural contract; acceptance is evidence about shape, not about truth or authority.
  • Its eight exclusive forms, local unknown-field policy and two-path error format favor portable code generation by refusing several attractive ambiguities.
  • Production governance begins where schema validation ends: authenticate the sender, authorize the act, test domain invariants, control replay and verify persistence and outcome separately.

A payment instruction arrives with an account identifier, a decimal amount, a timestamp and an event tag. Every field has the expected JSON type. Nothing extra is present. The validator returns no errors. The dangerous sentence is the one that often follows: “the request is valid.”

Valid in what sense? RFC 8927 gives a precise answer. JSON Type Definition, or JTD, decides whether an instance conforms to a declared schema. It can show that a member exists, an integer fits a named range, an object selected the permitted tagged-union branch, and an unexpected field was rejected. It cannot show that the account exists, the amount is affordable, the clock is honest, the sender may debit funds or the transfer settled.

That boundary is not a defect. It is the source of JTD’s portability.

A smaller language makes a sharper promise

RFC 8927 was published on the Independent Stream as Experimental. It explicitly lacks IETF consensus and is not Standards Track. Its experiment asks whether a schema language no more expressive than mainstream programming-language type systems can make code generation and validation behavior easier to reproduce across implementations.

The language has eight mutually exclusive forms. The empty form accepts anything. ref reuses a definition from the root. type handles primitive values and timestamps. enum selects one of a nonempty set of unique strings. elements applies one schema to each array member. properties describes a record. values describes a string-keyed map. discriminator selects a record shape through a string tag.

Mutual exclusivity matters. A schema cannot half-be a record and half-be a tagged union, leaving validators to invent precedence. Discriminator mappings cannot redefine the tag as another type or make a branch independently nullable. Definitions live only at the root, so the same reference name does not silently change meaning as evaluation descends. The specification trades expressive convenience for fewer interpretive forks.

That is Heng Lu’s minimum-initial-specification principle in executable form. The shared layer carries only the structure that independent parties can implement consistently. More expressive policy remains possible, but it does not become common law merely because somebody placed it beside the schema.

An empty gate can pass everything

The empty form is the cleanest antidote to inflated validation claims. An empty JTD schema accepts every JSON instance and never produces an error indicator. A green validation result can therefore mean “this object satisfied detailed constraints,” or it can mean “no content constraint was applied.” The receipt is meaningless without the schema identity and evaluation mode.

The same problem appears in gentler form with metadata. JTD permits metadata members for documentation, code-generation hints or local tools. Other parties are not expected to understand them. If a metadata extension changes validation, portable behavior exists only when the parties have made an out-of-band agreement. A field called minimumBalance inside metadata may look official and still be invisible to a conforming validator.

Evidence must therefore bind the message hash to the schema hash, schema version, validator version and extension profile. “JTD passed” is not reproducible if the evaluator cannot say which contract ran.

Unknown fields are a decision at every depth

The properties form distinguishes required members from optional ones. The same name cannot appear in both sets. Unspecified members are rejected by default, and additionalProperties:true can open that boundary.

But the permission is local. If the root object admits additional members, a nested object does not inherit that permission. The inner schema must make its own choice. This prevents one broad compatibility decision from silently opening every embedded control surface.

That detail has operational weight. Teams often loosen a top-level envelope to support forward-compatible routing metadata while expecting a nested authorization request to remain closed. Treating unknown-field policy as a global switch would erase that distinction. A validator record should report the rule at the object level where the field appeared, not merely label the whole message “strict” or “permissive.”

Location is not priority

JTD standardizes error indicators with two JSON Pointers. instancePath identifies the rejected location in the incoming value. schemaPath identifies the rule that rejected it. The pair is far more useful than an undifferentiated failure string: operators can reproduce which value met which boundary.

The order of error indicators is unspecified. The first item is not necessarily the root cause, the most severe defect or the first event in time. An application that approves remediation by array position invents semantics the RFC never supplied. JSON Pointer itself names a location inside a document; it does not name an owner or authorize a repair.

This is a recurring reality-layer mistake. A precise coordinate feels like a verdict. It is only an address for evidence.

Types remove some ambiguity, not the world’s ambiguity

JTD’s primitive types include signed and unsigned 8-, 16- and 32-bit integers, float32 and float64 numbers, booleans, strings and timestamps. The integer validator recognizes mathematical values in range even when JSON writes ten as 10, 10.0 or 1.0e1. A timestamp must fit RFC 3339 as refined by the Atom rules in RFC 4287.

That tells a receiver something useful. It does not say that a float was measured accurately, that a string is an existing customer or that a timestamp came from a trusted clock. A well-formed time in the future can pass syntax. So can a correctly shaped replay of an old, once-authorized command.

The omission of int64 and uint64 is especially honest. JSON implementations do not all preserve the full 64-bit integer range. I-JSON identifies the smaller interoperable range whose integers binary64 can represent exactly. Rather than expose a type whose name would promise more portability than the ecosystem can deliver, JTD leaves it out.

This restraint should guide extensions. A field should not be standardized merely because one generator can emit it. The common contract should promise only what independent receivers can preserve.

A tag chooses a branch, not an event

The discriminator form models a tagged union. An object must contain the named tag, its value must be a string found in the mapping, and the selected branch must validate. This prevents a message labeled account_deleted from omitting fields required for that branch.

It does not prove that an account was deleted. The tag came from the message producer. Authentication may establish who sent it; authorization may establish that the sender could request deletion; an audit record may establish acceptance; storage and readback may establish effect. Conflating those receipts lets a syntactically perfect assertion create reality by declaration.

The validator is also an attack surface

Schemas can refer to definitions, and careless reference graphs can cycle. RFC 8927 advises implementations evaluating user-supplied schemas to detect and abort circular references; otherwise a naive evaluator can loop indefinitely and become a denial-of-service target. RFC 8259 separately permits parser limits on input size, nesting depth and number precision.

Validation is therefore not a cost-free predicate. Operators need byte, depth, reference-expansion, error-count and execution-time budgets. They also need a policy for whether schemas are trusted artifacts, tenant input or remotely fetched dependencies. A schema that is valid JSON can still be hostile work.

Experiment means running evidence

RFC 8927 defines participation unusually clearly. A node participates when it validates messages, relies on another node to validate them or runs code generated from a JTD schema. The experiment succeeds through multiple independent implementations that actually exchange information. Publication alone does not provide that evidence.

This matches running-code primacy. An RFC number, repository badge or schema file is symbolic potential. Captured schema hashes, independent validator results, exchanged messages and observed error equivalence are operational proof. Adoption remains voluntary, and a node that does not implement the contract cannot be assumed to enforce it.

Sources

  1. RFC 8927 — JSON Type Definition
  2. RFC 8259 — The JSON Data Interchange Format
  3. RFC 7493 — The I-JSON Message Format
  4. RFC 6901 — JSON Pointer
  5. RFC 3339 — Date and Time on the Internet
  6. RFC 4287 — The Atom Syndication Format
  7. RFC 8610 — Concise Data Definition Language
  8. Heng Lu — Running-Code Primacy
  9. Heng Lu — Minimum Initial Specification, Localized Future Decision, and Voluntary Adoption
  10. Heng Lu — On Reality Layers, Symbolic Power, and Why Clarity Feels So Hostile