Changelog

Changelog

Release-by-release changes to the Datalog language, engine and public integrations.

This page tracks changes to the Datalog language, engine and public integration surfaces. The notes below retain the release details previously included in the C Stable API overview; they focus on changes that affect consumers and extension authors. For the complete release record, see the engine changelog.

0.11.1 — 2026-09-26

Reference sessions share an engine-owned immutable compiled policy instead of copying the complete ruleset. Freeing the policy handle does not invalidate its sessions: the shared storage survives until the last session closes. A policy placed in caller-owned storage still receives an independent session snapshot. Python's default preparation also avoids an intermediate configuration handle. No public API or backend ABI changes in this patch.

The released SMALL measurement is 515,416 bytes instead of 1,178,352 per reference session sharing an engine-owned policy: 56.3% less, with the same three engine allocations. It excludes the policy itself and optional explanation/backend storage; Python and CFFI still allocate.

This is a memory improvement, not a general solving-speed claim. The release records instruction-cost increases on its diagnostic fixtures and unresolved latency regressions in the prepared-session matrix. Earlier setup timings were not repeated after the final field relocation. See the published measurements and their limits.

0.11.0 — 2026-09-25

Backend ABI 5 requires extension authors to migrate and rebuild custom backends. It adds a preparation-storage query, passes that storage to prepare, and adds an infallible commit callback. ABI 4 descriptors are rejected before callbacks run.

  • Advanced session configuration can query backend storage requirements and attach caller-owned aligned storage. The host checks it and never frees or inspects its contents; there is no implicit allocation fallback.
  • A successful backend solve produces a candidate until the host accepts it. Event windows commit only at publication; rejected candidates are destroyed without commit, preserving the previously committed state.
  • Consumer API 2, frontend/program ABI 2, diagnostic ABI 1 and the Datalog language remain unchanged.

See the migration contract and 0.11.0 release notes.

0.10.0 — 2026-09-24

This is a coordinated source migration, not a compatibility release. Recompile C/C++ and CFFI consumers. The installed contracts are consumer API 2, frontend/program ABI 2, backend ABI 4, and diagnostic ABI 1. The language retains MAELYS-DATALOG-v2 syntax; the numbers identify different interfaces, not successive language revisions.

  • The C Stable API unifies application values, facts, predicates and domains under maelys_datalog_value_t, fact_t, predicate_t and domain_t (with the same prefix). The former public_* names have no aliases. Diagnostics require versioned initialization and separate status, code, and presence sections. Aggregate domain errors and signed-sum overflow receive distinct codes, with no partial solve result.
  • The C Advanced API adds in-memory manifest bundles, caller-owned policy-object storage, bounded domain installers, composed backend/context configuration, structured prepared explanations, filter statistics and explicit decision composition on the same opaque handles.
  • The SDK installs ten maelys/ headers. It no longer installs the historical <maelys_datalog.h> aggregator or private implementation headers. The old C Low-level API and Python V1 pages remain as clearly marked 0.9.1 history.
  • Python has one maelys_datalog binding against the installed public SDK. The former maelys_datalog_next experiment and native C shim are removed; ownership, errors and predicate flags require migration.
  • The WASM and JavaScript binding moves to a typed SDK interface with atomic multi-predicate batches, exact signed int64 through bigint, explicit source atoms, Why-false and structured diagnostics.
  • C domain builder macros, reference-solver hot-path changes, reproducible native archives, and defensive aggregate diagnostics are included.

See the v0.10.0 engine changelog for the complete changes and migration notes.

0.9.1

The low-level domain registry now installs declared policy-source atoms after a successful install_predicates callback. Before this fix, the callback path silently ignored the atom table; table-based domains were unaffected. Callback failures still stop installation and atom-installation failures propagate. Declarative consumer types, backend ABI 3 and the 0.9.0 window APIs are unchanged. See the 0.9.1 engine changelog.

0.9.0

The native C SDK adds a multi-fact event window. One accepted group contributes zero or more complete typed facts. The adapter retains the last N groups, deduplicates their fact union, and recomputes a complete snapshot. A shared fact survives until its last contributing group expires. An empty group still advances retention. The group identifier is metadata, not a Datalog term. Caller-owned fixed storage bounds groups, raw contributions, unique facts and interned text separately. Rejection preserves the committed input, result and cursor. The earlier single-fact window, Datalog syntax, consumer API v1, backend ABI 3 and program ABI 1 remain unchanged. Python and JavaScript do not expose this adapter.

0.8.0

The native C SDK adds a last-N single-fact event window. It inserts a generated integer occurrence ID as the first term of each accepted fact, retains the last N accepted events and recomputes the complete input snapshot on each push. A rejected push does not expire an event or advance the ID. The adapter borrows two sessions and uses caller-owned bounded storage; it does not allocate on its own init/push/read/close path. New read-only accessors report committed input text usage and expose ordered raw input facts. The adapter is not an incremental solver or a Python/JavaScript binding. Datalog syntax, consumer API v1, backend ABI 3 and program ABI 1 remain unchanged.

0.7.1

MAELYS_DATALOG_PUBLIC_ALLOW_NONE names the absence of optional manifest loading permissions. Its value is permanently 0u: replacing a literal zero with the name changes neither behavior nor ABI.

The WebAssembly solve path now retains a diagnostic when evaluation fails. A capacity or depth failure therefore names the category, and includes the observed count and limit when the solver provides them. Invalid lifecycle state also names its missing precondition. No public signature, export, program identity, consumer API version, or backend ABI changes in 0.7.1.

0.7.0

The reference backend adds the stratified integer aggregates min, max, and sum. They use the same contextual syntax, grouping and strict stratification as count, but their capabilities are independent:

OperatorCapabilityPublic IR kind
countMAELYS_DATALOG_CAP_AGGREGATESMAELYS_DATALOG_IR_COUNT (5)
minMAELYS_DATALOG_CAP_MINMAELYS_DATALOG_IR_MIN (6)
maxMAELYS_DATALOG_CAP_MAXMAELYS_DATALOG_IR_MAX (7)
sumMAELYS_DATALOG_CAP_SUMMAELYS_DATALOG_IR_SUM (8)

CAP_AGGREGATES remains count-only; it is not an umbrella for the three new operators. CAP_ALL now includes every known bit and has value 4095. A compiled program records the operators it requires, and session creation rejects a backend missing any one of them before preparation.

Consumer API v1, backend ABI 3 and program ABI 1 layouts remain unchanged. Extension code with exhaustive switches must handle or explicitly reject the new IR, premise and Why-false obstacle alternatives. Why-true can emit kind=min, kind=max, and kind=sum; Why-false can emit the corresponding *-mismatch alternatives plus min-empty and max-empty. See the 0.7.1 changelog for the complete migration contract.

0.6.0

The reference backend supports stratified distinct count. MAELYS_DATALOG_CAP_AGGREGATES is an optional capability for this count contract only. A compiled count program records this requirement automatically. Session creation checks it against the selected backend before calling that backend's preparation function; an unsupported backend returns UNSUPPORTED. Loading the policy does not perform that backend check.

Consumer API v1, backend ABI 3 and program ABI 1 layouts are unchanged. Extension authors must handle or reject MAELYS_DATALOG_IR_COUNT (5). Native explanation integrations must also account for MAELYS_DATALOG_EXPLANATION_PREMISE_COUNT (5) and MAELYS_DATALOG_WHY_FALSE_OBSTACLE_COUNT_MISMATCH (6). Why-true records the count observed in its frozen snapshot; Why-false can report a count-mismatch alternative. Programs without aggregates emit none of these alternatives. See the 0.6.0 migration notes.

0.5.0

One addition, and one change to an error code. API v1 and backend ABI 3 are unchanged.

An explanation workspace owned by the session. maelys_datalog_session_config_set_explanation_workspace(config, kinds) makes a session reserve, once at creation, the storage that any Why-true or Why-false explanation of the reference backend can need; ..._set_explanation_storage() lets the application supply that memory instead. Nothing is reserved by default. With a workspace, the existing maelys_datalog_result_explain_true_text() and ..._false_text() make no allocator call and keep the explanation prepared between the measuring call and the rendering call of the same query, so the measure-then-render pattern costs one exploration instead of two. Any other explanation request on the session replaces that one-entry cache; releasing the result clears it. A kind left out of the configured mask answers UNSUPPORTED rather than falling back to allocation.

STORAGE_TOO_SMALL. Storage too small for a preparation now returns this new status, appended to the enumeration, from prepare_explanation(), explain_text_in() and a session creation with borrowed storage. A text buffer too short still returns PAYLOAD_TOO_LARGE, and a document with status=truncated is still a successful outcome. Code that matched PAYLOAD_TOO_LARGE for the storage case, or switches exhaustively on the status, has to update.

0.4.1

Three additions on the explanation path, still API v1 and backend ABI 3.

One call, no allocation. maelys_datalog_result_explain_text_in() prepares, measures, writes and releases an explanation in storage the caller supplies, in one call: no handle survives, even when the write fails, and the reference engine makes no allocator call. A short text buffer returns PAYLOAD_TOO_LARGE with the required length; storage too small for the preparation returns STORAGE_TOO_SMALL (since 0.5.0; PAYLOAD_TOO_LARGE in 0.4.x) and leaves the required length untouched, because nothing was prepared. The prepared functions of 0.4.0 remain the path for writing one explanation several times without rebuilding it.

A bound to size storage once. maelys_datalog_session_explanation_storage_bound() returns, for the reference backend and the loaded profile, the largest storage any result of that session can require for Why-true or Why-false. Size a static arena from it at startup instead of querying each result; any other backend answers UNSUPPORTED, since the backend ABI only knows the exact need of a live result.

An aligned declaration. MAELYS_DATALOG_EXPLANATION_STORAGE(name, bytes) declares a byte array aligned for any explanation storage, in C11 and C++17, from a positive integer constant. It hides no allocation and no lifecycle.

0.4.0

The consumer API is still version 1; 0.4.0 only adds to it. Every addition below is declared in <maelys/datalog.h>, and none changes an existing signature or structure layout.

Bounded input buffer. maelys_datalog_input_edb_storage_requirements() reports the bytes and alignment a buffer needs for a fact capacity and a text budget; maelys_datalog_input_edb_init() places the buffer in storage the application owns, and maelys_datalog_input_edb_create_with_capacity() makes exactly one allocation for it. maelys_datalog_input_edb_add_fact() and maelys_datalog_input_edb_add_facts() copy predicate names and symbols into the buffer, validate a whole batch before writing, and append nothing on failure. maelys_datalog_session_solve_edb() solves from the buffer with the same result lease as maelys_datalog_session_solve().

Session configuration. maelys_datalog_session_config_create() and its setters state the capabilities a session requires and an optional work budget; maelys_datalog_session_create_configured() copies those values at creation and answers UNSUPPORTED rather than degrading. maelys_datalog_session_execution_fingerprint() binds the backend identity and options to the policy identity.

Limits and counts. maelys_datalog_limit_get() returns the capacities of the loaded library by an append-only key, so applications size buffers from the library rather than from constants. maelys_datalog_result_derived_fact_count() counts every distinct derived fact of a result, including non-query relations.

Prepared explanations. The five explanation functions prepare a Why-true or Why-false document once in storage the caller sizes with maelys_datalog_result_explanation_storage_requirements(), then measure and write its text as often as needed; the reference engine makes no allocator call on that path. A prepared explanation leases its result: maelys_datalog_result_free() refuses until every one is released. The existing *_explain_*_text calls remain and now run on the same path.

Source conveniences. <maelys/datalog_builders.h>, included by the main header, adds C and C++ initializers for predicate declarations (MAELYS_DATALOG_EDB, MAELYS_DATALOG_IDB_QUERY, MAELYS_DATALOG_POLICY_FACT and their variants) and symbol values, plus C11-only MAELYS_DATALOG_ADD_FACT, MAELYS_DATALOG_ADD_FACTS and MAELYS_DATALOG_QUERY, which infer the term kinds from the argument types. They export no symbol and change no ABI.

0.3.1

The 0.3.0 GitHub release was complete, but its npm channel did not publish: the channel script passed a tarball path that npm interpreted as a GitHub repository shorthand. 0.3.1 corrects that path for the tagged publication workflow. The fix concerns distribution, not the Datalog language or engine behavior. See the 0.3.1 source changelog.

0.3.0

Releases moved to the shared maelys-release workflow. Each native or WebAssembly target produces its own immutable receipt; channel publication is recorded separately, after it succeeds. The MAELYS-DATALOG-v2 specification also gained explicit licensing: CC BY 4.0 for explanatory prose, MIT for grammars and test corpus, while the engine remains MPL 2.0. These are release-engineering and documentation changes, not new language syntax. See the 0.3.0 source changelog.

0.2.0

The engine gained the common extension-declaration ABI v1: extensions can register named frontends, solver backends, join planners and context-local filters through opaque native contexts. Registration is atomic, catalogues are immutable after setup, and existing global and typed APIs remain available. Four standalone extension starters and an installed-SDK conformance kit accompany the API.

The release series dropped the -alpha suffix; the 0.x version already signals that minor releases may break compatibility. The npm channel moved to GitHub Packages because the earlier npmjs.com channel had never published. See the 0.2.0 source changelog.

0.1.0-alpha.4

Backend ABI v2 added the optional EXPLAIN_FALSE capability and a read-only Why-false text API. The reference backend supported it; the naive example backend answered UNSUPPORTED, and ABI v1 backend descriptors needed rebuilding. This release also introduced validated public program IR, selectable frontends and backends, capability negotiation, module SDKs, and separate program and execution fingerprints. The later 0.4.0 release changed the explanation document envelope, so consumers should follow the current explanation reference rather than copy an alpha-era text parser. See the alpha.4 source changelog.

0.1.0-alpha.3

The WebAssembly build now links the string-filter implementation already present in native builds. The preceding alpha.2 workflow had failed on undefined filter symbols, so alpha.2 did not produce a complete release. See the alpha.3 source changelog.

0.1.0-alpha.2

The engine was relicensed from MIT to MPL 2.0, aligning it with the other Maelys repositories. The vendored yyjson library retained its MIT license. This tag made no code change and, as noted above, its WebAssembly release workflow failed; do not treat it as a complete distribution. See the alpha.2 source changelog.

0.1.0-alpha.1

The first public alpha introduced the bounded, deterministic Datalog engine: native C11 and Python, JavaScript, WebAssembly and WASI bindings; semi-naive fixed-point evaluation with stratified negation; SMALL and LARGE memory profiles; policy identity, diagnostics, proofs and decision receipts. This historical entry is preserved in the engine changelog; it is not a promise that every early-alpha artifact remains available.