Clean up codebase: rename stdlib layer, strip porting residue, fix tooling

Rename src/jolt -> stdlib (the runtime-loaded layer; jolt-core stays the
seed-baked layer) and update the loader / emit-image / doc paths. Drop dead
code: the spike/ experiments, the duplicate clojuredocs-export.edn (json moves
to tools/), the Janet-era jolt.http binding, and the orphaned
persistent_vector.clj whose ns/path didn't even match.

Strip porting residue from comments and docstrings across host/chez, jolt-core,
stdlib, tests, and docs: internal issue ids, "Phase N" markers, and the "vs
Janet" historical exposition, leaving present-tense descriptions and the real
JVM-Clojure semantic contrasts. Same pass over the corpus suite labels. The seed
is unchanged (docstrings/comments aren't emitted), so the self-host fixpoint and
corpus are untouched.

Port tools/spec_coverage.py off the dead janet probe to bin/joltc and regenerate
coverage.md; drop the dead :host/janet rule from certify.clj and regenerate the
conformance profile. Add docs/host-interop.md (the JVM shims and how to register
your own host class from a library) and a writing-style note in CLAUDE.md.

Stabilize the four racy concurrency corpus cases (future-cancel and agent
send/send-off): give the future a sleeping body and the agent a slow action, so
cancel reliably catches an in-flight future and deref reliably reads the
pre-update snapshot. They certify deterministically now, so drop their :flaky
allowlist entries and the orphaned legend.
This commit is contained in:
Yogthos 2026-06-22 22:18:00 -04:00
parent c18f8087f0
commit 33eff7c7d8
112 changed files with 970 additions and 1621 deletions

View file

@ -77,6 +77,6 @@ per-context opt-in, exactly how the SCI bootstrap now loads
- Loading clj-ecosystem libraries via deps requires deciding their feature
set; the deps loader currently inherits the process default — a future
refinement is per-dependency feature configuration (filed with the deps
work, jolt-dw4).
work).
- `.cljc` authors targeting jolt can write `:jolt` branches and rely on
`:default` fallbacks.

View file

@ -1,6 +1,6 @@
# RFC 0005 — Structural collection-type inference
- **Status**: Implemented (jolt-5uj). Ray tracer 12.8s to 11.0s hint-free,
- **Status**: Implemented. Ray tracer 12.8s to 11.0s hint-free,
matching the explicit `^:struct` version; render checksum unchanged.
- **Champions**: jolt maintainers
- **Created**: 2026-06-13
@ -14,7 +14,7 @@ function its parameter and return types, recursively. A keyword lookup returns
the looked-up field's type, so nested access like `(:r (:direction ray))` is
typed end to end. This unifies the two facts the current inference tracks
inconsistently (a vector's element type, but not a map's field types), subsumes
the existing inference phases (jolt-99x Phases 0 to 3) as special cases, and
the existing inference passes as special cases, and
closes the remaining ray-tracer gap without a hint. The system is a
soft-typing-style inference: it never rejects a program, it assigns a concrete
type only when it can prove one, and it falls back to `:any` (and the existing
@ -22,7 +22,7 @@ runtime guard) everywhere else.
## Motivation
The inference added in jolt-99x specializes a collection access (drops the
The existing inference specializes a collection access (drops the
`:jolt/type` guard, emits `pv-count`, and so on) when it can prove the
collection's type. It works, it is sound, and it is fully dynamic-fallback
safe. But its type lattice grew ad hoc:
@ -96,7 +96,7 @@ are depth 2 to 3, well inside the cap.
Inference is a forward pass producing `[type node']` for each IR node (the
existing shape), threaded with a local type environment and the
inter-procedural state from Phase 1. The rules are uniform over the structural
inter-procedural state. The rules are uniform over the structural
type:
- **Literals.** `{:k v ...}` with constant scalar keys and struct-safe values
@ -115,9 +115,9 @@ type:
signature: core fns from a fixed signature table (below), user fns from the
inter-procedural fixpoint's inferred signature.
The Phase 1 inter-procedural fixpoint, recompile, escape gate, and closed-world
assumption (RFC to follow / jolt-767) are unchanged. They now propagate
structural types instead of flat tags.
The inter-procedural fixpoint, recompile, escape gate, and closed-world
assumption are unchanged. They now propagate structural types instead of flat
tags.
## Core function signatures
@ -266,8 +266,8 @@ plus a signature table.
tables and HOF handling).
4. The back end keeps reading the use-site type to specialize (guard drop for
`{:struct}`, `pv-count`/`pv-nth` for `{:vec}`), now uniformly.
5. Keep the Phase 1 fixpoint, recompile, escape gate, and triggering as is; they
propagate structural types.
5. Keep the inter-procedural fixpoint, recompile, escape gate, and triggering as
is; they propagate structural types.
The phases land incrementally behind the same optimization-mode gate, each
verified against conformance (three modes), the full test gate, and the
@ -298,5 +298,6 @@ ray-tracer benchmark, exactly as the current phases were.
param/return inference is enough for the collection-specialization goal;
full function types matter more for the type-checker (RFC 0006) and could be
deferred.
- **Closed-world boundary.** Inherited from Phase 1: param/return inference
assumes the compiled unit is the whole program. Documented there; unchanged.
- **Closed-world boundary.** Inherited from the inter-procedural pass:
param/return inference assumes the compiled unit is the whole program.
Documented there; unchanged.

View file

@ -2,10 +2,10 @@
- **Status**: Implemented. Core-fn error domains (arithmetic on non-numbers,
count/first/rest/next/seq/nth on non-seqable scalars), `JOLT_TYPE_CHECK=
off|warn|error`. Follow-ups landed: bounded scalar **unions** (jolt-pz5) so a
off|warn|error`. Follow-ups landed: bounded scalar **unions** so a
use is reported only when every member is in the error domain; **user-fn
error domains** behind `JOLT_TYPE_CHECK_USER` (jolt-zo1, closed-world);
precise **file:line:col** locations (jolt-fqy). The checker is now one
error domains** behind `JOLT_TYPE_CHECK_USER` (closed-world);
precise **file:line:col** locations. The checker is now one
inference walk (folded into `infer`), and is **on by default in direct-link
builds** — where it piggybacks on the specialization inference for ~free —
and opt-in (`JOLT_TYPE_CHECK`) in plain builds.
@ -203,22 +203,22 @@ smallest high-confidence table (arithmetic and seq/count/nth/first), and grow.
destroys trust. Mitigation: start tiny, test each entry against the runtime,
grow slowly. Open question: derive the table from the same machinery the
runtime uses, to avoid drift?
- **Unions.** *Resolved (jolt-pz5).* The lattice has a bounded scalar union
- **Unions.** *Resolved.* The lattice has a bounded scalar union
`{:union #{T...}}` (cap 4); differing if-branches form a union instead of
collapsing to `:any`, and a use is reported only when *every* member is in the
error domain. Unions are opaque to structural specialization, so codegen is
unchanged.
- **User-function signatures.** *Resolved (jolt-zo1), opt-in.* Behind
- **User-function signatures.** *Resolved, opt-in.* Behind
`JOLT_TYPE_CHECK_USER`: the checker re-checks a registered non-redefinable
user fn's body with one parameter bound to its concrete argument type; a
diagnostic the all-`:any` body did not have means that argument is provably
wrong. Monotonic, so still no false positives; closed-world, hence opt-in.
- **Negative/never types.** *Resolved (jolt-wwy).* Calling a provably
- **Negative/never types.** *Resolved.* Calling a provably
non-callable value (`:num`/`:str` — keywords/maps/vectors/sets are IFn) is
reported at the default level; wrong-arity to a registered single-fixed-arity
user fn is reported under the `JOLT_TYPE_CHECK_USER` opt-in. A union callee is
flagged only when every member is non-callable.
- **Position vs intent.** *Resolved (jolt-fqy).* The reader records each list
- **Position vs intent.** *Resolved.* The reader records each list
form's absolute offset (identity-keyed, so positions survive macroexpansion
exactly when the user's sub-form is spliced through); the analyzer stamps it
onto `:invoke` nodes, the checker carries it into each diagnostic, and the