Skip to content

Rete 0.3.6

Choose a tag to compare

@github-actions github-actions released this 21 Oct 12:36
· 75 commits to main since this release
25a4331

Where 0.3.6 is published: every channel. crates.io (rete-core,
rete-graph, rete-cli, rete-wasm), PyPI and npm (rete-graph), the
GitHub release with its native archives, browser bundle, Blender add-on and
the Claude Desktop extension (rete-0.3.6.mcpb, and rete.mcpb behind the
releases/latest/download/rete.mcpb link), the container images on GHCR
(rete-cli, rete-relay, rete-dev), the Pyodide fallback wheel, and the
desktop File Explorer installers. The extension is no longer uploaded to the
bucket; the copies there stay at 0.3.5.

What 0.3.6 changes on top of 0.3.5:

  • Behaviour change: property-path alternatives and sequences keep their
    duplicates.
    ?s (:a|:b) ?o and a sequence inside an alternative now
    return one solution per matching path, as SPARQL 1.1 §18.4 defines them,
    where 0.3.5 returned each pair once. Counts over such paths can go up
    (DataCite: 8,897 → 8,929 for ?s (dcite:cites|dcite:references) <doi>);
    add DISTINCT to count nodes rather than paths. *, +, ? and
    negated property sets are unchanged. Details below.
  • SPARQL runs under a memory budget. rete sparql and rete sparql-url
    take --memory-budget-mb (default 4096, 0 = unlimited), and
    Rete::open_ranged_lazy applies the same default, so the Python, R and
    Java clients and the relay are bounded too. rete verify streams the file
    instead of reading it whole.
  • Join planning follows the data's size. Lazy opens estimate each
    pattern from the tile directory and pick the join order and method from
    it; DataCite queries that ran out of memory at 16 GB now answer in seconds.
  • COUNT(DISTINCT …) is exact and bounded, spilling sorted runs to
    TMPDIR past the budget.
  • The Claude Desktop extension downloads from GitHub releases
    (https://github.com/caviri/rete/releases/latest/download/rete.mcpb).
  • Security: the TLS certificate checks are patched. rustls-webpki
    0.103.16 (RUSTSEC-2026-0382) and webpki-roots 1.0.10
    (RUSTSEC-2026-0381). These advisories are what kept 0.3.5 off crates.io,
    which goes from 0.3.4 straight to 0.3.6. Details below.

Repository-only changes in this release, with no effect on the published
packages: the DataCite converter keeps one identity per registered DOI and
guards its build (#312), and the dataset pipelines under scripts/ moved to
a separate dataset repository (#313).

Security

  • rustls-webpki 0.103.16 and webpki-roots 1.0.10 (were 0.103.15 and
    1.0.7–1.0.9 across the workspace, Python, R and File Explorer lockfiles),
    fixing RUSTSEC-2026-0382 (certificate verification could accept distrusted
    intermediates) and RUSTSEC-2026-0381 (the bundled roots trusted distrusted
    emSign intermediates) in the TLS stack behind remote reads over HTTPS. The
    browser engine does not link either crate.

Changed

  • The Claude Desktop extension downloads from GitHub releases. Every v*
    release attaches the bundle as rete-<version>.mcpb and, same bytes, as
    rete.mcpb, both in SHA256SUMS and both attested, so
    https://github.com/caviri/rete/releases/latest/download/rete.mcpb always
    serves the Latest release's build. The README, docs/agents.md and
    clients/mcpb/README.md link there. clients/mcpb/publish.sh, the manual
    R2 upload, is removed and is no longer a release step; the objects under
    https://data.graphplaza.com/mcpb/ are left in place, frozen at 0.3.5, so
    existing links keep working.

Fixed

  • Property-path alternatives keep SPARQL's duplicates. ?s (:a|:b) ?o
    is the union of the two branches (SPARQL 1.1 §18.4), so a pair both
    predicates connect is two solutions; rete evaluated every path as a set and
    returned it once. A sequence nested inside an alternative ((:a/:b)|:c) was
    deduplicated the same way. Both now keep their multiplicities; *, +,
    ? and negated property sets stay sets, as the spec defines them. On
    DataCite ?s (dcite:cites|dcite:references) <doi> now counts 8,929 — the
    1,218 cites plus 7,711 references of the equivalent UNION — instead of
    8,897 (32 records state both). Use SELECT DISTINCT to count nodes rather
    than paths.
  • COUNT(DISTINCT …) is bounded and exact. It kept every distinct value
    in an ordered set (about 40 bytes each), so COUNT(DISTINCT ?r) over the
    610 M PID relations of DataCite ran out of memory at 16 GB. Distinct values
    are now a sorted, deduplicated buffer of dictionary ids (8 bytes each); past
    an eighth of the memory budget (512 MiB by default, Rete::spill_threshold)
    it is written to TMPDIR as sorted delta-encoded runs and counted by
    merging them. That query now returns 609,765,497 (the card's count of
    dcite:PidRelation) in 47 s at 1.5 GB peak RSS, and the ten
    COUNT(DISTINCT ?s) invariant checks drop from 3.5–5.3 GB to 1.3–1.5 GB,
    with identical answers. A resident open spills at the same threshold when
    the command has a budget (rete sparql always does); the browser engine
    never spills.
  • Join order and join method follow the data's size. Without a resident
    pyramid (every lazy open, every file built with --memory-budget-mb) the
    planner ordered patterns by how many constants they had and pushed
    ?s a :Class to the end, so on DataCite ?s a dcite:Service ; dcite:publicationYear ?y started from the 109 M years and ran out of memory
    at 16 GB, although there are 517 services. The planner now estimates each
    pattern from the tile directory (tiles routed × triples per tile; no read,
    and per class), looks a pattern up per row when the rows found so far are
    at least 16 times fewer than the pattern (a bound subject becomes an SPO
    range read), streams the whole join when even the most selective pattern is
    large (per-row lookups, small patterns hashed, two large subject-sharing
    patterns merge-joined), and lands sub-select rows as dictionary ids instead
    of strings. On DataCite: the class × predicate joins run in 1.1–56 s within
    4.5 GB (were out of memory), ?r dcite:relationSubject <doi> . ?r ?p ?o in
    0.9 s (was out of memory, then 968 s), the bound-subject chains e_join_a/
    e_join_b in 0.9 s (were 32 and 54 s), ?s dcite:doi ?d . ?s dcite:fromSnapshot ?x in 17 s at 1.1 GB (was out of memory). Results are
    unchanged, except that a LIMIT without ORDER BY may return a different
    (equally valid) page.
  • rete sparql and every lazily-opened file now run under a memory
    budget.
    The dictionary chunk cache, the index tile cache and the raw block
    cache of a lazy open were unbounded on every query path (only rete export
    capped them), so a whole-graph scan kept everything it touched: on the 49 GB,
    9.53 B-triple DataCite file GROUP BY ?p was killed at 16 GB and a
    CONTAINS over every title peaked at 15.1 GB. rete sparql and
    rete sparql-url take --memory-budget-mb N (default 4096, 0 =
    unlimited) with the same split as rete export, and
    Rete::open_ranged_lazy applies the 4096 MiB default itself, so the Python,
    R and Java clients and the relay are bounded too (not the browser engine).
    The per-tile group directories that point lookups build now live in the tile
    cache and are evicted with their tile; they used to stay resident forever
    and could outgrow the tiles. The per-query term and number memos are capped
    at 64 MiB each. A local file goes to the lazy reader once it is larger than
    a quarter of the budget (1 GiB at the default, as before). Answers are
    unchanged (75 DataCite QA queries, 36 queries on three smaller files and
    the W3C suite compared). On DataCite, GROUP BY ?p now completes (876 s,
    1.1 GB peak RSS), the CONTAINS count peaks at 4.0 GB instead of 15.1 GB,
    and ?r dcite:relationSubject <doi> . ?r ?p ?o completes in 1.1 GB, though
    it still scans the whole graph until the join planner is fixed. See "Memory
    budget" in docs/sparql.md for what the budget does not cover.
  • rete verify streams. It read the whole file into memory, so a 49 GB
    file could not be verified in a capped container; it now hashes the sections
    in 8 MiB reads (rete_core::verify_ranged).

Install, artifact list, download verification and known limitations: release guide. Full history: CHANGELOG.md.