jolt/test/conformance/known-divergences.edn
Yogthos bd33d605ef Chunk range/map/filter to match JVM Clojure
range, map, and filter were fully element-by-element lazy, so
(map f (range 1 50)) realized one element per first/nth where JVM
Clojure realizes a whole 32-element chunk. range is a chunked
LongRange on the JVM and map/filter are chunk-preserving, so the
observable side-effect timing differed.

Following clojure.lang.LongRange, ChunkedCons, ChunkBuffer and
core.clj, this adds a crest field to the cseq record and a
cseq-chunked constructor modeling ChunkedCons (a standalone chunk
pvec, an offset, and the after-chunk seq). The chunk accessors move
to seq.ss next to the representation they read. map/filter/remove
take a chunked branch when the source is chunked, realizing the whole
chunk and chunk-cons'ing it onto a lazy rest, so their output is
itself chunked and chained transforms each batch by 32. Bounded range
is now an eager chunked seq, and the reduce fast path flows through a
ChunkedCons rest. The chunk-buffer/chunk/chunk-cons builder API in
natives-array.ss now produces a real ChunkedCons.

Single-arg (range), multi-coll map, and plain lazy seqs stay
element-by-element, like the JVM.

Adds a lazy / chunking suite to the corpus that observes realization
timing via an atom counter: first over a chunked map realizes 32,
crossing a chunk boundary realizes 49, chained maps batch [32 32],
filter applies the predicate to the whole first block, and a plain
lazy seq still realizes one element at a time. Two cases that
documented the old over-laziness now assert the JVM value of 32 and
were dropped from the allowlist. certify against JVM Clojure 1.12.3
reports 0 new and 0 stale divergences.
2026-06-29 22:02:06 -04:00

62 lines
5.1 KiB
Clojure

{:doc
"Rows of test/chez/corpus.edn whose :expected differs from reference JVM Clojure. The corpus is JVM-sourced (regen-corpus.clj), so this list is only the rows whose JVM value is an opaque host object that cannot round-trip to readable source — Java arrays, transients, atoms, beans, proxies, and chunks print as #object[..@addr] with a per-run identity — plus the (fn* foo) strictness case. For that the corpus keeps jolt's value. certify.clj gates on NEW (unlisted) divergences and STALE entries. Keyed by [suite label].",
:legend
{:numeric-model
"jolt has a numeric tower (exact integer / Ratio / double); no BigDecimal",
:host-model
"no JVM host: classes->name strings, type->symbol, *in* is a map, inline-impl extenders, duck-typed with-open close",
:reader-model
"jolt reader features (:jolt) + syntax-quote literal collapse (spec 2.4 S25); map source-order preserved",
:printer-model
"jolt printer renders transients/atoms/print-method overrides differently from JVM #object",
:strictness
"jolt is intentionally stricter: throws on odd assoc! args / defn with no param vector",
:impl-detail
"representation detail: syntax-quote yields a list? (JVM yields a Cons)",
:seq-type-model
"jolt models every seq as PersistentList (eager) or LazySeq (deferred); JVM reifies a specialized class per producer (Cons/Iterate/LongRange/Repeat/Cycle/ChunkedSeq/StringSeq/KeySeq/RSeq/ArraySeq/SubVector). Values and laziness are correct, only (class …) differs. jolt-aei7",
:chunking-model
"jolt now chunks range/vector seqs through map/filter like the JVM (forcing one element realizes the whole ~32-element chunk). What remains finer-grained: mapcat/dedupe realize 0 at construction where the JVM's (apply concat …) / sequence transformer force the first chunk just to build the seq. jolt-mm6v",
:integer-box-model
"jolt unifies every integer as one exact-integer type. A Chez fixnum is an immediate identical to the plain integer (no distinct identity to tag, no metadata on numbers), so (byte/short/int n) report Long, not Byte/Short/Integer. Value/arithmetic/equality are correct; a faithful narrow box would crash raw compiled (+ …) or de-optimize all arithmetic. jolt-k9sw"},
:entries
[{:suite "forms / fn",
:label "no param vector",
:category :strictness}
{:suite "io / cold tagged types via print-method",
:label "atom override fires nested",
:category :reader-model}
{:suite "io / cold tagged types via print-method",
:label "transient map",
:category :printer-model}
{:suite "io / cold tagged types via print-method",
:label "transient vector",
:category :printer-model}
{:suite "untested / JVM-shape stubs (documented jolt behavior)",
:label "bean is the map",
:category :host-model}
{:suite "untested / JVM-shape stubs (documented jolt behavior)",
:label "proxy resolves nil",
:category :host-model}
{:suite "untested / chunk family (eager equivalents) + cat",
:label "chunk round-trip",
:category :host-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "cons over a vector", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "iterate", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "range", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "repeat", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "cycle", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "vector seq", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "string seq", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "keys", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "rseq", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "sort", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "subvec", :category :seq-type-model}
{:suite "seq-type-model / specialized seq classes collapse", :label "drop over a vector", :category :seq-type-model}
{:suite "chunking-model / unchunked realization granularity", :label "mapcat is fully lazy at construction", :category :chunking-model}
{:suite "chunking-model / unchunked realization granularity", :label "dedupe is fully lazy at construction", :category :chunking-model}
{:suite "integer-box-model / narrow int class collapses to Long", :label "byte class", :category :integer-box-model}
{:suite "integer-box-model / narrow int class collapses to Long", :label "short class", :category :integer-box-model}
{:suite "integer-box-model / narrow int class collapses to Long", :label "int class", :category :integer-box-model}
{:suite "integer-box-model / narrow int class collapses to Long", :label "instance? Byte is false", :category :integer-box-model}
{:suite "integer-box-model / narrow int class collapses to Long", :label "instance? Long is true", :category :integer-box-model}]}