Skip to content
This repository was archived by the owner on Oct 14, 2026. It is now read-only.

Releases: tompassarelli/beagle

v0.25.2

Choose a tag to compare

@tompassarelli tompassarelli released this 23 Aug 03:59

Beagle v0.25.2

Beagle v0.25.2 is the cleaned product checkpoint for Beagle as an independent,
file-authored, statically typed Lisp derived from Clojure. It keeps the useful
compiler and Store machinery while moving the separate proposition-first
language thesis into Clause instead of forcing two languages into one product.

Changed

  • Source files and their checked AST are again Beagle's program authority.
    Beagle Store remains optional durable tooling for terms, triples, history,
    queries, provenance, and caches rather than a second language authority.
  • Clojure, JavaScript, and Nix are the primary hosted profiles. Native Core is
    retained as an explicit experimental system-layer path with separately
    selected C17, QBE, and C17/WASI Wasm materializers.
  • Unconsumed semantic-authority experiments were removed from the live product
    tree. Their history remains recoverable in Git while Clause develops the new
    language independently.

Fixed

  • Clojure output now implements the portable utf8-encode contract, and
    imported qualified union variants retain their nominal checker types.
  • Native Core adds focused fail-closed coverage for integer literals, recursive
    short-circuiting, distinct collections, sorting, artifact linking, and
    driver selection without promoting Native into the hosted release contract.
  • The Racket freshness gate separates the production compiler closure from the
    test closure, avoiding unnecessary test-module compilation in ordinary
    check and build loops while retaining the complete gate for tests.

Full Changelog: v0.25.1...v0.25.2

v0.25.1

Choose a tag to compare

@tompassarelli tompassarelli released this 22 Aug 10:11

Beagle v0.25.1

Beagle v0.25.1 repairs the Nix package for the final file-authored, typed-Lisp
language line. It changes package provenance and runtime completeness only; the
language and program-authority boundary frozen in v0.25.0 is unchanged.

Fixed

  • Nix-packaged Native builds now carry the exact source revision into compiler
    receipts even though immutable package sources contain no .git metadata.
    Checkout builds continue to derive provenance from their own Git HEAD, and
    malformed, absent, or conflicting revision claims fail closed.
  • The packaged runtime now includes ripgrep, which the Native build finalizer
    requires while validating generated artifacts.
  • Checked-AST reuse now defaults to the writable XDG or user cache instead of
    trying to create cache state inside an immutable packaged source tree.

Full Changelog: v0.25.0...v0.25.1

v0.25.0

Choose a tag to compare

@tompassarelli tompassarelli released this 22 Aug 09:02

Beagle v0.25.0

Beagle v0.25.0 is the final release of Beagle's file-authored, typed-Lisp
language line. It seals the Clojure-derived compiler and its Store, Native Core,
hosted-target, provenance, and materialization infrastructure before native
proposition-first work begins. This is not a proposition-first release.

Final typed-Lisp line

  • Source files and the checked typed-Lisp program remain the authority for
    native program meaning in this release. The compiler follows its established
    parse, check, and emit or Native Core lowering paths.
  • The existing .bgl, .bclj, .bjs, and .bnix authoring profiles remain
    available as frozen migration surfaces. No relational solver, checked theory,
    oriented-plan protocol, or proposition-first default is included.

Migration boundary

  • Pin v0.25.0 when a program must retain the typed-Lisp and file-authority
    contract. Later native Beagle development moves program authority into sealed
    semantic models instead of preserving this line through compatibility code.
  • Beagle Store, provenance, incremental computation, effects, observations,
    and target materialization remain part of the system carried by this release;
    the boundary freezes the authoring and program-authority model, not those
    reusable system capabilities.

Full Changelog: v0.24.0...v0.25.0

v0.24.0

Choose a tag to compare

@tompassarelli tompassarelli released this 22 Aug 08:59

Beagle v0.24.0

Beagle v0.24.0 makes macro expansion structurally hygienic, adds a typed
structural matcher for authoring macros, and turns the full compiler gate into
a bounded parallel release preflight. The Racket compiler and checked-in
self-hosted compiler carry the same macro and identity contracts.

Language and compiler

  • Macro hygiene now follows lexical scope identity end to end. Binding and
    reference edges are resolved before lowering, preserved through source facts
    and hosted emitters, and serialized through the self-hosted compiler. Local
    shadowing, nested expansion, and intentional capture therefore retain the
    identity chosen at the macro boundary instead of depending on rewritten
    spellings.
  • Stable lexical identities survive layout-only source changes. Scope and
    reference identities derive from structural provenance rather than transient
    names, so formatting or unrelated source movement does not silently remint
    the branch-corpus identity oracle.
  • Macros can use syntax-match for structural dispatch. Patterns can
    distinguish identifiers and literals, match list, vector, and map shape,
    capture a final tail, and select clauses in source order. Invalid categories
    and malformed tail patterns report at the pattern span, while successful
    expansions continue through normal type checking.
  • The self-hosted compiler implements the same matcher. The checked-in seed
    mirrors structural syntax-match, typed constant expansion, reachable branch
    checking, and malformed-pattern diagnostics, including a fixture that gates
    oracle and self-host agreement.

Test infrastructure and performance

  • The full release tier runs as supervised parallel shards. Each setup phase
    and shard has an explicit deadline, completion receipt, retained failure log,
    and subtree reaping. Worker results merge deterministically into the existing
    active, demoted, and gated-tier verdict.
  • Cold work is balanced and shared instead of repeated. Shard assignment is
    based on measured compiler-heavy costs; Wasm tests share canonical generated
    fixtures; and Native Core checkpoints reuse verified frozen programs before
    C17 materialization. Resolved Wasm toolchain work has its own measured
    process-lane capacity instead of inheriting the former missing-tool skip
    cost. The ordinary active loop remains separate from the full release
    preflight.
  • The parallel C17 checkpoint suite is advisory for this seal. Three
    independent release-preflight failures came from cold-cache prerequisites or
    scheduling rather than candidate behavior; the bounded replay of the final
    failure passed and verified the published checkpoint. The suite still runs
    under its unchanged 90-second owner, but it must be requalified before a
    later release can promote it back to blocking status.

Compatibility

This pre-1.0 minor release removes the legacy name-rewriting hygiene path.
Macros or tools that inferred binding identity from rewritten symbol spellings
must consume the compiler's structural binding and reference identities. The
new syntax-match form is additive.

Full Changelog: v0.23.0...v0.24.0

v0.23.0

Choose a tag to compare

@tompassarelli tompassarelli released this 17 Aug 17:09

Beagle v0.23.0

Beagle v0.23.0 brings the durable engine into the repository as Beagle
Store
. The former branch-core tree, Fram command names, and FRAM_*
configuration surface are replaced by store, beagle-store-*, and
BEAGLE_STORE_*. The rename is the visible part of a deeper change: qualified
references now remain structural from source through the Racket compiler,
self-hosted compiler, Native Core, and Store, while exact source bytes and
receipts remain authoritative at their own boundaries.

Beagle Store

  • Breaking: the in-repository engine is now Beagle Store. The engine lives
    under store/, its commands use the beagle-store-* prefix, its namespaces
    use store.*, and its configuration uses BEAGLE_STORE_*. The old
    branch-core/**, Fram command, namespace, package, and environment surfaces
    are removed rather than retained as aliases.
  • Durable revision operations are part of the Store. Generations bind to
    revisions; branch references support durable compare-and-set and
    post-durable watching; long chains can reseal past the old segment ceiling;
    and unreachable segments can be collected from explicit durable roots.
    Native chain-parity and float-coercion checks protect these transitions.
  • Store edits mint structural facts directly. Code ingestion and native
    fact reading retain qualified callee structure, Store resolution mints
    declarations and references from those values, and edit minting assigns
    ordered conflict-free keys. The temporary symbol-shaped qualified-reference
    scaffold and its accessor are gone, with a gate keeping the removed path at
    zero uses.

Language and compiler

  • Qualified references are structural end-to-end. A qualified reference
    has explicit qualifier and local-name fields instead of being repeatedly
    split and reconstructed from text. The parser, AST, checker, type catalog,
    source facts, Native Core lowering, and Clojure, JavaScript, and Nix emitters
    consume the same representation, including under local shadowing.
  • The self-hosted compiler carries the same contract. Its reader, parser,
    AST, checker, and hosted emitters preserve the structural reference, and the
    checked-in seed was reminted against the Racket oracle. Structural qualified
    references therefore survive the full self-host route rather than becoming
    target-specific strings.
  • Exact source bytes remain exact. Selecting a hosted projection no longer
    changes the immutable source snapshot used for identity. Provider paths and
    source digests stay stable across target projection, invocation order, and
    checkout location.
  • Beagle's boundary is stated plainly. The public documentation now
    presents Beagle as an independent typed Lisp with a Clojure-derived core,
    Native Core for execution, and Beagle Store for durable semantic identity.
    The allocation model and influence map distinguish shipped mechanisms from
    research claims and name the ideas Beagle adopts and refuses.

Test infrastructure and performance

  • The gate serializes itself. Concurrent beagle test invocations share
    one file lock, so release evidence cannot be produced by overlapping suites
    that contend for the same caches and build outputs. Slow active tests are
    listed with their wall times at the end of every run.
  • Consumer smoke is now a release-gate phase. A small multi-module program
    proves qualified Native references through source facts, and a Store-shaped
    program proves NativeLoweringCompleteV0 through the same native builder a
    real consumer uses. The fixtures and tool paths resolve from the checkout at
    runtime instead of depending on a repository name or fixed location.
  • A formerly 90-second native test now takes about two seconds when warm.
    The native parallel proof still performs a real build, execution, and QBE and
    Wasm refusal checks, but uses a minimal fixture and the content-keyed gate
    cache. Its measured focused path was 37.0 seconds without the gate-result
    cache and 1.869 seconds warm; the original 90-second deadline remains a
    tripwire.
  • Verified Native Core results are reusable. Whole-result and early-alias
    caches validate source, compiler, projection, and artifact identity before a
    hit can be reused, retire corrupt entries, and preserve failure diagnostics.
    The measured fully warm native build fell from roughly 180 seconds to 48.3
    seconds, a 3.73× improvement, with generated artifacts byte-identical to the
    cold build.
  • CI and release publication have separate jobs. The active gate is
    distributed by scheduling unit, while release publication validates authored
    notes and the exact candidate commit before producing assets.

Consumer evidence

  • Authoritative-history replay leaves both success and failure receipts. In
    the game consumer's history-and-shadow-engine proof (the Stage 4 proof), the
    same revision-bound journal window was replayed through the incumbent and
    candidate engines. A matching run and a deliberate semantic divergence were
    both retained as checked receipts, so agreement and refusal are independently
    auditable.
  • A semantic live-cutover rehearsal produced a complete admission receipt.
    In the following live-engine proof (the Stage 5 proof), one source change
    invalidated and cold-compiled exactly one semantic unit while eight unaffected
    units retained identity. The receipt records the visible 16 → 17 behavior
    change, matching forward and reverse replay, refusal of a mismatched candidate,
    compare-and-set winners at the expected head, and continued state after
    admission. This is downstream evidence for the compiler and Store contracts,
    not a claim that a general live-upgrade language primitive was added.

Fixes and correctness

  • Qualified Native globals retain their full spelling during free-reference
    discovery and lookup instead of losing the qualifier at the final lowering
    boundary.
  • Unresolved structural references fail at the parser, checker, emitter, native
    reader, or Store resolver that owns the boundary; they no longer become
    phantom aliases or arbitrary typed values through string fallback.
  • Canonical module-root comparisons use stable provider paths, and target
    projection preserves the original source bytes used by provenance and
    identity receipts.
  • Native cache hits revalidate the exact input closure before publication and
    consume validated aliases directly, preventing projected facts from being
    rewritten under a different cache identity.
  • Store sealing, status, ordering, graph control, edit verification, and commit
    gates now resolve through the renamed Beagle Store surface consistently.

Compatibility

This is a pre-1.0 minor release with a deliberate breaking rename. Repository
and script references to branch-core/** must move to store/**; Fram-prefixed
Store commands, namespaces, packages, and environment variables must move to
their beagle-store-*, store.*, and BEAGLE_STORE_* forms. No compatibility
aliases remain.

Code that inspected or constructed qualified references as symbol-shaped text
must use their qualifier and local-name fields. Store integrations must likewise
mint and consume structural reference facts. Whole-program compilation remains
the authoritative release path; the new caches reuse only previously verified
results and do not change the artifact contract.

Release artifacts

The GitHub release continues to attach the beagle-selfhost stage0 native
compiler and its beagle-selfhost.seed-nar-hash. Publication requires the exact
candidate commit to pass the non-publishing release gate, authored-note checks,
native artifact checks, and byte-for-byte native/Babashka/Racket parity over the
Beagle Store corpus.

Full Changelog: v0.22.0...v0.23.0

v0.22.0

Choose a tag to compare

@github-actions github-actions released this 17 Aug 08:45

Beagle v0.22.0

Beagle v0.22.0 turns Native Core into a practical substrate for standalone command programs and interactive Wasm engines. It closes module resolution: a require is now served only by sources the invocation names or by a declared source root, in the Racket compiler and the self-hosted compiler alike. It also lands the first compiler-owned semantic-unit reuse seam, while keeping whole-program compilation as the authoritative release path.

Language and typing

  • Breaking: module sources are now explicit and closed. A require resolves only through sources named by the invocation or a declared --module-root LOGICAL_PREFIX=PHYSICAL_DIRECTORY; ancestor-directory search and flat-basename fallback are gone in both compilers. The root maps a complete namespace path to exactly one file, and namespace-based emission preserves qualified identities across modules. beagle build, beagle check, beagle ast, beagle build --materializer, and beagle native-exe accept repeated roots; the self-hosted driver takes the same roots plus repeated --source for an exact closed bundle.
  • Checker and host-contract precision. Inference now keeps unknown distinct from Any, preserves fresh structure and invariant/second-order contract context, and numeric refinement returns the declared Number union alias (E003) rather than a mismatched primitive type. JavaScript static members, Atom, native Map, browser geometry, and numeric Math surfaces are typed, with number-predicate narrowing kept in parity between compilers.

Native and Wasm

  • Wasm entry ABI v1. Repeated --entry flags now produce distinct, qualified beagle_wasm_entry_v1__<ns>__<name> exports. Resource-bearing entries share an instance arena, expose explicit reset, and retain the zero-import reactor contract.
  • Deterministic Wasm host I/O. Hosts can feed byte records through the exported environment mailbox and read registered Buffer storage directly from linear memory. Entry results, seams, adapter source, and runtime policy remain bound into the build receipts.
  • Native programs can own their operating-system boundary. Typed capabilities now cover bounded filesystem inspection and reads, atomic writes, directory creation, append, wall-clock formatting, sleep, inherited and captured processes, explicit streaming child-process lifecycles, and an exclusive file lease. host.fs/lock-exclusive takes a non-blocking whole-file lock the operating system releases on close or on process death, returning a closed result union that carries contention as an error variant instead of an unbounded wait.
  • Transient vector builders. transient, conj!, and persistent! give Native Core a linear TransientVec builder that avoids rebuilding a persistent vector per element. The checker proves single ownership — including across recur, where a loop-owned builder must be threaded rather than captured — and the builder lowers through the native, C17, and wasm32 materializers.
  • Typed JavaScript host surfaces. Static members, Atom values, native Map construction and contracts, browser geometry, and the numeric Math surface are typed rather than opaque, and number-predicate narrowing agrees between the Racket compiler and the self-hosted compiler.
  • Native data tooling. Compiler-shipped Beagle libraries add datum reader events, strict JSON and EDN event codecs with structured failures, and structural Nix option-path extraction and suggestion utilities.
  • Coherent multi-module native builds. Native lowering now composes complete source bundles, resolves qualified cross-module calls, preserves imported unions and match context, and derives vector-literal types without downstream decoy declarations.
  • Command-line executables are substantially more capable. beagle native-exe accepts one typed (Vec String) argument vector as its entry boundary, while native output and process primitives support complete command behavior without hosted wrapper logic.
  • Bounded semantic-unit reuse is proven. The compiler can extract, validate, select, and deterministically reassemble exact typed/native unit payloads across layout-only, private-body, and public-interface mutations, and single-unit typed and native compilers now compile exactly one unit per request against a signature-only typing prelude. This is compiler groundwork, not yet a production incremental cache.

Test infrastructure and gate performance

  • The active gate is sharded by scheduling unit. --shard i/n partitions the heavy-first launch order across CI machines, including phase units from sharded test files, while coverage refusals are checked against the complete expansion. One-test units are counted correctly, including singular raco test summaries.
  • The Wasm materializer gate runs by phase. Its nineteen phase units complete independently with per-unit cache identities and deadlines, reducing the measured gate from about 400 seconds unsharded to about 168 seconds at four workers. Per-file concurrency is capped so identical fixture builds do not contend for the machine.

Fixes and correctness

  • An unresolvable require is rejected instead of silently registering a phantom alias. Previously every qualified call through such an alias typed at an arbitrary type with no diagnostic. A namespace the target's host runtime supplies is still accepted through the typed stdlib catalog or an explicit declare-extern.
  • A closed checked bundle is ordered by logical source id, so its module list, closure digest, and derived source facts are a function of the sources alone — not of argument order, and not of where the checkout lives.
  • Module exports resolve before inference runs, inference's unknown is kept distinct from Any and neutral in joins, freshly inferred structure is marked effectful and preserved at its expected shape, and invariant and second-order contract contexts survive checking.
  • Nullable text-index results, imported union-member coercion, zero-variant constructors, callback lowering, scalar conversions, source provenance, root-arena lifetime, and Wasm/POSIX shim separation now fail or lower at their owning boundary.
  • JavaScript emission preserves qualified aliases under local shadowing and detects asynchronous work nested inside emitted call and assignment forms.
  • Native build reports and semantic identities remain deterministic and fail closed when source, interface, obligation, or payload claims disagree.

Compatibility

This is a pre-1.0 minor release, and module resolution is the change most likely to need action. A build that relied on the compiler finding a provider by walking parent directories or by matching a bare file name must now name that provider in the invocation or declare a --module-root for it; the root maps a complete namespace path to one exact file, with - in a namespace segment read as _ in the file name. A root candidate carries the importing module's own profile extension, so a hosted module cannot reach a Beagle Core (.bgl) provider through a root — compile the Core module to the hosted target instead. An unresolvable require is now an error rather than a silent success.

The Wasm executable surface intentionally replaces the single beagle_wasm_entry_v0 export with qualified v1 entry exports; hosts using the old entry name must migrate. The new native host, transient-vector, and codec surfaces are additive. Whole-program builds remain authoritative, and the semantic-unit seam does not imply a persistent cache or a new artifact format.

Release artifacts

The GitHub release continues to attach the beagle-selfhost stage0 native compiler and its beagle-selfhost.seed-nar-hash. CI retains the byte-for-byte native/Babashka/Racket parity gate over the Fram corpus before those assets are published; under closed module resolution that gate compares the corpus modules whose requires it can serve, and reports each module it skips together with the Core provider that made it unreachable.

Full Changelog: v0.21.1...v0.22.0

v0.21.1

Choose a tag to compare

@github-actions github-actions released this 15 Aug 14:14

beagle-selfhost — stage0 native compiler (GraalVM native-image of the blessed seed).

The canonical Beagle builder: emits all certified targets (clj / js / nix) plus module resolution. ~20 MB, ~7 ms startup, zero reflection config.

Byte-for-byte parity gated in CI: native emit == babashka seed emit == Racket oracle emit, over the fram/src corpus.

./beagle-selfhost emit FILE.bclj          # also: ast | check | emit-from-ast --target js|nix

v0.21.0

Choose a tag to compare

@github-actions github-actions released this 15 Aug 13:04

beagle-selfhost — stage0 native compiler (GraalVM native-image of the blessed seed).

The canonical Beagle builder: emits all certified targets (clj / js / nix) plus module resolution. ~20 MB, ~7 ms startup, zero reflection config.

Byte-for-byte parity gated in CI: native emit == babashka seed emit == Racket oracle emit, over the fram/src corpus.

./beagle-selfhost emit FILE.bclj          # also: ast | check | emit-from-ast --target js|nix

v0.20.0

Choose a tag to compare

@tompassarelli tompassarelli released this 07 Aug 04:17

Beagle v0.20.0

Highlights

  • Native Core is now the center of the language: .bgl with bare #lang beagle always targets Native Core and lowers source stage → typed stage → frozen native program, with the materializer (restricted C17 or QBE) selected at build time rather than baked into the source. Roughly half the release's commits expand lowering coverage, and 31 committed validation drives execute real fram modules — fold, types, store, rt-core, kernel classify, FRI replay — end-to-end through C17 to running executables.
  • The world ontology is retired. The native-core stage schema is now stages.bclj with NativeCoreProgram and Frozen*StageV0 records, the build artifact is module.native-program with program-* report keys, content-digest is a real sha256 over an extended canonical encoding, and the dead draft/freeze/promote/Artifact lifecycle is deleted outright.
  • The typed-binding surface is locked: flat name: Type is the only annotation spelling at every binding position, returns are -> Ret, and the parenthesized and bracketed spellings are hard parse errors with pointed fix-its. Typed destructuring is gone (bind a name, destructure in the body), a binding vector annotates every binding or none, and roughly 6,200 annotation sites were recanonicalized in-tree. Both the Racket and self-hosted compilers close the grammar identically.
  • The checker now narrows on runtime proofs: a match arm refines a stable scrutinee to the matched member, and (instance? Member x) intersects on the true branch and subtracts from closed unions on the false branch — clearing 62 of 82 reported errors on native-core's own check profile without touching its source.
  • QBE landed as the first direct-native materializer and the anti-C-capture check: it reads the same frozen program C17 reads, and every QBE-shaped concession stays inside the materializer. Target ABIs became named inputs — layout measurement takes an ABI profile, QBE refuses a non-lp64 program by name, receipts attest the profile, and a gated wasm32 drive compiles and runs slices under the wasi clang and wasmtime against a committed seam ledger.
  • The ScriptC, Odin, and Zig targets were removed; the semantic-contract work from that arc (typed error carriers, composable allocation/domain raise sets) survives target-neutrally in the checker, and the native strategy consolidates on the C17 and QBE materializers.

Language

  • One annotation grammar: flat name: Type at every binding position — fn/defn/letfn/method params, defrecord and defunion fields, def/defonce, let/loop/with-open/if-let, define-macro contracts — with -> Ret returns. Wrapped (x : Int), [x : Int], and annotated-pattern spellings are rejected with fix-its that name the flat form; a mixed typed/bare binding vector is a parse error naming the offending binding (& rest exempt, x: Any satisfies the rule); a capitalized bare binding draws a lint since it usually is a dropped annotation.
  • match and instance? narrowing follows the ratified rules: arm-local refinement of stable lexical scrutinees, parametric scrutinees keep their substitutions through a member view, set! and ^:dynamic disable narrowing, and the false branch of instance? removes the member from a closed union.
  • Variant patterns bind the field (not the variant), variant accessors are emitted, and both behaviors were ported to the JS target.
  • A required module's defunion registers its whole variant surface, and imported defalias definitions expand through the provider require graph, so cross-module unions and aliases resolve the way same-module ones do.
  • Typed error contracts are modeled in the checker with payload carriers, allocation and domain raise sets compose, and an allocating function must declare :raises AllocationError.
  • Checker precision fixes: closed dynamic map keys are permitted, regex proofs survive Any bindings, record constructors are identified by registry rather than name shape, declared types are enforced through with-open and for :let bindings, and duplicate-namespace ambiguity is deferred instead of eagerly fatal.
  • Purity refinements: a self-opened transient counts as local mutation rather than a leak (in both the check and derivation passes), and loop bindings are walked when collecting mutation markers. Error values preserve namespaced payload keys.

Native Core

  • The staged pipeline is complete and first-class: stage schemas with canonical encodings and receipts, a determinism gate, a complete-module compilation command, and linking of complete modules into executables. All seven obligations — SSA, exhaustive match, closed layouts, checked arithmetic, legal ABI, token discharge, bounded effects — are validated with committed rejection fixtures and a rejection-depth corpus, so the pipeline provably refuses what it must.
  • Lowering coverage grew across the core vocabulary: loop/recur as SSA header blocks with back-edge jumps, checked integer arithmetic and division through the Outcome protocol, closed Atom mutation/assoc/compare-and-set, closed and dynamic keyword access, the Vec vocabulary (header-reference layout, count/nth/conj, literals, sequence primitives, doseq), persistent map and set operations, reduce-kv over closed maps, transients, exact float arithmetic and parse-double, deterministic stringification, sealed structural equality for dynamic values, and exhaustive sealed matches.
  • Union machinery deepened: records narrow through nested unions, a closed union narrows into a sub-union as a checked extract, flow arms join on the declared type when they cannot join structurally, carried nil alternatives widen, and map absence aligns with source optional unions.
  • Capability ABIs landed for stdout, host environment, sockets, and a monotonic clock, alongside sha256 byte-digest and codec source primitives, an explicit Atom state seam, growable arena materialization, and a write-capability arena acquire that satisfies bounded-effects with the write effect settled up the call graph. Function-bearing ABIs are refused.
  • Exact Unicode 15 text semantics matching JDK21 are embedded behind a gate, so native text operations agree with the hosted target's observable behavior.
  • The QBE materializer emits .ssa from the same frozen program as C17 — block parameters lower to phi nodes, explicit-offset aggregates are cross-checked against QBE's own layout computation rather than weakened to it — and its drive compares two independent emissions byte-for-byte. QBE is provided in the dev shell.
  • ABI profiles are explicit end to end: layout measurement takes the target ABI as a named input, build entry points and validation drivers thread NATIVE_SLICE_ABI, closed-layouts attests the declared profile, receipts name it, and the wasm32 validation drive (gated on BEAGLE_WASI=1) compiles slices with the wasi clang at -std=c17 -pedantic -Werror, runs them under wasmtime, and fails on seam growth or emission drift against a committed ledger.
  • A trapped instance now tells its host why it died: the trap code is recorded and reported through an optional, non-recursing reporter before abort — report only, a trap still aborts.
  • Cross-repo fram drives fail loudly on absent fram source, module identity resolves from the source-stage module table and survives lowering, and the drives track fram's live layout (t1/t2/t3 vocabulary, renamed sources, re-vendored fram-resolve corpus).

Self-host & remint

  • The facts-roundtrip core was ported to the self-hosted compiler, exposed on the CLI, and certified against an oracle corpus, with reader edge semantics and cached source locations brought into agreement.
  • Remint divergences were repaired for the JVM instance-position checker (receiver-adjusted arity, locked direction) and the graph emitter (expression-valued call heads, mint render round trips).
  • The self-hosted parser gained Nix inherit map entries and throwable unions, and emit-clj escapes control characters the Clojure reader accepts.
  • The self-host exemption ledger is truthful: explicitly unsupported forms are classified as unported rather than silently exempted.
  • The self-hosted compiler enforces the locked binding surface identically to the Racket compiler — the same three wrapped-form rejections, mixed-vector rejection, and the capitalized-bare warning — and the seed was reminted accordingly ([x : Int] previously miscompiled there into a binding literally named #%:).

Tooling & CI

  • Stale Racket bytecode is structurally impossible at the entrypoint seam: the one sourced entry file gates on a content-addressed stamp and runs raco make -j over every tracked .rkt when anything is newer or the pinned racket changed, with flock serialization for concurrent entrypoints and a BEAGLE_NO_ZO_GATE=1 escape. Bytecode also auto-recompiles when the pinned racket itself changes.
  • A canonical signature formatter lives outside the parser and is exposed as a command; two-entry signatures stay compact, nested signatures converge, and the authored and test corpora were reflowed at the flat canonical width.
  • Beagle source is text-authoritative: graph-registry adoption and @upstream:graph markers are gone, and native-core modules were de-adopted from graph upstream — graph projection remains a read-only view, never a gate.
  • Targets live in one canonical table and every target list in docs and tooling is a rendered view of it, so target inventories cannot drift.
  • CI pins Fram release compatibility, explicit Fram resolver output is honored, and secret scanning no longer misreads Beagle type annotations as credentials.
  • Firn gained a deterministic semantic index v1 with recovered authored option spans; beagle doctor probes the daemon endpoint directly; the Nix importer's parser recovers physical source locations from Nix tokens.
  • JS target: typed module boundaries are executable, and let initializers are scanned for local mutation.

#...

Read more

v0.19.0

Choose a tag to compare

@tompassarelli tompassarelli released this 27 Jul 08:31

Beagle v0.19.0

Highlights

  • Beagle now has a self-hosted compiler with a minted seed, byte-fixpoint remint gate, oracle ladder, and a native stage0 distribution. The self-hosted pipeline covers Clojure, JavaScript, and Nix emission, module resolution, macros, reader support, and checker parity.
  • Differential fuzzing and conformance ratchets now exercise the oracle and self-hosted compiler across targets. New reproducibility, downstream-consumer, and behavioral-emission gates make release verification fail closed.
  • The reader accepts additional Clojure-compatible forms: #_ discard, #js, ##Inf, ##-Inf, ##NaN, #^ metadata shorthand, bare-dot interop, Clojure-valid string escapes, and primed symbols.
  • JavaScript emission fixes preserve authored property names and underscores, avoid reserved-word mangling in property/method positions, lower effect-position if/cond idiomatically, freshen shadowed let bindings, and accept scoped npm requires.
  • Beagle is now dual-licensed under Apache-2.0 or MIT.

Language

  • Annotation-directed Atom construction allows a fresh (atom init) to adopt an expected (Atom T) element type while continuing to enforce invariance for aliased references. This enables nullable, explicitly annotated cells such as (Atom (U (Map String Any) Nil)) to start empty.
  • Purity checking now follows indirect purity boundaries, with tests covering the boundary behavior.
  • Added the case-to-match rewrite: literal case dispatch becomes match; grouped literal keys become or patterns, and unsupported constants are left unchanged for manual review.
  • The Nix target rejects free dotted names with diagnostic E021.

Self-host & remint

  • Added the Beagle self-hosted compiler source, official seed, bin/beagle-remint, and verification rungs for AST/check/emission parity and byte-stable bootstrap fixpoints.
  • The seed now includes the Atom-constructor checker update, resolving the remint divergence introduced by annotation-directed Atom construction.
  • Self-hosting gained Clojure, JavaScript, and Nix backends; --target dispatch; module resolution and extern imports; user macros; canonical character handling; deterministic lowering names; and parity fixes for unions, destructuring, JS quote, threading, parse failures, and macro expansion errors.
  • A GraalVM native stage0 package and CI verification/release-artifact workflow were added. Stage0 is preferred for verification when available, with babashka retained as a development fallback.

Tooling & CI

  • Added grammar-driven differential fuzzing, nightly fuzz CI, preserved minimized repros, and checker-precision parity coverage.
  • Added per-backend conformance oracle ratchets, a certification command, in-process batch compilation, deterministic byte-compare gates, and active JavaScript behavioral-emission coverage.
  • Added a hermetic downstream-consumer registry and release gate, including byte-clean compilation receipts, drift detection, sensitivity proofs, and crash-safe scratch containment. Test execution now drains subprocess streams concurrently and schedules the active tier with bounded parallelism.
  • Daemon runtime files are discoverable from a workspace, mirror repo-local state, and use TCP-ping liveness. Bun discovery is portable and package scope is worktree-aware.
  • Nix import emits structural (ms ...) / (s ...) forms; the Nix import roundtrip now self-bootstraps in the suite.
  • Tooling that rents fram's resolver now discovers it across fram's layout move (chartroom → codegraph, resolver at the repo root), and the cascade/callgraph gates fail loudly on empty graph output instead of silently passing.
  • Added regression coverage for declared unknown JVM statics.

Breaking changes

  • The ClojureScript target has been removed from the compiler, self-hosted compiler, test/conformance tiers, tooling, and editor integration. Projects targeting ClojureScript must migrate to a supported target.
  • The case surface is removed from self-host parsing. Use match; beagle rewrite case-to-match migrates literal dispatch automatically where safe.