A 62-case jolt-vs-JVM probe across seq type identity, chunking granularity, eagerness, and realization timing. Findings: the whole producer family is lazy at construction (no eager bugs remain), and the 26 divergences fall into two classes that diverge by representation, not value. Lock in the laziness contract as certified corpus rows: construction=0 for keep/keep-indexed/map-indexed/distinct/partition-by/partition-all/ interpose/interleave/take-nth/reductions/tree-seq/replace, sequence realizes 1, next realizes 2, rest realizes 1. Pin the two accepted divergence classes (allowlisted, gate-guarded): - seq-type-model: jolt reifies seqs as PersistentList/LazySeq vs JVM's Cons/Iterate/LongRange/Repeat/Cycle/ChunkedSeq/StringSeq/KeySeq/RSeq/ ArraySeq/SubVector (jolt-aei7) - chunking-model: unchunked, realizes one where JVM realizes a 32-chunk; mapcat/dedupe fully lazy at construction (jolt-mm6v) known-divergences.edn gains both categories; SPEC.md documents the seq semantics contract. Data/doc only, no re-mint. certify 0 new / 0 stale.
57 lines
4.3 KiB
Clojure
57 lines
4.3 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 seqs are unchunked: forcing one element realizes one (JVM realizes a ~32-element chunk), and mapcat/dedupe realize 0 at construction where JVM forces the first chunk — jolt is a finer-grained lazy superset. jolt-mm6v"},
|
|
: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 "first over a vector realizes one, not a chunk", :category :chunking-model}
|
|
{:suite "chunking-model / unchunked realization granularity", :label "nth 0 over a vector realizes one", :category :chunking-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}]}
|