Skip to content

Releases: cx-home/cx

CX v0.15.0

Choose a tag to compare

@eptx eptx released this 03 Aug 15:38

CX v0.15.0 — Release Notes

Date: 2026-08-03
Tag: v0.15.0

The toolchain release. The vendored V compiler moves from its 0.5.1-era
base to upstream V 0.5.2, carrying the cx fork's memory-management
patch series forward — plus two sharp fixes that the upgrade's own
validation battery surfaced. Deliberately thin and shipped fast: a
compiler upgrade is a foundation change worth isolating from feature work.

No breaking changes. cx source needed zero changes for the new
compiler.

Headlines

  • V 0.5.2 under the hood — the fork's 79-patch series rebased onto the
    upstream tag as 76 commits. In-window upstream wins: cgen
    sumtype/generic correctness fixes (the CX element tree is
    sumtype-heavy), -usecache repairs, mbedtls TLS-handshake hardening,
    and array micro-optimizations.
  • A collector-soundness find upstream can't see: two innocuous-looking
    upstream array changes — zeroing vacated delete slots, and letting
    empty arrays carry no buffer — each independently caused
    sweep-while-live use-after-frees under cx's conservative collector at
    high thread counts. Invisible under Boehm (upstream's only GC), caught
    by cx's masking-proof concurrency-soundness gate, and fixed as a
    fork-side conservative-retention contract that keeps all of
    upstream's performance work. The gate ladder (5 thread configurations
    on macOS, plus Linux-container parity) runs at zero catches and zero
    crashes.
  • Ingest regression found and erased — v0.14.0's demand-paged store
    load had quietly routed first-touch object reads through a
    scan-the-world cold path, collapsing embedded journal-bound ingest
    2881 → 91 events/s. An object-location index plus an MRU pack reader
    restore 2861 events/s — parity — with the lazy-load memory wins
    intact.
  • Authenticated event streams from CX[$http:sse-connect] now
    sends opts.headers, so a proof-bound SSE subscription (the identity
    model's required three-header handshake) finally works from a
    CX-native client.

Toolchain notes

  • The 0.5.2 builder's new C-error telemetry (auto-reports to the upstream
    tracker) is opt-in in the cx fork (V_C_ERROR_BUG_REPORT=1) — a
    fork must not phone home.
  • The vc bootstrap pin is regenerated for the new base and verified by a
    fresh-clone make; the concurrency-soundness gates are parameterized
    (VFORK_ROOT/VFORK_SRC/VFORK_V) so a candidate compiler tree is
    arbitrated before the submodule pin moves.
  • Upstream's closure-lifetime reclamation is enabled — it was the
    upgrade's top predicted risk and was exonerated by the gate once the
    real regressions were isolated.

Install

Download the release artifact for your platform and extract, or build
from source with make build. The hosted one-liner remains blocked on
GitHub Pages certificate issuance (#508).

Migration

None. v0.15.0 is additive over v0.14.0; the compiler upgrade is invisible
at the CX surface.

What's next

The CX partition (#516) — targeted, per-use-case consumables along
capability rings — is now slated as v0.16.0's headline, design-gated
behind its spec and the architecture review (#37).

CX v0.14.0

Choose a tag to compare

@eptx eptx released this 02 Aug 15:50

CX v0.14.0 — Release Notes

Date: 2026-08-02
Tag: v0.14.0

The eventing + endurance release. v0.13.0 made CX consumable; v0.14.0
makes a CX deployment survive its own success.

Two arcs dominate. cx fabric graduates from a design note to a served
platform tier: durable and transient event planes over XSP, with consumer
groups, failover, dead-letter policy, request–reply, backpressure, and a
NATS bridge — where a durable stream is a journal stream, so ordering and
verification come from the journal contract rather than a second
implementation. And the journal and store grow a lifecycle: rotation,
tiered retention with cold archive and chain anchors, and demand-paged
loading — so a long-lived deployment's cost tracks its working set
instead of its lifetime volume.

Between them sits a sustained performance campaign that moved remote
journal-bound ingest from ~16 events/s to ~660, and a fail-loud sweep
that closed a family of silent-wrong-answer defects in the evaluator.

No breaking changes.

Headlines

  • cx fabric, servedcx fabric-serve with durable + transient
    planes, consumer groups with sticky-exclusive assignment and liveness
    failover, DLQ + redelivery policy, request–reply, XSP §5 heartbeat /
    credit flow control / reconnect-resume, and a NATS subject bridge.
  • The journal has a lifecycle[rotate keep-n=N] seals every stream
    at its own boundary and moves the hot window to a fresh store; a
    segment index keeps sealed history walkable from the newest store
    alone. [retention …] policy sweeps it automatically with per-stream
    hot windows, cold archive, chain anchors retained whether a segment is
    archived or dropped
    , and a legal hold that suspends both.
  • The store pages on demand — opening an object-graph store populates
    only the refs layer; objects resolve on first touch through a
    self-verifying getter, so corruption still refuses loudly at first
    touch
    while resident memory tracks the working set. The whole-graph
    check becomes the explicit [$store:verify].
  • ~40× remote ingest — ~16 → ~660 events/s through pipelined appends,
    render caching, fold checkpoints, and finally moving the delivery pump's
    read+render off the sequencer lock (663/s measured at K=2000).
  • Per-principal read surfacesreadout($store, $t, $actor) receives
    the request's resolved principal, so a confidentiality boundary folds
    server-side instead of shipping a full read-model to every client.
  • Self-hosting all the way down — a fabric mount can ride a served
    cx-store:// store, with alias remoting (explicit presence, optional
    CAS) closing the last gap.

Language & stdlib

  • [?loop] with [break]/[continue], and [?do] — the
    condition-driven loop and evaluate-for-effect sequencing, with
    all-explicit exits: a branch that forgets its exit word is a diagnostic,
    never a silent wrong answer.
  • % as modulo, joining + - * /.
  • Per-thread PRNG streams and instantiable generators ([$random:new])
    [?worker] threads no longer race a process-global RNG.
  • CX-L007 flags aggregation over a simple field accessor, catching
    the count-composition trap mechanically.

Fail-loud hardening

A deliberate sweep against silent wrong answers, each closed at the root:

  • $first returned the whole collection for $filter results; err values
    vanished in unobserved [?let] bindings; absence in call position
    misdiagnosed as no callable; [?for] [where] calls never matched;
    [?element] as a call argument arrived as absence; [?async] never ran
    without [?await] despite the spec requiring eager spawn.
  • $cx:emit emitted unescaped quotes that broke re-parse; CXPath over an
    [err …] yielded zero matches, turning parse failures into empty
    results; a parsed MapNode was unnavigable.
  • Module-imported code now evaluates identically to program-context
    code
    — derived evaluation frames dropped their lexical position, so
    closures created inside imported defs resolved against the importing
    scope. One root cause behind three distinct reported symptoms.

Durability

  • Crash consistency: the journal store corrupted on unclean shutdown
    and then SIGBUS'd on reopen. Two-pass replay with a structural
    torn-tail discard; 0/40 corrupt across a kill-at-any-point harness.
  • Two writable in-process opens of one store root shared segment
    numbering; they now share the live handle or refuse loudly.

Toolchain & packaging

  • The public mirror builds from a clean clone again (V bootstrap and fork
    makefiles no longer float on remote HEADs).
  • The darwin artifact is self-contained — RE2 vendored and statically
    linked, dropping the Homebrew/abseil dylib chain.
  • WSL2 source builds work via the recursive-clone path.
  • Bindings: the retired :table[ opener purged from Go/Rust/Python; Rust
    arrow/parquet features compile; previously-unwired Python tests now
    run in the gate.

Install

Download the release artifact for your platform and extract, or build from
source with make build. The hosted https://cxhome.org/install one-liner
remains blocked on GitHub Pages certificate issuance (#508) and is not
advertised for this release.

Migration

None required — v0.14.0 is additive over v0.13.0. Two optional surfaces are
worth adopting deliberately:

  • Retention is opt-in. Without a [retention …] block a fabric mount
    keeps its full history exactly as before. Sizing guidance for the hot=
    window is in bench/xap/SIZING.md §1.
  • Store loading is now demand-paged by default. Per-object integrity is
    unchanged (every paged read self-verifies), but the exhaustive
    whole-graph reconstruction that used to run at every open is now the
    explicit [$store:verify]. Pass [opts eager="true"] to restore the
    inline check.

What's next

The CX partition (#516) — breaking CX into targeted, per-use-case
consumables along capability rings — is the next release's headline,
deliberately design-gated behind its spec and the architecture review.

CX v0.13.0

Choose a tag to compare

@eptx eptx released this 17 Jul 03:00

CX v0.13.0 — Release Notes

Date: 2026-07-16
Tag: v0.13.0

The platform + consumption release. The cx store becomes a production
platform component — a content-addressed multimodel engine under a
single-node service tier with authN/authZ, observability, and deploy
artifacts — and XAP features become a full distribution unit: sealed,
signed, published, discovered, verified, installed, and entitled. Around
that core, this release makes CX radically easier to consume in all four
modes: as a data format (a lossless conversion contract that finally
keeps its promise), as code (a CLI whose help, flags, and errors cannot
drift from the implementation), as a platform (the store + XAP guides,
verified live), and in operations (a real process-model story, a hosted
installer, and a public mirror that builds from a clean clone).

Two breaking changes (store scheme cutover and strictly-scalar attributes)
— see Migration.

Headlines

  • XAP feature distribution — the compose→package→publish→verify→install→
    entitle staircase ([$xap:compose], pkg-*, entitlement VCs,
    git-repo-as-registry), plus the deployment host: a XAP server is data
    plus adapters, zero bespoke server code.
  • cx store, production tiercx store-serve (CSRP + gRPC, static/
    JWT/DID/OIDC authN, RBAC, tenants, Prometheus/OTel, systemd/Docker
    artifacts), encryption-at-rest with KEK rotation, two-tier identity, and
    fifteen hardening waves over the serve plane.
  • The lossless contract, kept--lossless JSON and YAML now recover
    element documents byte-identically via the $tag envelope: structure,
    attributes, mixed-content order, metadata, and [table] payloads all
    survive. XML kept its exact lane; every lane now carries table images
    (cx:cols/cx:row, AST-JSON cols/rows, Markdown pipe tables,
    ast-bin v9 records).
  • A CLI that tells the truth — one registry drives dispatch and help
    (20+ verbs, uniform --help); unknown flags are hard errors instead of
    silent no-ops; cx select ships; cx FILE --data=INPUT binds $doc;
    cx demo demonstrates a working product.
  • Consumable out of the boxcurl -sSL https://cxhome.org/install | sh
    (SHA-256-verified), editors that work on first open (Neovim fallback +
    tree-sitter repaired, VS Code extension actually activates), a 20-section
    guide whose every example executes against the live binary under a gate,
    and a public mirror that builds and tests from a fresh
    git clone --recursive.

Changed (breaking)

  • Store scheme cutovercxpack:// / cxobj:// retired: file:// is
    the universal subtree model, document+<substrate>:// the document model,
    ?encoding= selects framing; contradictions with the on-disk marker are a
    hard CXER1120.
  • Attributes are strictly scalar (code.md §6.4.1 wins) — a non-scalar
    attr value raises CXER0100 with a child-element hint; validate.md's
    vocabulary moves to child elements ([enum v …], [schema …],
    [extends $Base]), old attr spellings fail loud with migration hints
    (CXER1603).
  • CXPath predicate sublanguage retired (from the 0.13 line's early
    waves; #110) — predicates are homoiconic prefix CX (//user[= $_@id 991]);
    cx fmt --migrate-predicates -w migrates fail-closed.

Fail-loud hardening

The release closes a long tail of silent-wrong-answer classes: unknown CLI
flags, empty-attr writes, unbound-$doc queries, out-of-range ascriptions
(including the 8-byte-hex i64 clamp), element-valued attributes, comment
placement moving hashes, [table[…]] heads mis-parsing under attributes or
nesting, YAML block-sequence import losing rows, and cx diff's table
blind spot. Where behavior is deliberately typed-lossy (Markdown tables,
CSV), the spec now says so and the flag surface rejects what it can't honor.

Migration

  • Store URIs: replace cxpack:///cxobj:// per the table in store.md;
    stores reopen self-describing.
  • Collection-valued attributes: move the value to a child element —
    [e sel=$nodes][e [sel $nodes]]; validate schemas: enum=[a b]
    [enum a b], schema=[…] → nested [schema …], extends=$B
    [extends $B].
  • Predicates (if arriving from 0.12): run
    cx fmt --migrate-predicates -w across your tree.
  • Hex under ::decimal/::bigint: write base-10.

Toolchain & public build

The vendored V fork pins its complete bootstrap inputs (vc, tcc,
macports-legacy) — clean clones build offline-deterministically; public
make test runs under a real C compiler; the mirror's CI calls only
public targets. Release artifacts: cx-darwin-arm64.tar.gz (CLI +
libcx.dylib + cx.h) with SHA256SUMS.txt.

Full detail: CHANGELOG.md §0.13.0.

CX v0.12.0

Choose a tag to compare

@eptx eptx released this 22 Jun 16:03

CX v0.12.0 — Release Notes

Date: 2026-06-22
Tag: v0.12.0

The reliability release. Concurrency and memory move from "works with
caveats" to sound by construction: tail calls no longer overflow the native
stack, the precise GC's cooperative-safepoint collector becomes the default so
multi-reactor HTTP and concurrent workers are safe, and the reactor / streaming
write paths are bounded against runaway RSS. Alongside that: the block-comment
syntax is unified on [; … ] (the one breaking change — see Migration), the
single-source-of-truth versioning model is enforced end to end, the CLI learns
stdin / inline evaluation, and roughly twenty bugs are fixed — several of them
silent-wrong-answer or capability-fails-silently violations of CX's fail-loud
principle.

Changed (breaking)

  • Block comments are now [; … ] only. [- … -] and [-- … --] are retired
    as comment forms, and [- a b] is always subtraction. This removes the
    long-standing [--token ambiguity between a comment and a minus expression.
    See Migration below. (Language version → 0.12.0.)

Reliability — concurrency & memory

  • Tail-call optimization (#60). Tail self-calls and tail closure-calls now
    run in O(1) native stack via a trampoline in the evaluator, so loop-shaped
    recursion no longer SIGSEGVs at depth (pure tail recursion is exercised
    100,000,000 deep). Semantics-preserving; non-tail and a few non-trampolined
    shapes fall back to ordinary recursion.
  • Cooperative-safepoint STW is now the default GC collector (#63 / #58).
    The precise -gc e collector parks running mutators at cooperative safepoints
    (mach-suspending only stragglers) before a stop-the-world cycle, so
    multi-reactor HTTP (CX_HTTP_WORKERS>1) and concurrent [?worker] threads are
    sound by construction rather than racing the collector. Revert with
    -d vgc_legacy_stw if needed. Single-reactor throughput is within noise;
    8-reactor is the tuning follow-up.
  • Reactor heap is bounded by heap growth, not request count (#57). The HTTP
    reactor collects its per-request transient heap once it has grown by
    CX_HTTP_GC_MB MB (default 64) since the last collect — self-tuning across
    light and heavy handlers. A light handler barely allocates so it almost never
    collects (full throughput + multi-reactor scaling); a heavy handler trips it
    every few requests so RSS stays bounded. (The earlier every-N-requests gate,
    default 64, fired a global stop-the-world ~hundreds of times/sec and cut
    throughput ~3× — that regression is fixed here. CX_HTTP_GC_MB=0 disables it;
    the legacy CX_HTTP_GC_EVERY request-count gate is still honored when set.)
  • HTTP serves multi-reactor by default (min(4, cores)). The server fans
    out across a few cores out of the box — sound on the cooperative-safepoint
    collector, and ~4 reactors is the sweet spot before the per-request GC lock
    starts to contend on a many-core box. Tune with CX_HTTP_WORKERS: an integer
    (honored as asked — a 64-core test gets 64; above the core count it
    oversubscribes, with a one-line note, and a 256 safety ceiling guards typos),
    max for one worker per core, or 1 to opt back into a single reactor.
    (Measured: ~162k req/sec default, ~110k at =1, on a 12-core box with a
    trivial handler.)
  • Streaming data-bin writes are bounded under -gc e (#52). Large-span
    recycling plus periodic collection cap the live set on the fd-streaming write
    path, so emitting a large document no longer balloons memory.
  • Comprehension memory fix (#62). [?for]’s per-item env.clone() no
    longer deep-copies the shared closures table, eliminating a general
    (non-HTTP) memory blow-up on large comprehensions.
  • Concurrent [?worker] threads (#58), behind CX_WORKER_THREADS. A
    [?worker] body runs on its own thread and coexists with a {block:true}
    serve, instead of monopolizing the thread so the server never binds. Off by
    default this release.

Changed

  • cx <file> renders every top-level form, not just the last (#16). A script
    with multiple top-level expressions now prints each result in order.
  • --allow-net no longer bypasses the §4.5 SSRF deny-set (#47). A bare
    --allow-net grants outbound reach but still refuses loopback / link-local /
    private / metadata ranges unless an explicit literal-IP or localhost grant
    admits them; only --allow-all bypasses the deny-set. Tightens the default
    security posture.

Added

  • cx-stdlib/strings string→number parsers (#54). to-number / to-int /
    to-float — a locale-free bridge that returns a numeric scalar for valid
    input and the absence channel () for non-numeric input (no silent
    string passthrough), so callers branch with [?else …]. Replaces the unsafe
    [$cx:parse …] workaround.
  • Concurrent SSE push on the serve path (#28). Topic pub/sub: a handler
    subscribes a connection to a topic and sse-publish fans one event out to
    every subscriber.
  • cx - and cx -e EXPR. Read a program from stdin (cx -) or evaluate an
    inline expression (cx -e '…') — no cx eval needed.
  • tools/vgc-debug/ toolkit (#70). Durable probes, gated diagnostic patches,
    and methodology for the precise-GC concurrency work — for contributors
    investigating collector behavior.

Versioning & release hygiene (#67)

  • The repo-root VERSION file is the single source of truth, enforced.
    Every surface either derives the version (the CLI / C-ABI via the build
    define, the guide at build time, the wasm build, runtime error messages) or is
    stamped from it by bump_version.sh (package manifests, README badges, the
    VS Code extension). User-facing error messages no longer cite a frozen release
    (e.g. the cast error lists supported kinds instead of "v0.8.0 supports …").
  • check-version-consistency now scans vcx/, spec/, docs-src/,
    stdlib/, and tooling/
    and fails the build on any stray vX.Y.Z literal
    outside an explicit history allowlist — so a release can no longer ship docs,
    tooling, or a playground that advertise an older version.

Fixed

Silent-wrong / data-loss (highest priority — fail-loud violations):

  • #38[$idiv] / [$mod] / [$div] now reject bigint and decimal
    operands (CXER0100) instead of silently returning an i64-wrapped wrong answer.
  • #10 — JSON / YAML emit of a :table block now projects its rows instead
    of dropping them to null.
  • #21[?for [in $x $m/key]] over a map member whose value is a
    sequence-of-elements now iterates the members (count and iteration agree).
  • #16 — see Changed (was: all but the last top-level form silently dropped).

Fail-loud / capability-silent:

  • #46 — a [?def] body that raises now surfaces the error instead of
    collapsing to a silent data literal.
  • #29net:set-deadline / set-opt on a std-stream handle now reject
    loudly instead of silently no-op'ing.
  • #23accept-iter surfaces a handler that returns without responding.
  • #56net:read-all / read-line / line-iter honor a configured
    read-deadline (dial opt or set-deadline), raising CXER4507 instead of
    hanging forever on a peer that never closes.
  • #55 — a zero-argument user [?def] is now callable by its bareword head
    ([f]) instead of parsing as a data element.
  • #53 — a bareword-head recursive [?def] call with computed arguments now
    dispatches instead of falling through to data construction.
  • #11 — unknown / retired directives stay fail-loud rather than silently
    falling back to a data literal (a pure-data resource still evaluates to
    itself; the fallback no longer over-reaches).

Lossless import:

  • #4 / #5 — YAML and TOML now import losslessly into the native map/array
    value model.

Other:

  • #48 — the HTTP server waits for the full POST body before invoking the
    handler.
  • #27[?select] sequence diagrams emit arrows with correct labels.
  • #39cx:parse of a single-root document returns a navigable node.
  • #18 — a [where] infix-comparison error points at the prefix form.
  • #17 — docs / examples / scripts use cx <file> instead of the redundant
    cx eval.
  • #15 — the published cx-v package ships transport/ + x/ and builds
    with clang (-cc cc).

Migration — comment syntax

The only breaking change. Block comments must use [; … ]:

[; this is a comment ]             ; the old [- … -] / [-- … --] forms are retired
[- 5 2]                            ; this is now subtraction (= 3), never a comment
  • Replace any [- … -] or [-- … --] comment with [; … ].
  • If you used [- … -] to comment out a block, switch it to [; … ].
  • Bare [- a b] that you intended as subtraction is unchanged and now
    unambiguous.

Compatibility

Language version advances to 0.12.0. The comment-syntax unification is the
sole breaking change; every other change is backward-compatible. The
cooperative-safepoint GC default is transparent to programs (revertible with
-d vgc_legacy_stw), and the new concurrency knobs (CX_HTTP_WORKERS,
CX_WORKER_THREADS) are opt-in. The ABI, on-disk format, and bundled-library
version axes are unchanged.