What works today, what is experimental or partial, and where the gaps are written down. The current release number, the planned list and the stability promise’s one-paragraph summary stay on the README.
docs/1.0-readiness.md states plainly what the
stability promise made at 1.0.0 covers — the DSL and runtime API in
the DSL reference won’t change in a breaking way
without a major-version bump — and what it explicitly doesn’t cover yet
(query DSL aggregation beyond count/median/group_by, Rust codegen for
read_model beyond its proven subset, Rails integration, Drivers, the
outbox’s standalone relay — see that doc’s “Explicitly not covered”
section). ADR 0025,
the breaking DSL redesign the 1.0.0 release was blocked on, is fully
landed — the README’s quickstart shows the
current syntax.
Exercised in CI on every push (the whole suite, alongside
hecks model_check and hecks fuzz_run.fuzz):
The first item, on the in-memory adapter, in one sitting: a declared rule refuses a command before it runs, and the same command goes through once the rule holds.
order = Order.create_pizza!(name: "Quattro", pizza: { price_cents: { cents: 1500 }, size: "large" })
order.purchase!(customer_name: "Sam", amount: { cents: 1500 }) # ~> GivenNotMet: a pizza needs at least one topping
order.add_topping!(topping: "Olive", amount: 2)
order.purchase!(customer_name: "Sam", amount: { cents: 1500 })
order.status # => "sold"
hecks fuzz_run.fuzz adapter=sqlite or adapter=postgres
— Postgres needs a real reachable local server and is noticeably
slower per seed, so pass smaller --seeds/--steps than the default
sweep). A reference-hop query field (owner/field) is queried, not
just indexed, on every SQL adapter: the hop folds into a local in:
clause before any adapter sees it
(spec/adapters/query_hop_agreement_spec.rb).read_model can declare count,
median and group_by, on Ruby and on the generated Rust runtime;
there is no sum, avg, min or max, and a plain query reduces
nothing. A group_by leaf holds one row: when several rows share a key
path the ask refuses, on every adapter and in Rust, rather than keeping
the first (ADR 0061).PostgresEra’s schema-evolution/translation system works and is
exercised in CI; the migration/rekey data-loss findings tracked
against it (era-migrated deletes resurrecting, rekey SQL invisible
to the approval digest, a dotted compute exempting its whole
parent attribute from the equivalence gate) are fixed and
live-verified against real Postgres as of 2026-08-27 — see
docs/future-features.md’s “Bug audits” section for the specifics
and what’s not independently re-checked yet. A compute whose
source is a dotted member fires in the compiled SQL like any other, so
its mint converts the record.read_model queries (see
Projections for its shape); one outside that subset
is refused in Rust with a “not generated for this domain” error and
still requires Ruby.Runtime::Outbox): a command’s save, its events, and one
pending row per policy/process-manager consumer commit together on
Sqlite/Postgres/PostgresEra (Memory keeps in-process rows); the
dispatcher drains them inline, the next boot redrives pending rows
and surfaces claimed ones. Heki/LocalStorage/D1 have no outbox yet
(boot warns); the relay is the dispatching thread plus boot-time
reconciliation, not a separate process.The planned-or-research-only list lives on the
README, where
spec/readme_planned_adrs_spec.rb checks it.
docs/future-features.md is the project’s
own running list of gaps, ranked by how much depends on them — read it
before assuming a capability exists that isn’t demonstrated here.