Merge pull request #301 from jolt-lang/release/windows-v011

Windows release binaries (x86_64) via MSYS2/MinGW
This commit is contained in:
Dmitri Sotnikov 2026-07-02 18:57:46 +00:00 committed by GitHub
commit 7add315394
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 117 additions and 28 deletions

View file

@ -12,6 +12,7 @@ on:
push: push:
tags: tags:
- 'v*' - 'v*'
workflow_dispatch: {} # dry-run the build matrix without tagging
permissions: permissions:
contents: write # create/update the GitHub Release and upload assets contents: write # create/update the GitHub Release and upload assets
@ -26,10 +27,18 @@ jobs:
include: include:
- os: ubuntu-latest - os: ubuntu-latest
target: x86_64-linux target: x86_64-linux
shell: bash
# No x86_64-macos: GitHub is retiring the macos-13 Intel runner (jobs # No x86_64-macos: GitHub is retiring the macos-13 Intel runner (jobs
# queue forever). Intel Macs build from source. macos-14 is arm64. # queue forever). Intel Macs build from source. macos-14 is arm64.
- os: macos-14 - os: macos-14
target: aarch64-macos target: aarch64-macos
shell: bash
- os: windows-latest
target: x86_64-windows
shell: msys2 {0}
defaults:
run:
shell: ${{ matrix.shell }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
@ -78,6 +87,54 @@ jobs:
if: runner.os == 'macOS' if: runner.os == 'macOS'
run: brew install chezscheme lz4 run: brew install chezscheme lz4
# --- Windows: MSYS2/MinGW-w64 toolchain + Chez built from source (ta6nt).
# The whole job runs in the msys2 shell so cc/xxd/paths behave; the
# produced joltc.exe is a plain Windows binary (no MSYS runtime dep). ---
- name: Set up MSYS2 (Windows)
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: false
install: >-
git make vim unzip zip
mingw-w64-x86_64-gcc
mingw-w64-x86_64-lz4
mingw-w64-x86_64-zlib
- name: Cache Chez Scheme (Windows)
if: runner.os == 'Windows'
id: cache-chez-win
uses: actions/cache@v4
with:
path: chez-install
key: chez-${{ runner.os }}-v10.4.1-mingw64
- name: Build Chez Scheme from source (Windows)
if: runner.os == 'Windows' && steps.cache-chez-win.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch v10.4.1 https://github.com/cisco/ChezScheme.git /tmp/chez-src
cd /tmp/chez-src
./configure --threads --installprefix="$GITHUB_WORKSPACE/chez-install"
make -j"$(nproc)"
make install
- name: Put chez on PATH (Windows)
if: runner.os == 'Windows'
run: |
printf '#!/bin/sh
exec "%s/chez-install/bin/scheme" "$@"
' "$GITHUB_WORKSPACE" > "$GITHUB_WORKSPACE/chez-install/bin/chez"
chmod +x "$GITHUB_WORKSPACE/chez-install/bin/chez"
echo "$GITHUB_WORKSPACE/chez-install/bin" >> "$GITHUB_PATH"
# cc is the build's compiler name; alias it to mingw gcc
printf '#!/bin/sh
exec gcc "$@"
' > /usr/local/bin/cc || printf '#!/bin/sh
exec gcc "$@"
' > "$GITHUB_WORKSPACE/chez-install/bin/cc"
chmod +x /usr/local/bin/cc 2>/dev/null || chmod +x "$GITHUB_WORKSPACE/chez-install/bin/cc"
- name: Show Chez version - name: Show Chez version
run: chez --version run: chez --version
@ -132,16 +189,24 @@ jobs:
ver="${GITHUB_REF_NAME}" ver="${GITHUB_REF_NAME}"
name="joltc-${ver}-${{ matrix.target }}" name="joltc-${ver}-${{ matrix.target }}"
mkdir -p "dist/${name}" mkdir -p "dist/${name}"
cp target/release/joltc "dist/${name}/joltc"
cp README.md LICENSE "dist/${name}/" cp README.md LICENSE "dist/${name}/"
tar -C dist -czf "dist/${name}.tar.gz" "${name}" if [ "${{ runner.os }}" = "Windows" ]; then
( cd dist && shasum -a 256 "${name}.tar.gz" > "${name}.tar.gz.sha256" ) cp target/release/joltc.exe "dist/${name}/joltc.exe"
( cd dist && zip -r "${name}.zip" "${name}" && sha256sum "${name}.zip" > "${name}.zip.sha256" )
else
cp target/release/joltc "dist/${name}/joltc"
tar -C dist -czf "dist/${name}.tar.gz" "${name}"
( cd dist && shasum -a 256 "${name}.tar.gz" > "${name}.tar.gz.sha256" )
fi
ls -la dist ls -la dist
- name: Upload to the GitHub Release - name: Upload to the GitHub Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:
files: | files: |
dist/*.tar.gz dist/*.tar.gz
dist/*.tar.gz.sha256 dist/*.tar.gz.sha256
fail_on_unmatched_files: true dist/*.zip
dist/*.zip.sha256
fail_on_unmatched_files: false

View file

@ -56,7 +56,11 @@ jobs:
- name: Install JDK + Clojure (certify oracle) - name: Install JDK + Clojure (certify oracle)
run: | run: |
sudo apt-get install -y default-jdk rlwrap sudo apt-get install -y default-jdk rlwrap
curl -L -O https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh # --retry + --fail so a transient CDN error retries instead of handing
# bash an HTML error page (a 2min timeout page flaked a run)
curl --fail --retry 5 --retry-delay 10 --retry-all-errors -L -O \
https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh
head -1 linux-install.sh | grep -q '^#!' || { echo "installer download corrupt"; cat linux-install.sh | head -5; exit 1; }
sudo bash linux-install.sh sudo bash linux-install.sh
clojure --version clojure --version

View file

@ -245,6 +245,6 @@
;; table so `build` can foreign-entry them to spill the bundled Chez boots. On ;; table so `build` can foreign-entry them to spill the bundled Chez boots. On
;; Linux dlsym can't see executable symbols otherwise (macOS exports them anyway). ;; Linux dlsym can't see executable symbols otherwise (macOS exports them anyway).
(bld-system (string-append (bld-system (string-append
"cc -O2 -rdynamic -I'" bld-csv-dir "' -I'" jb-build "' '" jb-main-c "' '" "cc -O2 " (if bld-nt? "" "-rdynamic ") "-I'" bld-csv-dir "' -I'" jb-build "' '" jb-main-c "' '"
bld-csv-dir "/libkernel.a' -o '" jb-out "' " (bld-link-libs))) bld-csv-dir "/libkernel.a' -o '" jb-out "' " (bld-link-libs)))
(display (string-append "build-joltc: wrote " jb-out "\n")) (display (string-append "build-joltc: wrote " jb-out "\n"))

View file

@ -57,6 +57,7 @@
;; --- toolchain discovery ---------------------------------------------------- ;; --- toolchain discovery ----------------------------------------------------
(define bld-machine (symbol->string (machine-type))) (define bld-machine (symbol->string (machine-type)))
(define bld-osx? (bld-contains? bld-machine "osx")) (define bld-osx? (bld-contains? bld-machine "osx"))
(define bld-nt? (bld-contains? bld-machine "nt"))
;; The Chez executable, for the isolated compile pass (see build-binary step 4). ;; The Chez executable, for the isolated compile pass (see build-binary step 4).
(define bld-chez (define bld-chez
@ -94,14 +95,19 @@
;; Link flags. macOS Homebrew layout for the kernel's lz4/zlib/ncurses deps. ;; Link flags. macOS Homebrew layout for the kernel's lz4/zlib/ncurses deps.
(define (bld-link-libs) (define (bld-link-libs)
(if bld-osx? (cond
(let ((lz4 (bld-sh-capture "brew --prefix lz4 2>/dev/null"))) (bld-osx?
(string-append (let ((lz4 (bld-sh-capture "brew --prefix lz4 2>/dev/null")))
(if (> (string-length lz4) 0) (string-append "-L" lz4 "/lib ") "") (string-append
"-llz4 -lz -lncurses -framework Foundation -liconv -lm")) (if (> (string-length lz4) 0) (string-append "-L" lz4 "/lib ") "")
;; Linux: the Chez kernel pulls in compression (lz4/z), the expression "-llz4 -lz -lncurses -framework Foundation -liconv -lm")))
;; editor (ncurses + terminfo), threads, dlopen, libuuid, and clock_gettime. ;; Windows (ta6nt, MinGW-w64 under MSYS2): the Chez kernel pulls in
"-llz4 -lz -lncurses -ltinfo -ldl -lm -lpthread -luuid -lrt")) ;; compression, winsock, COM/UUID, and the registry.
(bld-nt?
"-llz4 -lz -lws2_32 -lrpcrt4 -lole32 -ladvapi32 -luser32 -lshell32 -lm")
;; Linux: the Chez kernel pulls in compression (lz4/z), the expression
;; editor (ncurses + terminfo), threads, dlopen, libuuid, and clock_gettime.
(else "-llz4 -lz -lncurses -ltinfo -ldl -lm -lpthread -luuid -lrt")))
;; --- runtime manifest (mirrors host/chez/cli.ss's load order) --------------- ;; --- runtime manifest (mirrors host/chez/cli.ss's load order) ---------------
;; A line is either literal Scheme text to inline, or a tag whose emission the build ;; A line is either literal Scheme text to inline, or a tag whose emission the build
@ -411,7 +417,15 @@
;; direct-link?: opt-in closed-world direct-linking (app->app calls bind directly, ;; direct-link?: opt-in closed-world direct-linking (app->app calls bind directly,
;; no runtime redefinition). Off by default in every mode — release stays ;; no runtime redefinition). Off by default in every mode — release stays
;; dynamically linked. ;; dynamically linked.
(define (bld-suffix? s suf)
(let ((n (string-length s)) (m (string-length suf)))
(and (>= n m) (string=? (substring s (- n m) n) suf))))
(define (build-binary entry-ns out-path mode natives embed-dirs ext-roots direct-link? tree-shake?) (define (build-binary entry-ns out-path mode natives embed-dirs ext-roots direct-link? tree-shake?)
;; Windows executables carry .exe; normalize here so the append-payload and
;; cc paths agree and the shell can run the result.
(let ((out-path (if (and bld-nt? (not (bld-suffix? out-path ".exe")))
(string-append out-path ".exe")
out-path)))
;; The self-contained path (jolt-embedded-bytes "stub/launcher") needs no csv ;; The self-contained path (jolt-embedded-bytes "stub/launcher") needs no csv
;; kernel files, no Chez, no cc — only the legacy cc path does. ;; kernel files, no Chez, no cc — only the legacy cc path does.
(unless (jolt-embedded-bytes "stub/launcher") (bld-check-toolchain)) (unless (jolt-embedded-bytes "stub/launcher") (bld-check-toolchain))
@ -558,7 +572,7 @@
(build-self-contained entry-ns out-path mode builddir flat-ss flat-so boot (build-self-contained entry-ns out-path mode builddir flat-ss flat-so boot
(bld-native-link-flags natives)) (bld-native-link-flags natives))
(build-with-cc entry-ns out-path mode builddir flat-ss flat-so boot boot-h main-c (build-with-cc entry-ns out-path mode builddir flat-ss flat-so boot boot-h main-c
(bld-native-link-flags natives)))))))) (bld-native-link-flags natives)))))))))
;; --- self-contained link (in-process compile + append the boot to the stub) --- ;; --- self-contained link (in-process compile + append the boot to the stub) ---
;; compile-file runs against the DEFAULT interaction environment, so the boot's ;; compile-file runs against the DEFAULT interaction environment, so the boot's

View file

@ -11,7 +11,7 @@
;; reset between cases so there is no leakage — same isolation a fresh process gives. ;; reset between cases so there is no leakage — same isolation a fresh process gives.
;; ;;
;; chez --script host/chez/run-corpus.ss ;; chez --script host/chez/run-corpus.ss
;; JOLT_CHEZ_ZJ_FLOOR=N override the regression floor (default 2730) ;; JOLT_CHEZ_ZJ_FLOOR=N override the regression floor (default 3390)
;; JOLT_CORPUS_LIMIT=N every-Nth stride (fast iteration; floor drops to 0) ;; JOLT_CORPUS_LIMIT=N every-Nth stride (fast iteration; floor drops to 0)
;; JOLT_DUMP_CRASH_LABELS=1 list crash + allowlisted labels ;; JOLT_DUMP_CRASH_LABELS=1 list crash + allowlisted labels
(import (chezscheme)) (import (chezscheme))
@ -196,7 +196,7 @@
;; Regression floor: fail on any NEW divergence or if pass drops below the floor. ;; Regression floor: fail on any NEW divergence or if pass drops below the floor.
(define base-floor (let ((s (getenv "JOLT_CHEZ_ZJ_FLOOR"))) (define base-floor (let ((s (getenv "JOLT_CHEZ_ZJ_FLOOR")))
(if s (string->number s) 2730))) (if s (string->number s) 3390)))
(define floor (if limit 0 base-floor)) (define floor (if limit 0 base-floor))
(when (or (> (length diverged) 0) (< pass floor)) (when (or (> (length diverged) 0) (< pass floor))
(printf "REGRESSION: pass ~a < floor ~a or ~a new divergence(s)\n" (printf "REGRESSION: pass ~a < floor ~a or ~a new divergence(s)\n"

View file

@ -361,7 +361,7 @@
(guard (e (#t #f)) (guard (e (#t #f))
(def-var! "clojure.core" "char-name-string" (letrec ((char-name-string (lambda (c) (let fnrec4381 ((c c)) (jolt-get (var-deref "clojure.core" "char-name-strings") c))))) char-name-string))) (def-var! "clojure.core" "char-name-string" (letrec ((char-name-string (lambda (c) (let fnrec4381 ((c c)) (jolt-get (var-deref "clojure.core" "char-name-strings") c))))) char-name-string)))
(guard (e (#t #f)) (guard (e (#t #f))
(def-var! "clojure.core" "rand-nth" (letrec ((rand-nth (lambda (coll) (let fnrec4382 ((coll coll)) (let* ((v (jolt-invoke (var-deref "clojure.core" "vec") coll))) (jolt-nth v (jolt-invoke (var-deref "clojure.core" "rand-int") (jolt-count v)))))))) rand-nth))) (def-var! "clojure.core" "rand-nth" (letrec ((rand-nth (lambda (coll) (let fnrec4382 ((coll coll)) (jolt-nth coll (jolt-invoke (var-deref "clojure.core" "rand-int") (jolt-count coll))))))) rand-nth)))
(guard (e (#t #f)) (guard (e (#t #f))
(def-var! "clojure.core" "random-sample" (letrec ((random-sample (case-lambda ((prob) (let fnrec4383 ((prob prob)) (jolt-invoke jolt-filter (lambda (_) (let fnrec4384 ((_ _)) (jolt-n< (jolt-invoke (var-deref "clojure.core" "rand")) prob)))))) ((prob coll) (let fnrec4385 ((prob prob) (coll coll)) (jolt-filter (lambda (_) (let fnrec4386 ((_ _)) (jolt-n< (jolt-invoke (var-deref "clojure.core" "rand")) prob))) coll)))))) random-sample))) (def-var! "clojure.core" "random-sample" (letrec ((random-sample (case-lambda ((prob) (let fnrec4383 ((prob prob)) (jolt-invoke jolt-filter (lambda (_) (let fnrec4384 ((_ _)) (jolt-n< (jolt-invoke (var-deref "clojure.core" "rand")) prob)))))) ((prob coll) (let fnrec4385 ((prob prob) (coll coll)) (jolt-filter (lambda (_) (let fnrec4386 ((_ _)) (jolt-n< (jolt-invoke (var-deref "clojure.core" "rand")) prob))) coll)))))) random-sample)))
(guard (e (#t #f)) (guard (e (#t #f))

View file

@ -26,6 +26,12 @@ static int self_path(char *buf, uint32_t size) {
/* _NSGetExecutablePath fills buf and reports the needed size on overflow. */ /* _NSGetExecutablePath fills buf and reports the needed size on overflow. */
return _NSGetExecutablePath(buf, &size); return _NSGetExecutablePath(buf, &size);
} }
#elif defined(_WIN32)
#include <windows.h>
static int self_path(char *buf, uint32_t size) {
DWORD n = GetModuleFileNameA(NULL, buf, size);
return (n == 0 || n >= size) ? -1 : 0;
}
#else #else
#include <unistd.h> #include <unistd.h>
static int self_path(char *buf, uint32_t size) { static int self_path(char *buf, uint32_t size) {

View file

@ -66,9 +66,10 @@
\backspace "backspace" \space "space"}) \backspace "backspace" \space "space"})
(defn char-name-string [c] (get char-name-strings c)) (defn char-name-string [c] (get char-name-strings c))
;; Random selection over the host rand primitives. ;; Random selection over the host rand primitives — the reference shape:
;; nth directly (nil returns nil via RT.nth; a set throws like the JVM).
(defn rand-nth [coll] (defn rand-nth [coll]
(let [v (vec coll)] (nth v (rand-int (count v))))) (nth coll (rand-int (count coll))))
(defn random-sample (defn random-sample
([prob] (filter (fn [_] (< (rand) prob)))) ([prob] (filter (fn [_] (< (rand) prob))))

View file

@ -7,7 +7,7 @@ test` from the repo root.
## The spec corpus ## The spec corpus
`corpus.edn` is the contract: ~2920 rows `{:suite :label :expected :actual}`, with `corpus.edn` is the contract: ~3570 rows `{:suite :label :expected :actual :portability}`, with
`:expected` sourced from reference JVM Clojure by `test/conformance/regen-corpus.clj`. `:expected` sourced from reference JVM Clojure by `test/conformance/regen-corpus.clj`.
It is frozen (the canonical source) — add or change cases here, then re-source the It is frozen (the canonical source) — add or change cases here, then re-source the
answers with `regen-corpus.clj` and re-certify with `test/conformance/certify.clj`. answers with `regen-corpus.clj` and re-certify with `test/conformance/certify.clj`.
@ -22,7 +22,7 @@ answers with `regen-corpus.clj` and re-certify with `test/conformance/certify.cl
chez --script host/chez/run-corpus.ss chez --script host/chez/run-corpus.ss
JOLT_CORPUS_LIMIT=200 … # every-Nth stride, fast iteration JOLT_CORPUS_LIMIT=200 … # every-Nth stride, fast iteration
JOLT_CHEZ_ZJ_FLOOR=N … # override the floor (default 2678) JOLT_CHEZ_ZJ_FLOOR=N … # override the floor (see run-corpus.ss)
- `run-unit.ss` — host-specific unit cases (`test/chez/unit.edn`) that aren't in the - `run-unit.ss` — host-specific unit cases (`test/chez/unit.edn`) that aren't in the
JVM-portable corpus: dot-forms, java statics, io, reader, walk, vars/namespaces, JVM-portable corpus: dot-forms, java statics, io, reader, walk, vars/namespaces,

View file

@ -3583,4 +3583,5 @@
{:suite "contracts / misc" :label "vector invocation has nth semantics; run! honors reduced; eval self-evaluates values" :expected "[:ioob 1 true]" :actual "[(try ([1 2] 5) (catch IndexOutOfBoundsException _ :ioob)) (let [c (atom 0)] (run! (fn [x] (swap! c inc) (reduced x)) [1 2 3]) (deref c)) (fn? (eval +))]" :portability :common} {:suite "contracts / misc" :label "vector invocation has nth semantics; run! honors reduced; eval self-evaluates values" :expected "[:ioob 1 true]" :actual "[(try ([1 2] 5) (catch IndexOutOfBoundsException _ :ioob)) (let [c (atom 0)] (run! (fn [x] (swap! c inc) (reduced x)) [1 2 3]) (deref c)) (fn? (eval +))]" :portability :common}
{:suite "contracts / misc" :label "intern demands an existing ns; counted? excludes strings; seqable? includes arrays" :expected "[:t false true]" :actual "[(try (intern (quote no-such-ns-xyz) (quote v) 1) (catch Throwable _ :t)) (counted? \"s\") (seqable? (object-array 2))]" :portability :jvm} {:suite "contracts / misc" :label "intern demands an existing ns; counted? excludes strings; seqable? includes arrays" :expected "[:t false true]" :actual "[(try (intern (quote no-such-ns-xyz) (quote v) 1) (catch Throwable _ :t)) (counted? \"s\") (seqable? (object-array 2))]" :portability :jvm}
{:suite "contracts / misc" :label "nth of nil honors notFound; a nil index throws; the starred specials are special" :expected "[:default :npe [true true true true true]]" :actual "[(nth nil 5 :default) (try (nth [1] nil) (catch NullPointerException _ :npe)) [(special-symbol? (quote case*)) (special-symbol? (quote deftype*)) (special-symbol? (quote letfn*)) (special-symbol? (quote reify*)) (special-symbol? (quote &))]]" :portability :common} {:suite "contracts / misc" :label "nth of nil honors notFound; a nil index throws; the starred specials are special" :expected "[:default :npe [true true true true true]]" :actual "[(nth nil 5 :default) (try (nth [1] nil) (catch NullPointerException _ :npe)) [(special-symbol? (quote case*)) (special-symbol? (quote deftype*)) (special-symbol? (quote letfn*)) (special-symbol? (quote reify*)) (special-symbol? (quote &))]]" :portability :common}
{:suite "contracts / misc" :label "rand-nth of nil is nil; of a set throws" :expected "[nil :t]" :actual "[(rand-nth nil) (try (rand-nth #{1 2}) (catch Throwable _ :t))]" :portability :common}
] ]

View file

@ -23,7 +23,6 @@ clojure.core-test.plus 11 0
clojure.core-test.plus-squote 11 0 clojure.core-test.plus-squote 11 0
clojure.core-test.pos-int-qmark 1 0 clojure.core-test.pos-int-qmark 1 0
clojure.core-test.quot 25 0 clojure.core-test.quot 25 0
clojure.core-test.rand-nth 0 1
clojure.core-test.realized-qmark 1 0 clojure.core-test.realized-qmark 1 0
clojure.core-test.rem 16 0 clojure.core-test.rem 16 0
clojure.core-test.remove-watch 0 1 clojure.core-test.remove-watch 0 1

View file

@ -10,7 +10,7 @@ read one data file, run each case, compare, report.
| File | Role | Generated by | | File | Role | Generated by |
|------|------|--------------| |------|------|--------------|
| `test/chez/corpus.edn` | **The spec.** ~2900 cases of `{:suite :label :expected :actual}`, `:expected` **sourced from reference JVM Clojure**. | `test/conformance/regen-corpus.clj` | | `test/chez/corpus.edn` | **The spec.** ~3570 cases of `{:suite :label :expected :actual :portability}`, `:expected` **sourced from reference JVM Clojure**. | `test/conformance/regen-corpus.clj` |
| `test/conformance/profile.edn` | Per-case **feature classification** — which non-portable cases need which host capability. | `certify.clj --profile` | | `test/conformance/profile.edn` | Per-case **feature classification** — which non-portable cases need which host capability. | `certify.clj --profile` |
| `test/conformance/known-divergences.edn` | The few rows whose JVM value is an opaque host object that can't round-trip to readable source (Java arrays/transients/atoms/beans/proxies print as `#object[..@addr]`), so the corpus keeps jolt's value. | `regen-corpus.clj` leftovers, hand-checked | | `test/conformance/known-divergences.edn` | The few rows whose JVM value is an opaque host object that can't round-trip to readable source (Java arrays/transients/atoms/beans/proxies print as `#object[..@addr]`), so the corpus keeps jolt's value. | `regen-corpus.clj` leftovers, hand-checked |
| `test/conformance/regen-corpus.clj` | Sources every `:expected` from reference **JVM Clojure** in one process. | — | | `test/conformance/regen-corpus.clj` | Sources every `:expected` from reference **JVM Clojure** in one process. | — |
@ -54,8 +54,8 @@ the canonical, frozen contract**: it is what every runtime consumes, what
Historically every `:expected` was hand-written. `certify.clj` removes that Historically every `:expected` was hand-written. `certify.clj` removes that
weakness: it evaluates every `:actual` (and `:expected`) on **JVM Clojure** in a weakness: it evaluates every `:actual` (and `:expected`) on **JVM Clojure** in a
fresh `user` namespace and checks jolt's `:expected` against what real Clojure fresh `user` namespace and checks jolt's `:expected` against what real Clojure
produces. Of ~2740 vanilla-certifiable rows, **>2730 match reference Clojure produces. Of ~3400 vanilla-certifiable rows, **all but ~26 allowlisted rows
exactly**. The rest are classified (see below) — none are silently wrong. match reference Clojure exactly**. The rest are classified (see below) — none are silently wrong.
```sh ```sh
clojure -M test/conformance/certify.clj # gate clojure -M test/conformance/certify.clj # gate
@ -243,8 +243,7 @@ documented model divergence — nothing in the baseline is an unexplained bug:
- **vec of an array copies**: the reference ADOPTS an Object array (mutating - **vec of an array copies**: the reference ADOPTS an Object array (mutating
the array mutates the vector); jolt copies — immutable semantics win over the array mutates the vector); jolt copies — immutable semantics win over
the implementation leak (`vec` namespace, one row). the implementation leak (`vec` namespace, one row).
- **eval of JVM shapes** (`rand-nth`/`eval` residue): rows needing JVM-only
evaluation shapes (e.g. evaluating a Java array literal).
A future change that makes any of these rows pass will fail the cts gate as A future change that makes any of these rows pass will fail the cts gate as
STALE, forcing this section and the baseline to be updated together. STALE, forcing this section and the baseline to be updated together.