This directory tracks which real-world, pure-Clojure libraries load and
run on cljw. It is the concrete, externally-grounded half of the
convergence definition (F-010, Convergence Campaign Stage 0.5 / 1.3): cw v1
is not "converged" on the strength of its own test suite alone — it is
converged when libraries people actually use in the wild require cleanly.
ladder.md is the ranked table. This file explains how it is built and
maintained.
Libraries differ enormously in how much of the host platform they touch. A
data-structure utility that calls only clojure.core is a far easier — and
far earlier — target than one that reaches into java.io, threads, or
deftype-heavy machinery. Ranking by pure-Clojure degree turns "support
real libraries" into an ordered ladder the autonomous loop can climb one rung
at a time: each rung that fails surfaces exactly one next gap to close, and
clearing it tends to unblock several libraries at once.
Each candidate is placed by how much non-clojure.core host surface it
needs, lowest (easiest) first:
| Degree | Meaning |
|---|---|
| 1 | Zero Java/host interop. Only clojure.core + bundled clojure.* ns. |
| 2 | Touches java.lang.Math / java.util.regex only (cljw largely covers). |
| 3 | Touches java.util.* / java.text.* (locale, collections, BreakIterator). |
| 4 | Touches java.io / readers / writers / streams. |
| 5 | Threads, agents, deftype-heavy protocols, java.time, reflection. |
Degree is judged from the library's (:import ...) / java. interop forms
plus its transitive require graph. A library that is degree-1 in its own
namespace but transitively pulls a degree-4 namespace is ranked at the
higher (harder) degree.
deps.edn resolution landed (Campaign Stage 1.2): a ./deps.edn with
:paths / :deps {lib {:local/root "…"}} / :git/url+:git/sha / :aliases
contributes its source roots to the front of the require classpath, so a
library is loaded by pointing a small consumer deps.edn at it:
# A consumer project whose deps.edn names the library by :local/root:
# {:deps {org.clojure/data.priority-map {:local/root "/path/to/clone"}}}
cd consumer-proj && cljw -e '(require (quote clojure.data.priority-map))'The older manual classpath still works: -cp <root> (alias --classpath,
colon-separated) makes require search each root for <ns-path>.clj then
.cljc (ADR-0084); $CLJW_PATH is the fallback when -cp is absent.
The residual limitation is Maven, not deps.edn: a :mvn/version coord is
skipped (ADR-0101 am.1), not fetched — cljw has no artifact downloader — so
a transitive Maven dependency must still be cloned and supplied as an
explicit :local/root / :git coord by hand. A library blocked only by an
un-cloned transitive dep (not a real cljw feature gap) is marked
blocked: no deps.edn yet historically; the accurate phrasing is "blocked on an
un-fetched Maven/transitive dep" — they are not cljw failures, just
not-yet-loadable without laying the dep out.
.cljc reader conditionals resolve to the :clj branch on cljw (cljw is a
Clojure runtime, not ClojureScript), so #?(:clj ... :cljs ...) picks the
JVM-shaped branch — which is exactly where the Java interop blockers live.
- Fetch its source (raw GitHub is fine for a manual probe) and lay each
namespace out under a classpath root matching its
nspath. requireit on cljw with-cp <root>and exercise a representative function or two.- Judge its pure-Clojure degree (table above) from imports + transitive requires.
- Add a row to
ladder.mdwith{rank, lib, version, pure-degree, status, first-blocking-gap}. Runmd-table-align ladder.md. - If the library hits a real cljw feature gap (not just the missing
resolver), record it in the row as
NEEDS-ROW: <gap>. Do not edit.dev/debt.yamlfrom here — the main loop reads theNEEDS-ROW:markers and creates the debt rows, cross-referenced against the Java-tier SSOT (data/compat_tiers.yaml, Campaign Stage 0.3).
- loads —
requiresucceeds and exercised functions return correct values. - partial — loads but some functions hit a gap; the gap is named.
- fails —
requireitself fails on a real cljw gap (named). - blocked: no deps.edn yet (historical label) — not a cljw gap; blocked
only on an un-fetched transitive Maven dep that must be cloned + supplied
as a
:local/root/:gitcoord by hand (the:paths/:local/root/:gitresolver itself landed, Stage 1.2). - not-probed — seeded by static source inspection only; not yet loaded.