All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[1.0.0] - 2026-09-20
Stable SemVer baseline for the surface frozen in 0.12.0. No Consumer / Event / Query / Backend-callback meaning changes. Optional ops remain non-SemVer-core.
See 0.12 → 1.0 migration and ADR 030.
Added
- ADR 030 (SemVer 1.0): major / minor / patch policy for the frozen inventory
- 0.12 → 1.0 migration
Changed
- Public API guide and host docs describe 1.0 SemVer (not a freeze candidate)
- Roadmap: 1.0 done; multi-node Mnesia and Flow package remain deferred
Kept (compatibility)
- Legacy
%{after_sequence: n}page cursor {Rheo, url: …}Mongo shorthand whenmongodb_driveris present
[0.12.0] - 2026-09-20
API freeze candidate before 1.0. No Consumer / Event / Query / Backend-callback meaning changes from 0.11.1. HexDocs publishes the frozen surface; optional ops remain non-SemVer-core.
See 0.11.1 → 0.12 migration and ADR 029.
Added
- ADR 029 (API freeze candidate) with module inventory
- Public API guide and portable error-atom table
- Conformance unavailable group: dead-handle
ping→:backend_unavailable - Tutorial 17 (GitHub archive): freezing Rheo before 1.0
Changed
- HexDocs
groups_for_modules(Facade / Consume / Values / Backend / Runtime / Ops) +filter_moduleshide table engine and driver/client modules; Mix inspect tasks publish under Ops (optional, not SemVer-core) Rheo.InstanceandRheo.Backend.Mnesia.Storeare internal (@moduledoc false)- Roadmap: 0.12 done; next is 1.0 SemVer (multi-node Mnesia still deferred)
Kept (compatibility)
- Legacy
%{after_sequence: n}page cursor {Rheo, url: …}Mongo shorthand whenmongodb_driveris present
[0.11.1] - 2026-09-20
Correctness patch on v0.11.0: composite page cursors, a single Group poll timer, Registry-based group names, ETS/Mnesia indexing via a shared table engine, and ops/CI follow-through.
Changed
query_page/2next_cursoris%{partition => after_sequence}(legacy%{after_sequence: n}still accepted on apply)fetch/3of a missing stream returns:stream_not_found(group lookup no longer wins)- ETS and Mnesia declare
atomic_compare_and_set: false - Mongo declares
distributed: true - Groups register in an application-level
Rheo.Registryvia tuple - In-flight write timeouts map to
{:ambiguous, :timeout}on Mongo/Redis/Ecto
Fixed
- Group poll timer multiplication; missing events dead-letter instead of failing the fetch; Mongo client exits no longer crash the Group
- ETS/Mnesia claim/query/frontier scans; Mix inspect tasks when no instance is
running;
mix test.unitwithout Mongo/Redis - ETS/Mnesia range reads walk the
ordered_setkey range instead of filtering a full-tableselect, soread,materialize, andfetchcost O(range) rather than O(events in the stream). Consume throughput is now flat to at least 24k events (was degrading ~4x between 1k and 12k) fetch/3claims a batch in one ordered pass. Restarting the scan per lease re-walked the already-leased prefix, making a single fetch quadratic in:limit;fetch(limit: 4000)used to exceed the ETS call timeout and return:backend_unavailableRheo.Producer.drain/2returns{:error, :already_draining}instead of overwriting a pending drain's caller, matchingRheo.Group.drain/2Rheo.LiveDashboard.Pagecaches its stream/group/info walk for 2s, so re-sorting or re-paging the table does not replay N+1 backend calls
[0.11.0] - 2026-09-19
Mnesia backend: durable ETS-shaped OTP :mnesia store (single-node
disc_copies). No Consumer / Event / Query breaks.
See 0.10 → 0.11 migration and ADR 028.
Added
Rheo.Backend.Mnesia(durable: true,distributed: false) with full Backend + ops inspect callbacks- Mnesia guide; multi-node backend comparison in building-your-own-backend / configuration / capabilities docs
- ADR 028; migration
0.10-to-0.11
Changed
- Roadmap: Mnesia is 0.11; API freeze remains 0.12; multi-node Mnesia deferred
- Version bump only for hosts that do not opt into the Mnesia backend
[0.10.0] - 2026-09-18
Ops surface for an embedded Rheo. Inventory, dead-letter (DLQ) listing, group health, optional metrics/LiveDashboard, and Mix inspect tasks — without changing Consumer / Event / Query semantics or inventing a control plane.
See 0.9 → 0.10 migration and ADR 027.
Added
Rheo.list_streams/1,Rheo.list_groups/2,Rheo.dead_letters/3,Rheo.group_info/3plus%Rheo.DeadLetter{}/%Rheo.GroupInfo{}- Backend optional callbacks implemented on ETS, Mongo, Ecto, Redis
- Optional
Rheo.Telemetry.Metrics(requirestelemetry_metrics) - Optional
Rheo.LiveDashboard.Page(requiresphoenix_live_dashboard) - Mix tasks:
rheo.streams,rheo.lag,rheo.dead_letters,rheo.group_info,rheo.bench - Ops Livebook (
notebooks/ops.livemd); LiveDashboard Playground demo (notebooks/live_dashboard.livemd,examples/live_dashboard_ops.exs); ops guide, ADR 027, migration0.9-to-0.10
Changed
- Roadmap: Ops is 0.10; Mnesia deferred to 0.11
- Version bump only for hosts that ignore the new inspect APIs
0.9.0 - 2026-09-18
Redis Streams native backend. v0.8 prepared Model C receipts and the semantic
contract; v0.9 proves them on Redis without changing Rheo.Consumer,
Rheo.Event, or Rheo.Query meaning.
See 0.8 → 0.9 migration and ADR 026.
Added
Rheo.Backend.Redis— optional{:redix, "~> 1.5"}; Redis Streams consumer groups with portableevent.sequenceandlease.receipt= entry id- Fenced settle (fence hash +
XACK); reclaim viaXPENDING/XCLAIM Rheo.Backend.Wakeup+ Group reader Task (ADR 025); polling remains fallback- Redis guide, ADR 026, conformance suite tagged
:redis - Redis property + Broadway/Producer smoke suites; Article 16
- docker-compose
redis:7service;RHEO_REDIS_URL
Changed
- Version bump only for non-Redis hosts — no Consumer API breaks from 0.8
0.8.0 - 2026-09-17
Architectural reset. v0.1–v0.7 were successful discovery releases; v0.8 consolidates the abstractions learned from MongoDB, ETS, Ecto, partitions, replay, GenStage, and Broadway, and validates that the same settlement model can support Flow and native-stream backends such as Redis Streams — without shipping Redis or Flow yet.
See 0.7 → 0.8 migration and ADR 019.
Added
%Rheo.Lease{}.receipt— opaque backend-native settle identity (ADR 021)Rheo.Backend.Capabilities— validated guarantees vs mechanisms struct (ADR 023); unknown keys, non-boolean values, and disabled invariants raiseRheo.Settle— portable settlement vocabulary (:stale_lease,:receipt_mismatch,:backend_unavailable,{:ambiguous, _},{:failed, _},{:invalid, _}) and thenack_after_failed_ack?/1policyRheo.Inflight(renew_all/2,pop/2, capacity) andRheo.Backoff, shared byRheo.GroupandRheo.ProducerRheo.Producer.ack/3,nack/4,reject/4— settle durably and release the producer's inflight entry in one call- Telemetry
[:rheo, :handler, :error]when a handler raises or throws - Conformance suite grouped by guarantee; native-stream test double
(
Rheo.Backend.NativeStreamDouble) runs the full suite; flaky-backend double for settle failure injection - Property tests on ETS (partition routing, sequences, frontier, group isolation, fencing, replay, paging); failure-injection tests (settle failures, backend crash, drain)
- Flow readiness tests (
Rheo.Producer→ Flow map / partition / reduce / window / crash-before-settle) - Multi-instance ETS + SQLite isolation tests
- Livebook demos split into Quickstart, Concepts, Pipelines, and Backends
(
notebooks/*.livemd;rheo_demo.livemdis the index) - Optional integrations (ADR 020):
mongodb_driver,ecto/ecto_sql,gen_stage, andbroadwayareoptional: true;Rheo.Backend.Mongo,Rheo.Backend.Ecto,Rheo.Producer, andRheo.Broadwaycompile only when their dependency is present.mix core.checkproves the core-only build - ADRs 019–025; Flow and Redis readiness spikes; Article 15
Changed
Rheo.Consumerhandlers return:ack | {:retry, reason} | {:reject, reason}and receive a read-only context;setup/1must return a map (ADR 022)use Rheo.Consumeris a child spec forRheo.Group; the host supervisor owns the group and a second start returns{:error, {:already_started, pid}}- Groups are registered under a local name; the per-instance
Registryis gone Rheo.Group.drain/2andRheo.Producer.drain/2no longer block the process while waiting; the group traps exits and drains on supervisor shutdown- After a failed ACK the group nacks only definite failures; unavailable or ambiguous outcomes are left to lease expiry (fencing protects a committed ACK)
Rheo.Backend.capabilities/0returns the struct;Rheo.Backend.Ecto.capabilities/1too- Backends map driver errors into
Rheo.Settlereasons instead of returning exception structs;[:rheo, :fetch, :error],[:rheo, :ack | :retry | :reject, :error], and renew:resultmetadata carry the classified reason Rheo.Broadway.Acknowledgersettles through the producer helpers{Rheo, opts}requires:backend; theurl:shorthand raises unlessRheo.Backend.Mongois availableRheo.Query.new/2normalizesorder_bydirections1/-1- Stored nack / reject reasons are truncated diagnostics, not verbatim terms
- Logs carry stream / group / event ids, not handler return values
Removed
Rheo.Consumer.Bridgeand the silent multi-bridge join of a shared group- Flat capability maps (
to_legacy_map,normalize) - The unused
Rheo.Backend.Wakeupcontract (ADR 025 is a proposal for v0.9)
0.7.1 - 2026-09-17
Documentation-only release. No runtime API changes. Prefer
{:rheo, "~> 0.7.0"} (or "~> 0.7.1").
Added
- Practical HexDocs Guides: Quick Start, Configuration, Consumer Groups, Enqueuing, Dequeuing, Replay, Querying, Partitions and lag, ETS, Mongo, Using Ecto, Broadway, GenStage, Building your own backend
Changed
- HexDocs extras regrouped into collapsible groups: Guides: Introduction / Advanced / Cookbook, Migrating from previous versions, Design: Architecture / ADRs / Tutorials
- Mermaid diagrams render on HexDocs via ExDoc's
before_closing_body_taghook - README documentation index updated for the new guide layout
- Livebook demo titled/versioned for v0.7.1 (Broadway + Ecto sections match the v0.7 API)
0.7.0 - 2026-09-16
GenStage / Broadway interoperability. Additive — Rheo.Consumer and
Rheo.Group are unchanged. See
0.6 → 0.7 migration.
Added
Rheo.Producer—GenStageproducer that turns demand intoRheo.fetch/3and emits%Rheo.Lease{}. Bounds unsettled leases with:max_demand, renews inflight leases everylease_ms / 2, drops stale leases for redelivery, polls when idle, and backs off exponentially on fetch errors. Options::rheo,:stream,:group,:max_demand,:lease_ms,:poll_ms,:consumer_id,:partitions,:on_failure,:nameRheo.Producer.confirm/2— tells the producer a lease was settled durably so renewal stops and a demand slot is releasedRheo.Producer.drain/2,inflight_count/1,config/0, and Broadway'sprepare_for_draining/1callbackRheo.Broadway.transform/2— Broadway:transformerbuilding a%Broadway.Message{}withdata: lease.eventandmetadata: %{lease:, stream:, group:, partition:, attempt:}Rheo.Broadway.Acknowledger— successful →Rheo.ack/2; failed →Rheo.nack/3, orRheo.reject/3withon_failure: :reject(settable per message viaBroadway.Message.configure_ack/2)Telemetry
[:rheo, :producer, :start | :stop]and[:rheo, :broadway, :ack | :retry | :reject]- ADR 018; tutorial article 14
- Livebook Broadway + ETS section; 0.6 → 0.7 migration
Changed
gen_stageandbroadwayare dependencies, becauseRheo.ProducerandRheo.Broadway.Acknowledgercompile against those behaviours rather thanCode.ensure_loaded?/1guards. Arheo_broadwaypackage split is deferred — see ADR 018 "Alternatives".- ADR 007 now points at ADR 018: GenStage is still not used internally, but it is a supported consumption surface
0.6.0 - 2026-09-16
Ecto SQL backend for PostgreSQL and SQLite. See 0.5 → 0.6 migration.
Added
Rheo.Backend.Ecto— fullRheo.Backendon a host-ownedEcto.Repo:{Rheo, backend: {Rheo.Backend.Ecto, repo: MyApp.Repo}}- PostgreSQL (
Ecto.Adapters.Postgres) withFOR UPDATE SKIP LOCKEDclaims andjsonbpayload/metadata columns; SQLite (Ecto.Adapters.SQLite3) for durable zero-service local runs Rheo.Backend.Ecto.Server— configuration holder whose registered name is the opaque backend handle (same pattern as Mongo and ETS, ADR 010)Rheo.Backend.Ecto.Migrations— idempotent dialect-aware DDL forrheo_streams,rheo_stream_sequences,rheo_events,rheo_groups, andrheo_deliveries, plusRheo.Backend.Ecto.Migrations.V1formix ecto.migratemix rheo.ecto.gen_migration— generates a host migration that delegates to the library, so schema changes ship as Rheo codeRheo.Backend.Ecto.Codec— JSON and timestamp encoding per dialectRheo.Backend.Ecto.capabilities/1— dialect- and option-aware flags (distributedfollows the dialect,notificationsfollowsnotify: true)- Optional
notify: true→NOTIFY rheo_eventson append (PostgreSQL only) - Optional
prefix:to hold the Rheo tables in a PostgreSQL schema - Backend conformance runs on SQLite by default and on PostgreSQL when
RHEO_POSTGRES_URL(orDATABASE_URL) is set - ADR 017; tutorial article 13
- Livebook optional SQLite/Ecto section; 0.5 → 0.6 migration
Changed
ectoandecto_sqlare now dependencies;postgrexandecto_sqlite3are optional so the host picks its own driver. Splitting Rheo into per-backend packages is deferred — see ADR 017 "Alternatives".- ADR 011 allows an optional
capabilities/1for backends whose flags depend on runtime configuration;capabilities/0remains the static self-description docker-compose.ymland CI add a PostgreSQL service
0.5.0 - 2026-09-16
Partitions, per-partition sequences, contiguous ACK frontier, and lag. See 0.4 → 0.5 migration.
Added
- Configurable
partition_countwith per-partition sequence allocation - Deterministic key routing via
:erlang.phash2/2(Rheo.Partition) - Contiguous committed frontier per
(stream, group, partition)(ADR 016) Rheo.lag/3and%Rheo.Lag{}(sum of per-partition HW − frontier)- Static Group/Consumer
:partitionsassignment (:allor list) - Partition-scoped
replay/reset_group(:partition/:partitions) - Capabilities
partitions: true,contiguous_frontier: true - ADR 016; tutorial article 12
- Livebook section for multi-partition publish, frontier hole, and lag
Changed
- Group docs store per-partition
cursors/frontiers(legacynext_sequencemaps to partition0) - Stream docs store
next_sequencesmap - README / Livebook / changelog doc links stay on absolute HexDocs or GitHub URLs so hex.pm/packages/rheo does not 404 (same class of fix as 0.4.1)
0.4.1 - 2026-09-16
Fixed
- README documentation links use absolute HexDocs /
GitHub URLs. Relative
docs/…andnotebooks/…paths were rewritten by Hex torepo.hex.pm/preview/rheo/…and 404'd because those files are not in the package tarball (hex.pm/packages/rheo).
0.4.0 - 2026-09-16
Search, pagination/streaming, replay/reset, and event lineage — additive over v0.3.0. See 0.3 → 0.4 migration.
Added
- Query sequence bounds:
:after_sequence(exclusive),:until_sequence(inclusive) - Opaque page cursors on
%Rheo.Query{};%Rheo.Page{events, next_cursor} Rheo.query_page/2andRheo.stream_query/2(bounded page size)Rheo.create_group/3start cursors::start_after,:start_atRheo.replay/3— reopen deliveries (from_sequence:,from:,query:)Rheo.reset_group/3— destructive per-group delivery reset (confirm: true)- Backend callbacks
replay/4,reset_group/4; capabilityreplay: true Rheo.Event.Lineagehelpers forcorrelation_id,causation_id,producer,schema,schema_version- Telemetry:
[:rheo, :group, :replay],[:rheo, :group, :reset] - ADR 015; tutorial article 11
- Conformance + unit coverage for search/replay on ETS and Mongo
- 0.3 → 0.4 migration
Changed
- Expanded
Rheo.Querydocumentation with filters, ranges, pagination examples - Livebook demo documents search/replay APIs (still defaults to ETS)
Migration
- Non-breaking for v0.3 callers: existing
Rheo.query/2{:ok, list}unchanged - Prefer a new group with
:start_after/:start_atfor safe replay isolation - Never call
reset_groupwithoutconfirm: true
0.3.0 - 2026-09-15
Added
Rheo.Backend.ETS— ephemeral per-instance ETS backend (no Docker)- Backend
capabilities/0callback; Mongo and ETS implementations - Backend conformance suite (BackendContract ExUnit template) for ETS and Mongo
- ADRs 011, 012, 014; tutorial article 10
- Docker-free
mix rheo.demo(default ETS;RHEO_BACKEND=mongofor Mongo)
Changed
- Application auto-start can use
config :rheo, backend: Rheo.Backend.ETS - Livebook demo defaults to ETS
0.2.0 - 2026-09-15
Added
- Named Rheo instances (
{Rheo, name:, backend: {Mod, opts}}) andrheo:opts Rheo.Instance,Rheo.Group,Rheo.GroupSupervisor- Real consumer
concurrency, lease renewal, fetch backoff, drain - Portable
%Rheo.Query{}andRheo.Backend.Mongo.Codec Rheo.renew/2; persistence-error telemetry- ADRs 009, 010, 013; migration guide; tutorial article 9
Changed
Rheo.Consumerstarts a Group via a bridge process (no poll GenServer)- Backend callbacks take opaque
handleinstead of topology GenServer Rheo.Eventno longer decodes Mongo documents
Breaking
- Supervision options: prefer
name+backendtuple; dropsupervisor_name - Query
:sortremoved; use:order_by - Event document decoding removed from
Rheo.Event; useRheo.Backend.Mongo.Codec.event_from_doc/1
0.1.0
Initial Mongo-backed MVP: streams, groups, leases, Consumer, docs, Livebook.