Cure v0.23.0 :: Packaging, Proof, and Polish
by Aleksei Matiushkin
v0.23.0 is the release that finally ships the remote package-registry story. The work was scaffolded in v0.18.0, tentatively pencilled into every release between v0.19.0 and v0.22.0, and rescheduled every time so that those releases could focus on the language surface.
With the language itself in a stable place after v0.22.0, v0.23.0 lands the registry in full -- HTTP client, lockfile, Ed25519 signing, Rekor-style transparency log, Hex cross-publishing -- alongside a broad ergonomics upgrade that catches the day-to-day cycle up to the language.
Remote package registry
Six new modules in Cure.Project.*:
-
Cure.Project.Registry-- read-only HTTP client over OTP's:httpc. Every response body is content-addressed by its SHA-256 and cached on disk under~/.cure/registry_cache/. Hashes are re-verified on every read; a tampered cache entry is thrown away and the request re-issued. Every call emits structured events on the new:registrystage ofCure.Pipeline.Events(:fetch_start,:fetch_ok,:fetch_failed,:cache_hit,:hash_mismatch). -
Cure.Project.Lock-- reads and writesCure.lock. The shipped format is the one the v0.17.0 design document specified:[lock.http] version = "1.2.3" hash = "sha256:..." dependencies = ["json ~> 2.0"]resolve_with_lock/2short-circuits the resolver when every current constraint is still satisfied by the locked version. The result is that a secondcure depsafter a clean checkout touches neither the network nor the backtracking solver. -
Cure.Project.Signing-- Ed25519 key management on top of OTP's built-in:cryptosupport. Keys live under~/.cure/keys/with tight file permissions. The signing message isname || NUL || version || NUL || sha256(tarball); the same canonicalisation runs on both sides. Clients keep atrusted.tomlthat maps maintainer handles to their public-key bytes; a signature that does not verify against a trusted key surfaces asE041. -
Cure.Project.Transparency-- client-side verifier for the Rekor-style append-only publish log. Every log entry is canonicalised as key-sorted JSON and its hash is chained against the previous entry. When the/logendpoint is unreachable the verifier returns{:ok, :unverified}and emits a warning underE042; operators who want strict verification flipconfig :cure, strict_transparency: true. -
Cure.Project.Publisher-- assembles the package tarball, signs it, and uploads it via a JSON envelope containing base64 tarball and signature bytes.build_hex_tarball/1produces a Hex-compatible tarball (VERSION,CHECKSUM,metadata.config,contents.tar.gz) formix hex.publishto consume. -
Cure.Project.Json-- minimal internal JSON codec. The compiler speaks its own JSON for the registry protocol so no external dependency has to land in the core.
New CLI surface
cure publish/cure publish --dry-run/cure publish --hexcure search <query>andcure info <name>[:version]cure keys generate <handle>andcure keys listcure doctor-- environment + project + source health report, exits non-zero on any warning or error so it can gate CIcure fix [--dry-run]-- project-wide safe rewrites (line endings, trailing whitespace, tabs -> two spaces, blank-line runs, trailing newline)cure test --cover-- runs the self-hosted test suite through OTP's:coverand emits an HTML report under_build/cure/cover/index.html
Standard library (up to 27 modules)
-
Std.Json-- the runtime companion to the v0.21.0@derive(JSON)extension. TheValueADT covers every JSON shape (Null | Bool(Bool) | Num(Float) | Str(String) | Arr(List(Value)) | Obj(List(JsonPair))). Encoder and decoder are backed by:cure_std_jsonon the Erlang side. -
Std.Http-- thin wrapper over:httpc.get/1,get/2(with headers),post/3,head/1. ReturnsResult(Response, HttpError)so callers can compose HTTP with plainResult-chains. The registry client dogfoods the same runtime module. -
Std.Gen.shrink_int/1,shrink_list/1,shrink/1-- shrinking primitives. Integer shrinking halves toward zero; list shrinking drops elements, shortest-first; the polymorphicshrink/1dispatches on runtime shape (int / list / tuple). -
Std.Test.forall_shrunk/3andforall_shrunk_default/2-- shrinking-aware property runner. On the first failing sample the runner walks the shrinker until no smaller value fails the property and raises{:property_failed_with_shrunk, minimal}. The reported counterexample is the minimum, not the first draw -- the single biggest DX win for property-based testing.
Infrastructure
-
Cure.Telemetry-- optional:telemetrybridge. Subscribes to everyCure.Pipeline.Eventsstage and re-emits events under[:cure, :pipeline, <stage>, <event_type>]. Production deployments can feed compilation and Z3 latency into an existing observability stack without extra glue. The:telemetrydependency is declared optional inmix.exs; if it is not on the load path the bridge silently becomes a no-op. -
Cure.Doctor-- structured diagnostic. Checks Elixir / OTP / Z3 presence, the registry URL, project file sanity, lockfile freshness, open type holes, undocumented public functions. Each finding carries a severity, a code, a hint, and an actionable fix. -
Cure.Fix-- project-wide safe rewrites. Walkslib/**/*.cureandtest/**/*.cure, applies five conservative transforms, leaves files alone when nothing changes. -
Cure.Cover-- instrumentation harness around OTP's:cover. Renders an HTML report plus a per-module text summary.
Showcase example
examples/cure_brainloop/-- the top-pick showcase from the internalideas_for_cure_apps.md. A toy expression-language interpreter with a REPL FSM. Uses ADTs, records, refinement types, protocols, effects, FSM callback mode, OTP interop, FFI, and the newStd.Jsonmodule in one self-contained codebase. Ships with an ExUnit suite that covers lexer, parser, evaluator, and environment semantics.
Error catalog
Five new codes E038-E042:
E038 Registry Fetch FailedE039 Registry Hash MismatchE040 Registry Package Not FoundE041 Registry Signature InvalidE042 Transparency Log Unreachable
Documentation
docs/PACKAGE_REGISTRY.mdrewritten from a v0.17.0-era design document into the authoritative shipped contract: endpoints, lockfile format, signing message, transparency log entry schema, failure-mode matrix.docs/PUBLISHING.md-- end-to-end walkthrough covering key generation, dry-run verification, live publish, Hex cross-publish, key rotation, strict-transparency mode, and troubleshooting.
By the numbers
- 1144 tests pass (up from 1114; 3 doctests + 1141 tests).
mix credo --strict: 0 issues across 167 source files.mix cure.check.stdlib: 27/27 (up from 25/25).mix cure.check.examples: 44/44.- Five new error-catalog codes
E038-E042. - Two new documentation files (
docs/PUBLISHING.md, major revision ofdocs/PACKAGE_REGISTRY.md).
What's next (v0.24.0)
With the registry story closed, v0.24.0 returns to the language itself:
- Monomorphisation. Specialise polymorphic functions whose call sites all use concrete types.
- Profile-guided optimisation. Feed profiler data into the inliner and pattern-aware SMT encoder.
- IDE reach. Ship first-class Helix / Zed configurations and upgrade the VS Code extension to track the current LSP surface.
- REPL-level hot reload. Recompile-and-rebind on every file save for long-running REPL sessions.
Getting started
git clone https://github.com/am-kantox/cure-lang.git
cd cure
mix deps.get && mix test
mix escript.build
./cure version # Cure 0.23.0
./cure doctor # check your environment
The repository is at github.com/am-kantox/cure-lang. v0.22.0 cleaned up the language corners; v0.23.0 gives the ecosystem a home.