Skip to content

Philosophy

Each rule below comes with a tradeoff.

The schema is the only schema. Standard JSON Schema provides structure, while Standard Schema provides validation. Both interfaces are vendor-neutral, so shorn does not need validator-specific code. Tradeoff: shorn cannot encode values that JSON Schema cannot describe, including Date, bigint, Map, and Set. See rich types.

Bytes are canonical and derived. Fields are ordered by their names in UTF-16 order. Because the order is derived, schemas and validators cannot disagree about it. Tradeoff: you cannot choose the field order. The low-level m API cannot override it either.

No self-description. Payloads contain no field names, type tags, overall length, or version byte. Tradeoff: shorn cannot evolve schemas automatically. Use fingerprinted() to detect a mismatch; 26.7% of near-miss schemas otherwise decode to the wrong value without an error.

Detect, do not resolve. shorn reports a schema mismatch but does not reconcile two versions. Adding field tags would enable that, but would make payloads larger. Tradeoff: applications must keep historical codecs and select one by fingerprint. See ADR 0002.

Only imported features add bundle size. Async validation is a free function rather than a Schema method because class methods do not tree-shake. It adds 450 minified bytes only when imported. Tradeoff: async validation does not compose with fingerprinted(). See ADR 0001.

Invalid data fails explicitly. Unknown properties are refused, overlong varints are rejected, and trailing bytes cause an error. Invalid UTF-8 is fatal. Impossible array counts are rejected before allocation. DecodeError includes a byte offset. Tradeoff: schemas that allow arbitrary keys fail during codec construction. In fixed schemas, unexpected properties fail during encoding instead of being dropped silently.

Claims are measured. Every number in these docs comes from a benchmark in the repository. Changes that do not improve the measurements are rejected, including presizing the Writer, using indexed loops, and creating a lazy DataView. Tradeoff: claims stay narrow. shorn is neither the fastest codec nor the smallest after every compression method.

Round trips preserve representation. decode(encode(x)) returns x, not merely an equivalent value. shorn does not automatically convert ISO-8601 timestamps to epoch integers because the decoded string might differ from the original spelling. Tradeoff: an ISO-8601 timestamp uses about 20 more bytes than an epoch integer. Applications can choose the smaller representation explicitly.