Contributing to Belay

Copy Markdown View Source

Thanks for looking under the hood. Ground rules that keep this codebase easy to work on:

Development

mix deps.get
mix test                # full suite against the in-memory adapter
BELAY_PG=1 mix test     # same suite against Postgres

The Postgres run expects a server at localhost:55433 (password belay):

docker run -d --name belay-postgres -e POSTGRES_PASSWORD=belay \
  -e POSTGRES_DB=belay_test -p 55433:5432 postgres:16

CI additionally runs the PostgreSQL suite against supported endpoints 14 and 18.

The rules that matter

  1. Storage semantics live once. Anything both adapters must agree on belongs in the pure shared-logic module (lib/belay/storage.ex) or in the shared test suite. If you add a storage operation, implement it in Memory and Postgres and cover it with a test that runs against both — the suite is the contract.
  2. Never read the wall clock in engine code. Take now as an argument (SQL included: $now parameters, not now()). Tests advance a Belay.Clock.Sim; a Process.sleep in a test is a review flag.
  3. No leaders. If your feature needs cluster-wide once-ness, express it as an idempotent operation deduped by the database (unique index, row-level atomicity), not by election.
  4. First-class columns over meta blobs. If the engine branches on it, it gets a column and an index, not a JSON path.
  5. Failure honesty. Document at-least-once edges and race windows in the moduledoc where they live. A known caveat in writing beats an implicit one in production.

Pull requests

  • One logical change per PR; tests required, on both adapters where storage is touched.
  • mix compile --warnings-as-errors must pass.
  • Public functions get @doc and specs; internal modules get @moduledoc false and a one-paragraph comment saying what they own.

Reporting issues

Include: Belay version, storage adapter, Postgres version, and — for engine bugs — the smallest failing scenario you can express with Belay.Testing.drain/2 and a SimClock. Security reports: email the maintainer rather than opening a public issue.