docs: refresh clojure-vs-jerboa status markers + add reader-literals explainer

ober

dfc55032068f249b6fa7b1aa2e372ab326da9d7f

diff --git a/docs/clojure-reader.md b/docs/clojure-reader.md
new file mode 100644
index 0000000..3b9fa90
--- /dev/null
+++ b/docs/clojure-reader.md
@@ -0,0 +1,115 @@
+# Clojure Reader Literals in Jerboa
+
+This document elaborates on §4.9 of [`clojure-remaining.md`](./clojure-remaining.md) — why Jerboa does not (yet) have Clojure's four reader literals, what the design options are, and why the item is marked "risky / could be deferred forever."
+
+## What Clojure's reader literals buy you
+
+Clojure has four reader-level shorthands that create data structures directly from source syntax, no constructor call:
+
+| Clojure literal | Reads as | Equivalent call |
+|---|---|---|
+| `{:a 1 :b 2}` | persistent map | `(hash-map :a 1 :b 2)` |
+| `#{:a :b :c}` | persistent set | `(hash-set :a :b :c)` |
+| `[1 2 3]` | persistent vector | `(vector 1 2 3)` |
+| `:foo` | keyword object | (none — keywords are only literals) |
+
+They're "reader" features because the tokenizer turns `{a 1 b 2}` into a map value *before* macro expansion runs. `{}` isn't a function call — it's the data structure itself.
+
+This matters for ergonomics because Clojure code is saturated with data literals: `(assoc m :name "Alice" :age 30)`, `(reduce-kv f {} xs)`, `(filter #{:admin :owner} roles)`. All of these compile to constructor calls in the workaround form, which feels heavier than they read in Clojure.
+
+## Why Jerboa can't just alias them
+
+Each of those characters is **already taken** by Jerboa's reader:
+
+```scheme
+[...]    ;; Gerbil/Chez-style alternative parentheses
+         ;; (let ([x 1] [y 2]) ...)   ← used everywhere in the codebase
+
+{method obj args}   ;; method dispatch sugar → (~ obj 'method args)
+                    ;; e.g. {length s} → (~ s 'length)
+
+name:    ;; trailing-colon keyword syntax → #:name
+:std/sort ;; leading-colon module-path sugar → (std sort)
+```
+
+Look at any `.ss` file in the repo — `[x 1]` shows up in every `let`, `for`, `cond` clause, and `match` pattern. If `[...]` suddenly meant "persistent vector", every binding form in the entire codebase breaks silently.
+
+Same for `{...}` — it's used for method dispatch, not just reserved. `{add stack 5}` is valid Jerboa today; in Clojure it would be a map literal with `add`, `stack`, `5` as alternating keys and values (which wouldn't even parse, odd arity).
+
+So a straight alias is a non-starter. The question is whether you can get the Clojure ergonomics *some other way*.
+
+## The design doc's proposal (§4.9)
+
+The proposal is an **opt-in file-local reader directive**:
+
+```scheme
+#!clojure-reader
+(import (std clojure))
+
+(def user {:name "Alice" :age 30})          ;; → (hash-map :name "Alice" :age 30)
+(def admins #{"alice" "bob"})               ;; → (hash-set "alice" "bob")
+(def coords [1 2 3])                         ;; → (vec 1 2 3)
+(def role :admin)                            ;; → 'admin (symbol)
+```
+
+The directive is the first token in the file. If present, the reader enters "Clojure literal mode" for the rest of that file only — `[...]` becomes vector construction instead of bracket parens, `{...}` becomes map construction instead of method dispatch, etc. Files without the directive are unchanged.
+
+It's the same pattern as `#!chezscheme` / `#!r6rs` at the top of Chez files — a file-scoped reader switch.
+
+## Why it's marked "risky"
+
+Four reasons, roughly in order of severity:
+
+1. **File-local state in a re-entrant reader.** `lib/jerboa/reader.sls` is hand-written and not obviously extensible. Adding file-scoped modes requires a dynamic parameter threaded through every reader production, and dynamic-wind discipline so nested reads (e.g. string ports) don't leak the mode out.
+
+2. **Loss of `[...]` as bracket parens.** Even in opt-in files, the author loses the Gerbil convention that brackets are just prettier parens. They can't write `(let ([x 1]) ...)` any more; they have to pick one notation and stick to it. Porters often expect to mix freely.
+
+3. **Debuggability.** `[x y]` means different things in different files. Error messages like "got vector expected list at line 5" won't tell you which reader mode was active; people will spend time hunting `#!clojure-reader` at the top of a file they didn't write.
+
+4. **The ergonomics payoff may not justify the cost.** The design doc's last bullet:
+
+   > **Could be deferred forever.** If we conclude the ergonomics cost isn't worth the reader complexity, skip it and document the constructor forms as the permanent Jerboa idiom.
+
+## What you get today without it
+
+Every structure has a constructor that reads nearly as cleanly:
+
+```scheme
+(import (std clojure))
+
+;; Map — variadic key/value pairs
+(def user (hash-map 'name "Alice" 'age 30))
+
+;; Set — variadic args
+(def admins (hash-set "alice" "bob"))
+
+;; Vector — variadic args
+(def coords (vec 1 2 3))
+
+;; Keyword — trailing-colon reader syntax
+(def role name:)                    ;; a real keyword object
+;; Or use a symbol, which is what most Jerboa code does:
+(def role 'admin)
+```
+
+And for access, all the polymorphic ops work uniformly (that's what §4.4–§4.10 were about):
+
+```scheme
+(get user 'name)           ;; → "Alice"
+(contains? admins "alice") ;; → #t
+(assoc user 'role 'admin)  ;; → new map with role added
+```
+
+So the "missing" part is purely syntactic weight at literal construction sites — not missing semantics.
+
+## Recommendation
+
+The polymorphic operation layer (landed in Phase E, §4.4–§4.10) is the 90% of what Clojure porters actually want. The literal-syntax layer is the last 10%, at a cost of reader surgery and permanent debuggability weirdness. The design doc itself hedges toward "deferred forever," and the current recommendation is to agree with that — unless there's a specific porting target where literal density is really hurting readability, the constructor forms are a fine permanent idiom.
+
+If you *do* want to pursue it, the cleanest starting point isn't the full four-literal reader mode — it's adding just `:keyword` literal syntax as a reader extension (no conflict with module paths if it's behind the directive), then evaluating whether the rest is worth the `[...]` tradeoff. That's a few hours instead of a few days and tells you whether the approach is viable.
+
+## See also
+
+- [`clojure-remaining.md`](./clojure-remaining.md) — full design doc for the Clojure-compat campaign, including §4.9 where this item originates.
+- `lib/jerboa/reader.sls` — the hand-written reader that would need to be modified.
+- `lib/std/clojure.sls` — the `(std clojure)` module that provides the constructor forms (`hash-map`, `hash-set`, `vec`) used as workarounds today.
diff --git a/docs/clojure-vs-jerboa.md b/docs/clojure-vs-jerboa.md
index 8615283..8a529f7 100644
--- a/docs/clojure-vs-jerboa.md
+++ b/docs/clojure-vs-jerboa.md
@@ -2,50 +2,60 @@
 
 A comprehensive inventory of what Clojure offers that Jerboa/Chez Scheme doesn't (or has in weaker form), with detailed explanations of what each feature does and why Clojure developers consider it a game-changer.
 
-Organized from most foundational to most specialized. In-progress Jerboa work noted where relevant.
+Organized from most foundational to most specialized. Status markers:
+
+- **[landed]** — shipped in Jerboa; see the section for the module name
+- **[partial]** — some of the feature exists, some parts still missing
+- **[open]** — real gap, still worth implementing
+- **[deferred]** — real gap, intentionally deferred (see section for reasoning)
+- **[non-goal]** — deliberately not pursued (see section)
+
+Last updated: 2026-04-11 after Phase E of the Clojure-compat campaign (metadata, multimethods, protocols, atom watches, agents, record-as-map). See [`clojure-remaining.md`](./clojure-remaining.md) for the campaign's own design doc.
 
 ---
 
 ## Table of Contents
 
 1. [The Philosophical Foundation](#1-the-philosophical-foundation)
-2. [Persistent Immutable Data Structures](#2-persistent-immutable-data-structures) (in progress)
-3. [Transients](#3-transients)
-4. [The Unified Sequence Abstraction](#4-the-unified-sequence-abstraction)
-5. [Lazy Sequences](#5-lazy-sequences)
-6. [Transducers](#6-transducers)
-7. [Reducers](#7-reducers)
-8. [The Four Reference Types](#8-the-four-reference-types)
-9. [Software Transactional Memory (STM)](#9-software-transactional-memory-stm)
-10. [core.async (CSP Channels)](#10-coreasync-csp-channels) (in progress)
-11. [Protocols](#11-protocols)
-12. [Multimethods](#12-multimethods)
-13. [Records and Types](#13-records-and-types)
-14. [Destructuring Everywhere](#14-destructuring-everywhere)
-15. [Metadata](#15-metadata)
-16. [Dynamic Vars and Thread-Local Binding](#16-dynamic-vars-and-thread-local-binding)
-17. [Clojure Spec](#17-clojure-spec)
-18. [Namespaces](#18-namespaces)
-19. [EDN and Tagged Literals](#19-edn-and-tagged-literals)
-20. [Reader Conditionals](#20-reader-conditionals)
-21. [Rich Number Tower](#21-rich-number-tower)
-22. [Keyword/Symbol Semantics](#22-keywordsymbol-semantics)
-23. [`loop`/`recur` and Tail Calls](#23-looprecur-and-tail-calls)
-24. [`for` Comprehensions](#24-for-comprehensions)
-25. [Delays, Futures, and Promises](#25-delays-futures-and-promises)
-26. [Memoize, Trampoline, and Friends](#26-memoize-trampoline-and-friends)
-27. [Exception Design: ex-info](#27-exception-design-ex-info)
-28. [core.match](#28-corematch)
-29. [core.logic (miniKanren)](#29-corelogic-minikanren)
-30. [Zippers](#30-zippers)
-31. [Specter](#31-specter)
-32. [Datafy / Nav](#32-datafy--nav)
-33. [clojure.walk](#33-clojurewalk)
-34. [Set Operations](#34-set-operations)
-35. [Property-Based Testing (test.check)](#35-property-based-testing-testcheck)
-36. [Component Lifecycle Libraries](#36-component-lifecycle-libraries)
-37. [REPL-Driven Development Culture](#37-repl-driven-development-culture)
-38. [Miscellaneous Small Things That Add Up](#38-miscellaneous-small-things-that-add-up)
+2. [Persistent Immutable Data Structures](#2-persistent-immutable-data-structures) **[landed]**
+3. [Transients](#3-transients) **[landed]**
+4. [The Unified Sequence Abstraction](#4-the-unified-sequence-abstraction) **[partial]**
+5. [Lazy Sequences](#5-lazy-sequences) **[open]**
+6. [Transducers](#6-transducers) **[landed]**
+7. [Reducers](#7-reducers) **[open]**
+8. [The Four Reference Types](#8-the-four-reference-types) **[partial]** — atoms, agents, volatiles landed; refs (STM) open
+9. [Software Transactional Memory (STM)](#9-software-transactional-memory-stm) **[open]**
+10. [core.async (CSP Channels)](#10-coreasync-csp-channels) **[landed]** — minus parked-go CPS
+11. [Protocols](#11-protocols) **[landed]**
+12. [Multimethods](#12-multimethods) **[landed]**
+13. [Records and Types](#13-records-and-types) **[landed]**
+14. [Destructuring Everywhere](#14-destructuring-everywhere) **[partial]**
+15. [Metadata](#15-metadata) **[landed]**
+16. [Dynamic Vars and Thread-Local Binding](#16-dynamic-vars-and-thread-local-binding) **[partial]**
+17. [Clojure Spec](#17-clojure-spec) **[non-goal]**
+18. [Namespaces](#18-namespaces) **[partial]**
+19. [EDN and Tagged Literals](#19-edn-and-tagged-literals) **[open]**
+20. [Reader Conditionals](#20-reader-conditionals) **[deferred]**
+21. [Rich Number Tower](#21-rich-number-tower) **[landed]** (via Chez)
+22. [Keyword/Symbol Semantics](#22-keywordsymbol-semantics) **[partial]**
+23. [`loop`/`recur` and Tail Calls](#23-looprecur-and-tail-calls) **[landed]** (proper TCO via Chez)
+24. [`for` Comprehensions](#24-for-comprehensions) **[partial]**
+25. [Delays, Futures, and Promises](#25-delays-futures-and-promises) **[partial]**
+26. [Memoize, Trampoline, and Friends](#26-memoize-trampoline-and-friends) **[partial]**
+27. [Exception Design: ex-info](#27-exception-design-ex-info) **[open]**
+28. [core.match](#28-corematch) **[landed]**
+29. [core.logic (miniKanren)](#29-corelogic-minikanren) **[open]**
+30. [Zippers](#30-zippers) **[open]**
+31. [Specter](#31-specter) **[open]**
+32. [Datafy / Nav](#32-datafy--nav) **[open]**
+33. [clojure.walk](#33-clojurewalk) **[open]**
+34. [Set Operations](#34-set-operations) **[landed]**
+35. [Property-Based Testing (test.check)](#35-property-based-testing-testcheck) **[open]**
+36. [Component Lifecycle Libraries](#36-component-lifecycle-libraries) **[open]**
+37. [REPL-Driven Development Culture](#37-repl-driven-development-culture) **[partial]**
+38. [Miscellaneous Small Things That Add Up](#38-miscellaneous-small-things-that-add-up) **[partial]**
+
+**See also:** [Where to focus next](#still-worth-implementing-as-of-2026-04-11) — a condensed roadmap of the remaining open items ranked by value/effort.
 
 ---
 
@@ -81,7 +91,7 @@ Jerboa has `[...]` aliased to `(...)` and has strings/numbers, but no literal ma
 
 ## 2. Persistent Immutable Data Structures
 
-**Status in Jerboa**: In progress.
+**Status in Jerboa**: **[landed]** — `(std pmap)` / `(std pvec)` / `(std pset)` / `(std pqueue)` / `(std sorted-set)`. All HAMT-based where applicable, structural equality and hashing, polymorphic iteration via `(std iter)`.
 
 Clojure's defining technical achievement. Four core persistent collections, all implemented via **Hash Array Mapped Tries (HAMT)** or variants, giving effectively-O(1) (really O(log32 N)) updates with **structural sharing**.
 
@@ -132,8 +142,16 @@ Lists are the classic singly-linked list but immutable. Queues are O(1) persiste
 4. **Compositional updates**: `assoc-in`, `update-in`, `merge-with`, `get-in`.
 5. **Equality by value**: Two maps are `=` iff they contain the same entries. Same for nested structures. Hashes are structural.
 
-### Jerboa Gap
-Chez's built-in hashtables are mutable, and `eq?`/`equal?` comparison of them works but there's no structural sharing. Lists are persistent-ish (cons cells), but conjugate, assoc, update-in style operations don't exist. No persistent vector, map, set, or queue with HAMT characteristics. You're building this — it's the foundation for almost everything else.
+### Jerboa Status
+
+Jerboa now has the full family:
+
+- `(std pmap)` — HAMT persistent map with O(log32 N) assoc/dissoc/lookup, structural equality, structural hashing. Also exported as `imap` via `(std immutable)`. Records participate polymorphically: `(get point 'x)`, `(keys point)`, etc.
+- `(std pvec)` — 32-way persistent vector, O(log32 N) assoc/conj/pop/nth, structural equality.
+- `(std pset)` — HAMT persistent set, structural equality, union/intersection/difference.
+- `(std pqueue)` — O(1) amortized persistent FIFO queue.
+- `(std sorted-set)` — ordered persistent set with range queries.
+- Update-in-style operations (`get-in`, `assoc-in`, `update-in`) live in `(std misc nested)` and dispatch polymorphically over all of the above plus records, concurrent-hash, hash-table, and vector.
 
 ---
 
@@ -153,7 +171,13 @@ A sidekick to persistent data: **transients** are a mutable "building mode" for 
 
 The genius: transients give you mutability's performance without losing immutability's semantics, as long as you don't leak the transient across threads.
 
-**Jerboa gap**: No persistent structures yet, so no transients. When you build them, transients should be part of the design from day one — they're how Clojure avoids the "but immutable is slow!" critique.
+**Jerboa status**: **[landed]**. Each of the persistent types has a transient sidekick:
+
+- `imap-transient` / `tmap-set!` / `tmap-delete!` / `persistent-map!` for pmap.
+- `pvec-transient` / `transient-set!` / `transient-append!` / `pvec-persistent!` for pvec.
+- `pset` has `pset-persistent!` for bulk building.
+
+`(std clojure)` exposes the Clojure-style surface: `transient`, `persistent!`, `assoc!`, `dissoc!`, `conj!`. The typical "build a big collection in a loop" pattern gets the Clojure perf story without losing the immutable API on the outside.
 
 ---
 
@@ -173,7 +197,12 @@ Every higher-order operation — `map`, `filter`, `reduce`, `take`, `drop`, `tak
 
 Because of this uniformity, once you learn 40 sequence functions, they work on *everything*.
 
-**Jerboa has**: `for/collect`, `for/fold`, `map`, `filter`, `flatten`, `unique`, `take`, `drop`, `every`, `any`, `filter-map`, `group-by`, `zip`, `frequencies`, `partition`, `interleave`, `mapcat`, `distinct`, `keep`, `split-at`, `append-map`, `snoc`. Good coverage but not a single unified abstraction — lists, vectors, hash tables, and strings each have their own APIs. Iteration via `in-list`/`in-vector`/`in-hash-keys` in `for` is closest to the seq idea but is a macro-time thing, not a runtime polymorphic protocol.
+**Jerboa status**: **[partial]**. Very good functional coverage: `for/collect`, `for/fold`, `map`, `filter`, `flatten`, `unique`, `take`, `drop`, `every`, `any`, `filter-map`, `group-by`, `zip`, `frequencies`, `partition`, `interleave`, `mapcat`, `distinct`, `keep`, `split-at`, `append-map`, `snoc`. Two runtime-polymorphic layers have landed since the original writeup:
+
+- `(std iter)` — a polymorphic iteration protocol that `for` can consume, bridging pmap/pset/pvec/list/vector/string uniformly.
+- `(std clojure)` — `first`/`rest`/`next`/`last`/`seq`/`reduce`/`into` dispatch polymorphically over all the persistent types, plus records-as-maps.
+
+What's still not there is a **lazy** unified seq — Clojure's `seq` abstraction is lazy by default, and Jerboa's polymorphic iteration is eager. That's §5 territory.
 
 ---
 
@@ -204,7 +233,7 @@ Laziness composes naturally with `take`, `take-while`, `drop-while`. You can wri
 
 **Gotchas Clojure exposes**: chunking (realizes 32 at a time for efficiency), head retention (holding the head of a lazy seq prevents GC of realized elements), and `doall`/`dorun` for forcing.
 
-**Jerboa has**: Chez's lazy library exists but isn't in the prelude. `in-producer` gives some of this via `for`. No culture of lazy-by-default; you build with eager collections and decide to go lazy. A lazy-seq macro integrated into the prelude would close much of the gap.
+**Jerboa status**: **[open]**. Chez's lazy library exists but isn't in the prelude. `in-producer` gives some of this via `for`. No culture of lazy-by-default; you build with eager collections and decide to go lazy. A `lazy-seq` macro integrated into the prelude plus `cycle`/`repeat`/infinite `iterate`/`take-while`/`drop-while` would close most of the gap. Tier 2 in the roadmap below.
 
 ---
 
@@ -264,14 +293,9 @@ The same pipeline works over eager collections, lazy seqs, channels, and reducib
 
 Most people never write raw transducers — they compose `map`, `filter`, `mapcat`, `take`, `drop`, `dedupe`, `distinct`, `partition-by`, `partition-all`, `map-indexed`, `keep`, `keep-indexed`, `cat` (catenating transducer), `halt-when`, `interpose`, `random-sample`.
 
-### Jerboa gap
-
-Jerboa has `for/fold` and `for/collect` which are macro-level fused loops — conceptually similar in that they avoid intermediate lists, but not composable values you can pass around. Building a transducer library in Jerboa would require:
-1. Agreeing on the reducing-function protocol.
-2. Providing arity-overloaded `map`/`filter`/etc. that return transducers when called without a collection.
-3. Providing `into`/`transduce`/`sequence`/`eduction` entry points.
+### Jerboa status
 
-Huge payoff. Probably the single feature most worth porting after persistent data.
+**[landed]** — `(std transducer)` ships a full transducer library with the standard cast: `tmap`, `tfilter`, `tmapcat`, `ttake`, `tdrop`, `tdistinct`, `tdedupe`, `tpartition-by`, `tpartition-all`, `tkeep`, `ttake-while`, `tdrop-while`, `tinterpose`, `thalt-when`, etc. Composed with `comp`, applied with `transduce` or `into`, and wired into CSP channels via `(chan n xform)` so transducers transform values as they flow through `(std csp)` pipelines. `(into [] xform data)` works uniformly over lists, vectors, pmaps, psets, pvecs. Zero intermediate allocation.
 
 ---
 
@@ -290,7 +314,7 @@ An earlier (2012) attempt at the same composition problem that lives on alongsid
 
 The `fold` bit is the key — Clojure automatically parallelizes the reduction for persistent vectors/maps using a divide-and-conquer `combine-fn`.
 
-**Jerboa gap**: No parallel fold. `pmap` exists (you mentioned fixing it recently), but no reducer-level parallelism that automatically splits collections. Chez has threads; the primitives are there.
+**Jerboa status**: **[open]**. No parallel fold. `pmap` exists but no reducer-level parallelism that automatically splits collections via a divide-and-conquer combine function. Chez has threads; the primitives are there. This would need a split protocol on pvec and pmap that returns two halves, plus a fork/join driver. Tier 2.
 
 ---
 
@@ -307,7 +331,7 @@ Plus `var` for thread-local dynamic binding.
 
 ### Atom
 
-**Status in Jerboa**: Recently aliased in `(std misc atom)` and re-exported from the prelude.
+**Status in Jerboa**: **[landed]** — `(std misc atom)` and re-exported from the prelude. Includes `add-watch!` / `remove-watch!`, `set-validator!`, and `volatile!` / `vreset!` / `vswap!` / `vderef` for single-thread-fast volatiles.
 
 ```clojure
 (def counter (atom 0))
@@ -350,7 +374,12 @@ Key properties:
 
 See section [16](#16-dynamic-vars-and-thread-local-binding).
 
-**Jerboa gap**: Atoms just arrived. Agents and refs are the big missing pieces. Building agents on top of Chez threads + a work queue is straightforward. STM is harder.
+**Jerboa status**: **[partial]**. Atoms, volatiles, and agents have landed; STM refs are still open.
+
+- **Atoms** — `(std misc atom)`, with watches and validators.
+- **Volatiles** — `(std misc atom)`, for cases where you want a mutable cell without CAS.
+- **Agents** — `(std agent)`. A dedicated worker thread per agent, backed by a CSP channel queue. `send` / `send-off` / `await` / `agent-error` / `agent-value` / `restart-agent` / `shutdown-agent!` / `clear-agent-errors` all present. Matches Clojure's `:fail` error-mode semantics: if an action throws, the agent enters an error state and further sends raise until `restart-agent` is called.
+- **Refs (STM)** — still open. See §9.
 
 ---
 
@@ -390,19 +419,20 @@ Lock-based concurrency is notoriously error-prone: deadlocks, lock ordering, for
 
 **Cost**: transactions can't do IO (or must be idempotent), and contention leads to retry churn. But for "update these five refs consistently" problems, nothing is as ergonomic.
 
-**Jerboa gap**: None of this. Chez has mutexes and condition variables. Building STM requires:
+**Jerboa status**: **[open]**. None of STM exists yet. Chez has mutexes and condition variables; building STM requires:
+
 1. Version counters on refs.
 2. Transaction-local read/write sets.
 3. A commit protocol with conflict detection.
 4. Retry semantics.
 
-It's a significant engineering project, but the abstraction is well-specified.
+It's a significant engineering project, but the abstraction is well-specified. Atoms + agents cover ~80% of the "I need concurrent state" use cases; STM matters most when you need to coordinate updates across multiple refs atomically (transfer-money problems). A scaled-down STM that coordinates 2–8 refs per transaction is dramatically simpler than a fully general one and covers most practical uses.
 
 ---
 
 ## 10. core.async (CSP Channels)
 
-**Status in Jerboa**: In progress.
+**Status in Jerboa**: **[landed]** — `(std csp)`. Channels, `go`, `alts!`, transducer-backed channels via `(chan n xform)`, buffers (fixed, dropping, sliding), `timeout`, `pipe`, `pipeline`, `mult`/`tap`, `pub`/`sub`, `mix`/`admix!`/`unmix!`/`toggle!`, `put!`/`take!` with callbacks, `split`, `onto-chan!`, `async/reduce`. Timer wheel for `timeout` behind `JERBOA_CSP_TIMER_WHEEL`. The one non-landed piece is **parked-go via CPS transformation** — Jerboa's `go` runs on an OS thread rather than a state-machine-transformed continuation, so you can't have a million parked go-blocks on a small thread pool. See [§3.8 in `clojure-remaining.md`](./clojure-remaining.md#38-fully-parked-go-cps-transformed) — it's a research project, indefinitely deferred.
 
 Clojure's CSP-style concurrency library. Not in core but ships with Clojure projects almost universally.
 
@@ -468,10 +498,7 @@ A channel can apply a transducer to values as they flow. The pipeline steps exec
 - Composes beautifully with transducers.
 - Solves the "what if I want millions of workers" problem on a JVM with thousands of OS threads.
 
-**Jerboa gap**: In progress per user note. Chez has threads and mutexes; the hard part is the `go` macro's state machine transformation (CPS transform). Possible approaches:
-1. OS-thread-per-channel-worker (simpler, doesn't scale to millions).
-2. Delimited continuations (Chez has them via `call/1cc`).
-3. A full CPS transformation macro like Clojure's.
+**Remaining gap**: Parked `go`. Jerboa's current `go` forks an OS thread; each one costs real stack and scheduling overhead. Clojure's trick is a compile-time CPS transform on the `go` body that turns channel ops into state transitions, so the block's "pending state" is a tiny closure in a scheduler's run queue. That's a research-scale macro project (pattern-match over every Scheme special form, rewrite into CPS, keep source locations). Deferred.
 
 ---
 
@@ -514,7 +541,7 @@ Also: `extend-type`, `reify` (anonymous implementation of a protocol), `satisfie
 
 Protocol dispatch is extremely fast — compiles to a type-keyed cache that becomes direct dispatch after warmup. Near-virtual-call speed.
 
-**Jerboa has**: `defmethod` on structs via `(defmethod (area (self circle)) ...)`. This is single-inheritance method dispatch tied to a struct. Clojure protocols are independent of type hierarchy and can be retrofitted onto any existing type. Jerboa's method system is closer to Gerbil/CLOS without the extensibility story.
+**Jerboa status**: **[landed]** — `(std protocol)`. Exports `defprotocol`, `extend-type`, `extend-protocol`, `reify`, `satisfies?`. Method dispatch uses a type-keyed cache that becomes near-direct after warmup. Protocols can be extended to any type — records, built-ins, custom types — from outside their definition site, solving the expression problem. Jerboa's older struct-bound `defmethod` is still there for single-dispatch on first-arg type; protocols are the preferred path for new code.
 
 ---
 
@@ -554,7 +581,7 @@ True multiple dispatch (CLOS-style).
 
 Separates "how do I choose which code runs" from "what code runs". Can model taxonomies that cross-cut your type system. Overkill for many things (hence protocols are preferred for type-based dispatch) but invaluable when you need real multi-argument dispatch or value-based dispatch.
 
-**Jerboa gap**: No equivalent. `defmethod` is protocol-style (first-arg struct type). Building multimethods = a dispatch table keyed by the result of a user function, plus an `isa?` relation.
+**Jerboa status**: **[landed]** — `(std multi)`. Exports `defmulti`, `defmethod` (multimethod arity), `remove-method`, `prefer-method`, `methods`, `get-method`, `derive`, `underive`, `isa?`, `parents`, `ancestors`, `descendants`, `make-hierarchy`. Full taxonomy support via user-defined hierarchies, `:default` fallback, and prefer-method for ambiguity resolution. Vector dispatch works for true multi-argument dispatch: `(defmulti collide (fn [a b] [(:type a) (:type b)]))`.
 
 ---
 
@@ -596,7 +623,12 @@ Anonymous implementation:
 
 Creates an unnamed instance implementing those protocols/interfaces. Like an ad-hoc object.
 
-**Jerboa has**: `defrecord` which gives pretty-print and `->alist`. Good, but not protocol-implementing and not the same "record is a map" semantics. Jerboa `defstruct` is more primitive.
+**Jerboa status**: **[landed]**. Two pieces came together:
+
+- **Protocol-implementing records** via `(std protocol)` + `extend-type` or `extend-protocol`. Any `defstruct` or `defrecord` type can satisfy protocols from outside.
+- **Record-as-map** via `(std clojure)`. `defstruct` and `define-record-type` instances now answer to the full polymorphic collection API: `get`, `contains?`, `count`, `empty?`, `keys`, `vals`. Keys coerce symbol/string/keyword. Inherited fields are included in declaration order. `get-in` walks into records nested inside pmaps and vice versa.
+
+The one intentional non-match: `assoc` / `dissoc` on a record **escapes to a persistent-map** instead of returning a new record of the same type. Chez's sealed-record model doesn't expose a generic rebuild path, and the pmap escape is uniform. Users who need to preserve the record type on update should use the record's own field setter or allocate a fresh record via the constructor. `reify` is provided by `(std protocol)` for ad-hoc anonymous implementations. See [`clojure-records-as-maps` in the cookbook](../README.md) for the full pattern.
 
 ---
 
@@ -641,9 +673,14 @@ Possibly the feature Clojure programmers miss most in other languages. Destructu
 
 Keyword-argument style falls out of rest + map destructuring.
 
-**Jerboa has**: `match` provides strong pattern matching, and `using` gives dot-access to struct fields. But you can't just write `(def (f [x y z]) ...)` and have it destructure a list argument in the parameter position across the language. Destructuring in `let` uses `let-values`/manual `car`/`cdr`. No map destructuring with `:keys` style. Jerboa has `let-alist` which is close.
+**Jerboa status**: **[partial]**. `match` provides strong pattern matching, and `using` gives dot-access to struct fields. `let-alist` handles alist-key destructuring. What's missing:
+
+- `(def (f [x y z]) ...)` — destructure a list argument in the parameter position
+- `(def (f {:keys [name age]}) ...)` — map destructuring with `:keys` style in function params or `let`
+- `:as` for "bind the whole plus the pieces"
+- `:or` for defaults on missing keys
 
-A destructuring `def`/`let` macro in the prelude would be very high-value.
+This is probably the **single biggest daily-ergonomics gap** for Clojure migrants. A destructuring `def`/`let` macro that desugars to the existing `match` machinery would cover most of it. Tier 1 in the "still worth implementing" list.
 
 ---
 
@@ -679,7 +716,9 @@ Every Clojure value of a "reference type" (symbols, vars, collections, functions
 
 Uses metadata heavily: `(doc f)`, `(source f)`, `(dir ns)` — all pulled from var metadata.
 
-**Jerboa gap**: Chez doesn't have a unified metadata concept. You can wrap things but it's not systematic. Big value for introspection, documentation, and macro systems.
+**Jerboa status**: **[landed]** — `(std misc meta)`. Exports `with-meta`, `meta`, `vary-meta`, `meta-wrapped?`, `strip-meta`. Uses a wrapper-record approach (rather than modifying every record type to add a metadata slot), so only values you actually call `with-meta` on pay any allocation. `with-meta` replaces rather than nests — `strip-meta` is single-step. `=?` in `(std clojure)` strips meta on both sides, so metadata doesn't affect equality, matching Clojure's contract.
+
+Remaining gap: the shorthand reader syntax `^:private x` / `^String x` / `^{:doc "..."} x` has no equivalent — you write `(with-meta x '((private . #t)))` in long form. Deferred along with the rest of §4.9 reader work; see [`docs/clojure-reader.md`](./clojure-reader.md).
 
 ---
 
@@ -712,7 +751,13 @@ Also thread-aware: `bound-fn`, `bound-fn*` capture current dynamic bindings so y
 
 Inside a binding thread, dynamic vars can be `set!` to a new value for the rest of the thread's execution. Lets you update state that started as a dynamic default.
 
-**Jerboa gap**: Chez has `fluid-let` and parameters (`make-parameter`, `parameterize`) which are similar. Jerboa's prelude doesn't surface these clearly. A `(def ^:dynamic *foo* ...)` + `(binding ...)` sugar would be natural.
+**Jerboa status**: **[partial]**. Chez has `fluid-let`, `make-parameter`, and `parameterize` — the underlying mechanism exists and is powerful. What's missing is the Clojure-friendly syntactic layer:
+
+- `(def-dynamic *foo* default)` — sugar over `(define *foo* (make-parameter default))`
+- `(binding [*foo* new-val *bar* other] body)` — sugar over `(parameterize ([*foo* new-val] [*bar* other]) body)`
+- A convention that `*earmuffed*` names are dynamic and fair game to `binding`
+
+These are three small macros. Tier 1 in the roadmap below.
 
 ---
 
@@ -780,9 +825,9 @@ Every predicate in a spec can have a generator. With `s/fdef`, `clojure.spec.tes
 - **Documentation** — specs are the truth about what shape data takes.
 - **Generative testing** without writing generators.
 
-**Jerboa has**: `list-of?`, `maybe`, `:` for checked cast, `assert!`, but no composable spec system, no function contracts, no generator integration.
+**Jerboa status**: **[non-goal]** for full spec; **[open]** for a scaled-down schema library. Today Jerboa has `list-of?`, `maybe`, `:` for checked cast, `assert!`, but no composable spec system, no function contracts, no generator integration.
 
-This is a large feature. A scaled-down "malli" style (data-driven schema) is the common alternative in Clojure-land today; simpler to port.
+Full `clojure.spec` is a large feature and tied to assumptions about the Clojure runtime. A scaled-down **malli**-style data-driven schema system is the pragmatic alternative in Clojure-land today and far simpler to port — schemas are just nested data structures with a validation/conform/explain API. Recommended if anyone needs it; not on the current roadmap.
 
 ---
 
@@ -824,7 +869,7 @@ Clojure namespaces are first-class runtime objects, not just compile-time file o
 
 Reloads a namespace's file and re-interns its vars. Combined with REPL-driven development, this is the core of the Clojure workflow.
 
-**Jerboa has**: Chez-style module imports with `(import (std ...))`. Less introspection, no hot reload primitives in user code as far as I've seen. `:reload` style dev loop is missing.
+**Jerboa status**: **[partial]**. Chez-style module imports with `(import (std ...))` work, and the MCP tooling (`jerboa_module_exports`, `jerboa_module_catalog`, `jerboa_find_definition`) provides substantial introspection. What's missing is the **hot reload** primitive — `(require 'ns :reload)` without restarting the process. Chez doesn't expose this cleanly. Tier 3 in the roadmap.
 
 ---
 
@@ -861,7 +906,7 @@ You can register your own:
 
 `print-method` dispatch lets records, custom types, etc., round-trip through EDN.
 
-**Jerboa has**: JSON, CSV, YAML support. No EDN-equivalent native "Scheme data serialization" format with tag extensions. S-expressions via `read`/`write` come close, but there's no registered tag extension hook and no safety partition.
+**Jerboa status**: **[open]**. JSON, CSV, YAML supported. No EDN-equivalent native Scheme-data serialization with tag extensions. S-expressions via `read`/`write` come close, but there's no registered tag extension hook and no sandboxed-read/unsafe-read partition. Tier 2 — medium effort, self-contained library.
 
 ---
 
@@ -881,7 +926,7 @@ For code that runs on multiple platforms (Clojure, ClojureScript, ClojureCLR, ba
 
 Platform-specific branches baked into the reader. Not #ifdef — actual platform selection at read time.
 
-**Jerboa gap**: Not currently relevant since Jerboa is one target, but reader conditionals become valuable when you have Jerboa-vs-Chez divergences or want to share code with Gerbil.
+**Jerboa status**: **[deferred]**. Not currently relevant since Jerboa is one target. Reader conditionals become valuable if/when Jerboa adds a second target (wasm, for example) or wants to share code with stock Chez or Gerbil. Revisit then.
 
 ---
 
@@ -937,7 +982,9 @@ Used heavily by spec, clojure.xml, datascript, and API design. Lets you have `:u
 
 Keywords are interned; `(identical? :foo :foo)` is always true. Same for symbols.
 
-**Jerboa gap**: Jerboa has symbols but no `keyword` distinct type. `name:` reader syntax creates `#:name` keywords — it's there, but less pervasive in API design. Making keywords callable as functions-of-maps in Jerboa would be high impact (requires an applicable-struct system or a wrapper).
+**Jerboa status**: **[partial]**. Jerboa has a distinct `keyword` type and `name:` reader syntax that creates them, plus `keyword?`, `string->keyword`, `keyword->string` helpers. `(std clojure)`'s `get` and friends accept symbol, string, and keyword keys on records and pmaps interchangeably, so the pragmatic "keyword as API key" use case works today.
+
+What's missing is **keywords callable as functions of maps** — `(:name m)` as shorthand for `(get m :name)`. That requires an applicable-struct system or a reader rewrite (and collides with Jerboa's `:std/sort` module-path syntax). Low priority: `(get m 'name)` reads nearly as cleanly. Deferred.
 
 ---
 
@@ -995,7 +1042,7 @@ Not the side-effecting `for` of JS — list comprehensions with filters and lets
   (println x))
 ```
 
-**Jerboa has**: `for/collect` which supports multiple bindings in `for`, and `#:when` style guards exist in Racket's `for`. Jerboa's `for` supports `(#:when cond)` — check the implementation. If not, this is a small but high-value addition: `:let`, `:while`, `:when` clauses in `for/collect`.
+**Jerboa status**: **[partial]**. `for/collect` and `for/fold` support multiple bindings (Cartesian product nesting). Clause extensions (`:let`, `:while`, `:when` style) aren't fully standardized — worth verifying what's implemented and adding anything missing. Small user-facing win; Tier 3.
 
 ---
 
@@ -1040,7 +1087,7 @@ Set-once synchronization:
 
 Used for rendezvous between threads, or anywhere you need "some thread will eventually produce this value."
 
-**Jerboa has**: `try-result`, async patterns in `(std async)`. Delay is partially there via Chez's `delay`/`force` — but future and promise in the Clojure sense need the thread pool + structured result. `(std concur)` has the building blocks.
+**Jerboa status**: **[partial]**. `try-result`, async patterns in `(std async)`, and CSP `go` blocks cover most use cases. Chez's `delay`/`force` provide the lazy-value part directly. What's missing is the named Clojure surface: `delay` + `realized?`, `future` + `deref` + `future-cancel`, `promise` + `deliver`. These are thin wrappers over the existing primitives — Tier 3 in the roadmap.
 
 ---
 
@@ -1058,7 +1105,7 @@ Small built-ins that matter:
 - `(iterate f x)` — lazy infinite `[x (f x) (f (f x)) ...]`.
 - `(repeatedly n f)` — calls f n times, lazily.
 
-**Jerboa has**: `compose`, `comp`, `partial`, `complement`, `identity`, `constantly`, `curry`, `flip`, `conjoin`, `disjoin`, `juxt`, `cut`. Very good coverage. Missing `memoize`, `fnil`, `iterate`, `every-pred`, `some-fn`, `repeatedly`. Easy to add.
+**Jerboa status**: **[partial]**. `compose`/`comp`, `partial`, `complement`, `negate`, `identity`, `constantly`, `curry`, `flip`, `conjoin`/`disjoin` (Clojure's `every-pred`/`some-fn` under different names), `juxt`, `cut` are all in the prelude. Still missing: **`memoize`**, lazy **`iterate`** (Clojure's `(iterate f x)` = `[x (f x) (f (f x)) ...]`), **`repeatedly`**, **`fnil`**, **`trampoline`** (only strictly needed for mutual recursion across value-returning branches, since Chez has proper tail calls). These are all small, one-day adds. Tier 1 in the roadmap.
 
 ---
 
@@ -1089,7 +1136,7 @@ Clojure's answer to "exceptions should carry data, not just strings":
 
 Lets you catch by data-pattern rather than by class hierarchy, and serialize exceptions through channels/queues.
 
-**Jerboa has**: `try/catch/finally` with pattern-based catches and condition objects. `(std errors)` has its own structured errors. Close in spirit but not the standardized "ex-info + ex-data" convention that clojure-spec, pedestal, etc., all build on.
+**Jerboa status**: **[open]**. `try/catch/finally` with pattern-based catches and condition objects exist. `(std errors)` has its own structured errors. Close in spirit but not the standardized `ex-info`/`ex-data` surface that clojure-spec, pedestal, and porters expect. This is a ~10-line shim on top of Jerboa's condition system — Tier 1 in the roadmap.
 
 ---
 
@@ -1139,7 +1186,7 @@ Unification, relations, constraints, goals. Used for:
 
 Also `clojure.core.logic.pldb` — Prolog-like deductive database.
 
-**Jerboa gap**: No logic programming. A Jerboa port of a miniKanren flavor is a self-contained library — not deeply integrated with core, so it's approachable.
+**Jerboa status**: **[open]** (low priority). No logic programming. A Jerboa port of a miniKanren flavor is a self-contained library — not deeply integrated with core, so it's approachable. Off the Clojure-compat critical path; valuable for anyone doing logic programming specifically. Tier 4.
 
 ---
 
@@ -1162,7 +1209,7 @@ Essential for:
 - HTML/XML navigation (see `clojure.data.zip`)
 - Functional editors
 
-**Jerboa gap**: No zipper library. Straightforward port; not integrated with any core feature.
+**Jerboa status**: **[open]**. No zipper library. Straightforward port of `clojure.zip`, ~200 lines, not integrated with any core feature. Tier 2.
 
 ---
 
@@ -1183,7 +1230,7 @@ Defines **navigators** as composable objects. Navigators include `ALL`, `MAP-VAL
 
 `update-in`/`assoc-in` scale to the depth you're at; Specter scales to arbitrary *shapes* of navigation.
 
-**Jerboa gap**: No equivalent. Like zippers, a self-contained library that would pair naturally with persistent collections.
+**Jerboa status**: **[open]**. No equivalent. Like zippers, a self-contained library that would pair naturally with persistent collections. Tier 2.
 
 ---
 
@@ -1204,7 +1251,7 @@ Added in Clojure 1.10. The idea: **any opaque value can be turned into inspectab
 
 Used by tooling like REBL and Reveal to build **data inspectors**: click into a database connection, see a map; click a table, see rows; click a row, see cells. Any type can implement `Datafiable` to expose itself.
 
-**Jerboa gap**: No unified datafy/nav protocol. Big value for REPL tooling and debugging.
+**Jerboa status**: **[open]**. No unified datafy/nav protocol. Big value for REPL tooling and debugging. Now more tractable since `(std protocol)` is in place — datafy/nav is naturally expressed as two protocols. Tier 2.
 
 ---
 
@@ -1230,7 +1277,7 @@ Used by tooling like REBL and Reveal to build **data inspectors**: click into a 
 
 Generic tree rewriting that works on arbitrary nested Clojure data. One of those "I use it once a month but it's the right tool" libraries.
 
-**Jerboa gap**: No walker. Easy to build on top of a recursive structure visitor.
+**Jerboa status**: **[open]**. No walker. Easy to build on top of a recursive structure visitor — ~100 lines total including `postwalk`/`prewalk`/`walk`/`keywordize-keys`/`stringify-keys`/`macroexpand-all`. Tier 1 in the roadmap.
 
 ---
 
@@ -1257,7 +1304,7 @@ Plus relational operators:
 
 Small relational algebra over sets of maps. Rarely used in production but beautifully minimal.
 
-**Jerboa gap**: No set type or set operations in the prelude.
+**Jerboa status**: **[landed]** for the core operations. `(std clojure)` and `(std pset)` provide `hash-set`, `persistent-set`, `union`, `intersection`, `difference`, `subset?`, `superset?`, `disj`, `contains?`, `conj`. The **relational** operators (`project`, `select`, `join`, `rename`, `index`) from `clojure.set` are still open — they're a small self-contained library that would compose naturally on top of `(std pset)` + pmap.
 
 ---
 
@@ -1283,7 +1330,7 @@ Integrates with `clojure.spec`:
 
 Clojure's property-based testing culture is notable — many libraries ship `test.check` suites.
 
-**Jerboa gap**: No generative testing framework. Massive win for testing serialization, round-tripping, parsers, algorithms.
+**Jerboa status**: **[open]**. No generative testing framework. Would be a major quality-of-life win for testing serialization, round-tripping, parsers, algorithms. Generators + shrinking can be built as a self-contained library; QuickCheck ports are well-documented so the API surface is known. Tier 2.
 
 ---
 
@@ -1309,7 +1356,7 @@ Stuart Sierra's `component`, `integrant`, and `mount` — patterns for managing 
 
 Solves the "how do I wire up 15 stateful services with dependencies and restart them cleanly at the REPL" problem. Makes hot-reload of business code possible without losing connections to the world.
 
-**Jerboa gap**: No lifecycle framework. Low-urgency for small apps but important for long-running services. Could build on top of defrecord + a dependency graph.
+**Jerboa status**: **[open]**. No lifecycle framework. Low-urgency for small apps but important for long-running services. Could build on top of `defrecord` + `(std protocol)` (for `Lifecycle` start/stop) + a dependency graph. Now easier to implement since protocols landed. Tier 3.
 
 ---
 
@@ -1327,7 +1374,7 @@ Not a feature per se but an ecosystem. Clojure's REPL story:
 
 The whole stack rewards "keep the system running, shape it from inside."
 
-**Jerboa has**: `jerboa_repl_session`, `jerboa_eval`, and MCP-based tooling that's actually quite strong here. The gap is mostly editor integration and the "send form from editor to live REPL, see it evaluate" experience. Jerboa + an nREPL-style protocol + LSP tooling could close this.
+**Jerboa status**: **[partial]**. `jerboa_repl_session`, `jerboa_eval`, and the MCP tool surface are actually quite strong for "evaluate this form in a live runtime and see the result" — that's most of the non-visual nREPL experience, delivered as tool calls to the agent instead of messages to an editor. The gap is the **editor-side integration**: the "hit C-x C-e on a form in your source buffer, see the result inline" experience that CIDER/Calva/Conjure deliver. Closing it requires either a proper nREPL-compatible server (so existing Clojure editor plugins work) or native LSP extensions for Jerboa-aware editors. Either is a separate project from language features. Tier 4 in the roadmap.
 
 ---
 
@@ -1384,47 +1431,124 @@ Forward declarations so mutually recursive top-level defs compile.
 ### `pr` vs `print`
 Clojure distinguishes `print` (human-readable, no escapes) from `pr` (EDN-readable round-trippable output). `prn` = `pr` + newline. `println` = `print` + newline. Tiny but constant aid for REPL debugging.
 
+### Jerboa status roll-up for this section
+
+**Landed** in `(jerboa prelude)` or dedicated modules:
+- Threading: `->`, `->>`, `some->`, `cond->`, `as->` (all present); also `->?` for ok/err result threading
+- Collection helpers: `get-in` / `assoc-in` / `update-in` via `(std misc nested)`; `group-by`, `frequencies`, `partition`, `juxt`, `zip`, `into`, `merge`, `select-keys`, `update` (via `(std clojure)` and the prelude)
+- Conditionals: `when`, `when-not`, `when-let`, `if-let`, `if-not`, `awhen`, `aif`, full `case` (via Chez)
+- Arithmetic: `quot`, `rem`, `mod`, `min`, `max`, `bit-*` ops (all via Chez)
+- Set/map construction: `hash-map`, `hash-set`, `sorted-set`, variadic constructors from `(std clojure)` and `(std sorted-set)`
+- Predicate combinators `conjoin`/`disjoin` (same shape as Clojure's `every-pred`/`some-fn`), `complement`, `negate`
+- `declare` — Chez `define` forward refs work naturally; no separate macro needed
+- `pr`/`pr-str` vs `print`/`display` — Chez `write` vs `display` is the structural analogue
+
+**Open** (worth adding):
+- `doto` macro — threads side-effecting calls on one object. Trivial macro. **Tier 1**.
+- Anonymous `#(...)` reader shorthand — requires reader modification (same class of work as [`clojure-reader.md`](./clojure-reader.md)); Jerboa uses `(lambda (x) ...)` / `(cut + <> 1)` instead. **Deferred.**
+- `condp` — single-predicate dispatch form. Small macro, nice-to-have. **Tier 3**.
+- `merge-with`, `zipmap`, `reduce-kv` — the last few map-convenience functions not yet in `(std clojure)`. (`merge` and `select-keys` already landed.) Small self-contained additions. **Tier 1**.
+- `min-key` / `max-key` — select the element of a collection that minimizes/maximizes a key function: `(max-key :age users)`. Trivial ~5-line definitions. **Tier 1**.
+- `fnil` — wraps a function so `nil`/`#f` arguments get replaced with defaults before calling. Trivial closure. **Tier 1**.
+
 ---
 
-## Summary: Where to Focus
-
-If I had to rank the features by "biggest game-changer you can practically add to Jerboa":
-
-| Tier | Feature | Difficulty | Payoff |
-|------|---------|-----------|--------|
-| 1 | Persistent data structures + transients | Hard | Foundational |
-| 1 | Transducers | Medium | Huge — unlocks reusable pipelines |
-| 1 | core.async channels + go | Hard | Structured concurrency |
-| 1 | Protocols | Medium | Extensibility + polymorphism |
-| 1 | Map destructuring everywhere | Easy | Daily ergonomics |
-| 2 | Atoms / agents / refs / STM | Medium-Hard | Concurrent programming story |
-| 2 | Dynamic vars + binding | Easy | Context propagation |
-| 2 | Spec (or malli-style schemas) | Medium | Validation + testing |
-| 2 | Lazy sequences in prelude | Easy-Medium | Infinite data model |
-| 2 | Multimethods | Easy | Open dispatch |
-| 2 | Metadata on vars/collections | Medium | Introspection + tooling |
-| 3 | core.match enhancements | Easy | Already strong |
-| 3 | Zippers, clojure.walk, clojure.set | Easy | Library-level, self-contained |
-| 3 | Property testing | Medium | Quality story |
-| 3 | Datafy/Nav + REBL-style tooling | Medium | Dev experience |
-| 3 | ex-info style structured errors | Easy | Error ergonomics |
-| 3 | Specter | Medium | Deep update ergonomics |
-| 4 | core.logic | Medium | Niche but fun |
-| 4 | Component lifecycle | Medium | Long-running systems |
-| 4 | nREPL-style editor integration | Hard | Ecosystem, not language |
-
-The things that Chez/Jerboa already does as well or better than Clojure:
-- **Proper tail calls** (no `loop`/`recur` needed)
-- **Numeric tower** (Chez rationals + bignums are first-class)
-- **Pattern matching** (Jerboa's `match` is strong)
-- **Macro hygiene** (Chez's `syntax-case` is arguably more powerful than Clojure's macros)
-- **Continuations** (Chez has `call/cc`; Clojure does not)
-- **Compilation speed and startup time** (Chez AOT vs JVM warmup)
-
-The things that are cultural/ecosystem rather than language:
-- REPL-driven workflow tooling
+## Summary: Where Things Stand (2026-04-11)
+
+### What's landed
+
+Most of the features originally ranked "Tier 1 / Tier 2" are now in place. The Clojure-compat campaign tracked in [`clojure-remaining.md`](./clojure-remaining.md) — plus earlier work on the persistent data structures and CSP channels — has shipped:
+
+| Feature | Module | Notes |
+|---------|--------|-------|
+| Persistent map / vector / set | `(std pmap)` `(std pvec)` `(std pset)` | HAMT where applicable, structural `=?` and hash |
+| Persistent queue | `(std pqueue)` | O(1) amortized FIFO |
+| Sorted set | `(std sorted-set)` | Range queries, ordered traversal |
+| Transients | `imap-transient`, `pvec-transient`, `pset-persistent!` | Bulk-build API via `(std clojure)` `transient`/`persistent!`/`conj!`/`assoc!` |
+| Transducers | `(std transducer)` | `map`/`filter`/`take`/`dedupe`/etc., composed with `comp`, applied with `transduce`/`into`, integrated with CSP channels via `(chan n xform)` |
+| core.async CSP | `(std csp)` | Channels, `go`, `alts!`, buffers, `mult`/`tap`, `pub`/`sub`, `mix`, `pipe`, `pipeline`, `put!`/`take!`, `timeout` with timer wheel, transducer channels |
+| Atoms + watches + volatiles | `(std misc atom)` | `atom`, `swap!`, `reset!`, `compare-and-set!`, `add-watch!`, `remove-watch!`, `volatile!`/`vreset!`/`vswap!` |
+| Agents | `(std agent)` | `send`/`send-off`/`await`/`agent-error`/`restart-agent`, `:fail` error mode |
+| Protocols | `(std protocol)` | `defprotocol`, `extend-type`, `extend-protocol`, `reify`, `satisfies?` |
+| Multimethods | `(std multi)` | `defmulti`, `defmethod`, `prefer-method`, `derive`, `isa?` hierarchies |
+| Metadata | `(std misc meta)` | `with-meta`, `meta`, `vary-meta`, `strip-meta`; `=?` strips before comparing |
+| Record-as-map | `(std clojure)` + `(std misc nested)` | Records answer `get`/`keys`/`vals`/`count`/`contains?`/`empty?`; `assoc`/`dissoc` escape to pmap; `get-in` walks records |
+| Set operations | `(std pset)` + `(std clojure)` | `union`, `intersection`, `difference`, `subset?`, `superset?` |
+| `get-in`/`assoc-in`/`update-in` | `(std misc nested)` | Polymorphic over pmap, chash, hash-table, vector, pair (alist), and records |
+| Pattern matching | `(jerboa prelude)` | `match` with nested, guards, predicates, or-patterns, view patterns |
+
+### What Chez/Jerboa does as well or better than Clojure
+
+- **Proper tail calls** — Chez guarantees TCO, so no `loop`/`recur` ceremony. Natural recursion is fine; `(loop ... (recur ...))` is only a familiarity nicety for migrants.
+- **Numeric tower** — Chez has exact rationals, arbitrary-precision integers, bignums, and complex numbers built in. The Clojure `BigInt`/`BigDecimal`/`Ratio` distinction is flatter and more pervasive in Chez.
+- **Pattern matching** — Jerboa's `match` is already excellent; this was one area of parity from the start.
+- **Macro hygiene** — Chez's `syntax-case` is arguably more powerful than Clojure's macros. Jerboa inherits this.
+- **Continuations** — Chez has `call/cc`; Clojure doesn't.
+- **Compilation speed and startup time** — Chez AOT vs JVM warmup. Jerboa scripts start in ms, not seconds.
+
+### Cultural/ecosystem gaps (not language features)
+
+- REPL-driven workflow tooling (partially addressed via MCP tools, `jerboa_repl_session`, `jerboa_eval`)
 - Dependency management
 - Documentation conventions
 - Community-maintained idiom libraries
 
+---
+
+## Still Worth Implementing (as of 2026-04-11)
+
+What's left, ranked by value-per-effort. Each entry links to the section above for the full discussion.
+
+### Tier 1 — Biggest daily-ergonomics wins, low-to-medium effort
+
+| Feature | Section | Effort | Why it's worth doing |
+|---------|---------|--------|----------------------|
+| **Map destructuring with `:keys` in `let`/`def`** | [§14](#14-destructuring-everywhere) | Easy–Medium | Single biggest "I miss this every day" gap for Clojure migrants. `(def (f {:keys [name age]}) ...)` in function params. A macro on top of the existing `match` machinery. |
+| **`ex-info` / `ex-data` structured exceptions** | [§27](#27-exception-design-ex-info) | Easy | Ten-line shim over Jerboa's condition system. Makes every library catch-by-data-shape instead of catch-by-class. |
+| **`memoize` / `iterate` / `repeatedly`** | [§26](#26-memoize-trampoline-and-friends) | Easy | The three missing functional combinators. Couple dozen lines total. |
+| **`clojure.walk` (`postwalk` / `prewalk` / `keywordize-keys`)** | [§33](#33-clojurewalk) | Easy | Generic tree rewriting. Self-contained library, ~100 lines. |
+| **`doto` macro** | [§38](#38-miscellaneous-small-things-that-add-up) | Trivial | Threads an object through side-effecting calls. One-macro add. |
+| **Dynamic vars + `binding` sugar** | [§16](#16-dynamic-vars-and-thread-local-binding) | Easy | Wrap `make-parameter`/`parameterize` in `def-dynamic` + `binding` macros so Clojure porters don't have to know about Chez parameters. |
+| **Map-convenience stragglers** | [§38](#38-miscellaneous-small-things-that-add-up) | Easy | `merge-with`, `zipmap`, `reduce-kv`, `min-key`/`max-key`. The handful of map-convenience functions not yet exported from `(std clojure)` (merge and select-keys already landed). Each is 5–15 lines. |
+
+### Tier 2 — High value, medium effort, self-contained
+
+| Feature | Section | Effort | Why it's worth doing |
+|---------|---------|--------|----------------------|
+| **Lazy sequences in the prelude** | [§5](#5-lazy-sequences) | Medium | `lazy-seq`, `cycle`, `repeat`, infinite `iterate`, `take-while`, `drop-while`. Chez has the primitives; expose them as a first-class idiom. |
+| **Zippers (`clojure.zip`)** | [§30](#30-zippers) | Medium | Functional tree editing. Classic, well-specified, ~200 lines. Pairs naturally with `match` for AST work. |
+| **Specter-style path navigation** | [§31](#31-specter) | Medium | Path-based deep navigation over arbitrary nested data. Scales `update-in` to arbitrary *shapes*. |
+| **Reducers / parallel fold** | [§7](#7-reducers) | Medium | Auto-parallel `(r/fold + (r/map inc big-vec))`. Needs a divide-and-conquer split protocol on pvec and pmap. |
+| **EDN format with tagged literals** | [§19](#19-edn-and-tagged-literals) | Medium | Safe Scheme-data serialization with an extension hook. Fill-in for JSON/EDN interop. |
+| **Datafy / Nav** | [§32](#32-datafy--nav) | Medium | Protocol for exposing opaque values as inspectable data. Big dev-experience win once REPL tooling matures. |
+| **Property-based testing (test.check style)** | [§35](#35-property-based-testing-testcheck) | Medium | Generators + shrinking. Clojure's `clojure.test.check` is the canonical reference. |
+
+### Tier 3 — Significant effort, significant payoff
+
+| Feature | Section | Effort | Why it's (maybe) worth doing |
+|---------|---------|--------|------------------------------|
+| **STM refs (`ref` / `dosync` / `alter` / `commute`)** | [§9](#9-software-transactional-memory-stm) | Hard | The last big concurrency primitive Jerboa doesn't have. Well-specified design (version counters + read/write sets + commit protocol), just a real engineering project. A scaled-down variant that only coordinates 2–8 refs per transaction is much easier than a fully general one. |
+| **Component lifecycle framework** | [§36](#36-component-lifecycle-libraries) | Medium | Stuart Sierra's `component`, `integrant`, or `mount`. Solves "start 15 services in dependency order, restart cleanly at the REPL." Mostly a library on top of `defrecord` + a dependency graph. |
+| **`clojure.set` relational operators** | [§34](#34-set-operations) | Easy | `project`, `select`, `join`, `rename`, `index`. Small relational algebra over sets of maps. Self-contained. |
+| **Namespace hot reload** | [§18](#18-namespaces) | Medium | `(require 'ns :reload)` without restarting. Chez doesn't expose this cleanly, so it needs real wiring — but it's the linchpin of REPL-driven dev. |
+| **`for` comprehension `:let`/`:while`/`:when` clauses** | [§24](#24-for-comprehensions) | Easy | Jerboa's `for/collect` is already close; this is clause additions. Small user-facing win. |
+| **Delay / Future / Promise polish** | [§25](#25-delays-futures-and-promises) | Easy | Chez has the primitives; wrap them as `delay`/`force`/`realized?`, `future`/`deref`, `promise`/`deliver` for Clojure parity. |
+
+### Tier 4 — Niche, deferred, or non-goal
+
+| Feature | Section | Status | Reasoning |
+|---------|---------|--------|-----------|
+| **Clojure reader literals (`{}`/`#{}`/`[]`/`:kw`)** | [`clojure-reader.md`](./clojure-reader.md), [§4.9](./clojure-remaining.md#49-reader-literals-----v-kw) | Deferred (risky) | Requires opt-in file-local reader modes; permanent debuggability weirdness; most porters adapt to constructor forms in a day. Could be deferred forever. |
+| **Parked `go` via CPS transform** | [§10](#10-coreasync-csp-channels), §3.8 in `clojure-remaining.md` | Deferred | Research-scale macro project. Jerboa's OS-thread `go` is fine for thousands-of-coroutines use cases, just not millions. |
+| **Clojure Spec / full schema system** | [§17](#17-clojure-spec) | Non-goal | Too large to port faithfully. A scaled-down malli-style schema library is the recommended alternative for anyone who needs it. |
+| **core.logic (miniKanren)** | [§29](#29-corelogic-minikanren) | Open, low priority | A self-contained library port; valuable for anyone doing logic programming, but far from the Clojure-compat critical path. |
+| **Keywords as functions `(: k m)` on pmaps** | [§22](#22-keywordsymbol-semantics) | Deferred | Would require applicable-struct support. Instead use `(get m k)`, which is already polymorphic. |
+| **nREPL-style editor protocol** | [§37](#37-repl-driven-development-culture) | Partial | Jerboa's MCP tooling covers a lot of the same ground (`jerboa_eval`, `jerboa_repl_session`). A proper nREPL server would unlock CIDER/Calva-style editor integration but is a separate project. |
+| **Reader conditionals** | [§20](#20-reader-conditionals) | Deferred | Useful only when Jerboa has multiple targets; currently one target. Revisit if Jerboa-wasm or Gerbil-share becomes real. |
+| **`.clj` source loading** | — | Non-goal | Not porting the JVM compiler. |
+
+### Recommendation
+
+If I were picking the next pass after this campaign: **Tier 1 as a single batch**. Map destructuring, `ex-info`, `memoize`/`iterate`/`repeatedly`, `clojure.walk`, `doto`, and dynamic-var sugar together are maybe a few days of work and close most of the "I type this every hour and Jerboa doesn't have it" complaints from Clojure migrants. Tier 2 items become more attractive in isolation once Tier 1 is in place. Tier 3's STM is the only remaining "foundational" gap and deserves a real design round of its own.
+
 The language features above are what you'd port. The culture is built alongside, one idiomatic library at a time.