# JSON-e compatibility contract

Reference: json-e/json-e revision `87167b21ed1a4040cc48cfabb61a62c77e6ac0fd`, JS package 4.8.4, MPL-2.0. The unmodified upstream specification and its normalized JSON projection are in tests/fixtures. All 1,175 cases are represented by generated MoonBit assertions; no cases were filtered. Normative values are compared structurally; rejection cases must reject, but upstream error class names/text are not API commitments. Official Python and JavaScript implementations were both executed against the entire pinned specification with a frozen UTC clock; both matched all cases. Reference result digests are recorded separately from implementation tests.

Supported operators: $eval, $json, $if, $flatten, $flattenDeep, $fromNow, $let, $map, $reduce, $find, $match, $switch, $merge, $mergeDeep, $sort, $reverse. Builtins: min, max, sqrt, abs, ceil, floor, range, lowercase, uppercase, len, str, number, strip, rstrip, lstrip, join, split, fromNow, typeof, defined. Context can shadow builtins. Omission is distinct from JSON null. Dot access rejects missing keys; bracket object access yields null. Array negative indices and clamped slices are supported. String ordering is lexical by Unicode scalar value rather than MoonBit default length-first ordering.

Deliberate boundaries: the portable API defaults now to 1970-01-01T00:00:00.000Z; callers inject current UTC explicitly, or override context.now. Dates accept the pinned millisecond UTC form, years 0001..9999. Relative years are 365 days and months 30 days as upstream. Numeric values are finite binary64; range/index operands must fit signed 32-bit bounds. Non-finite arithmetic rejects instead of emitting non-JSON numbers. Functions cannot be passed from host context JSON or returned uncalled. There are no filesystem imports, process execution or network side effects. Error messages differ; resource limits can reject work that upstream permits. Case mapping uses the MoonBit core implementation; passing this corpus is bounded evidence, not a proof for every Unicode case or every future upstream release.

Default budgets: 1,000,000 evaluator/parser/conversion steps, nesting 128 (configurable up to 256), 100,000 elements/code units per input or output collection/string. String sizes are also checked on input conversion and intermediate expression results; concatenation checks the combined size before allocating. CLI request limit 4,000,000 code units and batch limit 1,000, each request with independent engine budget. Budgets bound interpreter work; they are not an operating-system sandbox or a strict heap-byte cap. Native runtime verification is delegated to actual Linux CI because the local Windows environment has no C compiler.

Run `python scripts/check_reference.py` and `moon test --deny-warn`; the former validates source locks and every generated test input and expected outcome. `specification_test.mbt` is test data, excluded from production line counts.
