defmodule Lockstep.MixProject do
use Mix.Project
@version "0.1.0"
@source_url "https://github.com/b-erdem/lockstep"
def project do
[
app: :lockstep,
version: @version,
elixir: "~> 1.15",
start_permanent: Mix.env() == :prod,
description: description(),
package: package(),
deps: deps(),
docs: docs(),
elixirc_paths: elixirc_paths(Mix.env()),
name: "Lockstep",
source_url: @source_url
]
end
def application do
# `:inets` and `:ssl` are needed by `Lockstep.LLMExplainer` (the
# optional Anthropic Claude integration). They live in OTP and
# cost nothing extra to declare; if `LLMExplainer` is never used,
# they just sit idle.
[extra_applications: [:logger, :compiler, :syntax_tools, :inets, :ssl]]
end
defp deps do
[
{:ex_doc, "~> 0.31", only: :dev, runtime: false},
{:cachex, "~> 4.1", only: :test},
{:telemetry, "~> 1.0", only: :test},
# ex_rated needs Ex2ms (match-spec macros) for delete_bucket/prune.
# We don't call those, but the `import Ex2ms` inside other
# functions still requires the module to be loaded at compile time.
{:ex2ms, "~> 1.5", only: :test},
# groot needs HLClock for hybrid logical clock timestamps.
{:hlclock, "~> 1.0", only: :test},
# delta_crdt: real version for clean repro of the
# set_neighbours+failed-send crash (test/delta_crdt_real_test.exs).
{:delta_crdt, "~> 0.6", only: :test},
# Lockstep.LLMExplainer (optional). If a host app already has
# Jason in its deps, the explainer activates; otherwise it
# silently skips. We also keep it for our own tests.
{:jason, "~> 1.4", optional: true}
]
end
defp description do
"Coyote-style controlled concurrency testing for the BEAM. " <>
"PCT/POS scheduling, schedule shrinking, trace replay, " <>
"Elixir + Erlang AST rewriters, and ETS / atomics / " <>
"persistent_term sync points -- so message-passing AND " <>
"shared-state races surface deterministically."
end
defp package do
[
maintainers: ["Baris Erdem"],
licenses: ["Apache-2.0"],
links: %{
"GitHub" => @source_url,
"Changelog" => @source_url <> "/blob/main/CHANGELOG.md"
},
files: ~w(lib LICENSE mix.exs README.md CHANGELOG.md
CONTRIBUTING.md AGENTS.md METHODOLOGY.md skill)
]
end
defp docs do
[
main: "readme",
extras: [
"README.md",
"CHANGELOG.md",
"CONTRIBUTING.md",
"AGENTS.md",
"METHODOLOGY.md",
"skill/lockstep/SKILL.md": [filename: "skill", title: "Skill (Anthropic)"],
"mcp_server/README.md": [filename: "mcp_server", title: "MCP Server"]
],
source_ref: "v#{@version}",
source_url: @source_url,
groups_for_modules: [
"Runtime API": [
Lockstep
],
"OTP wrappers": [
Lockstep.GenServer,
Lockstep.GenStatem,
Lockstep.Agent,
Lockstep.Task,
Lockstep.Task.Supervisor,
Lockstep.Registry,
Lockstep.Supervisor
],
"NIF wrappers": [
Lockstep.ETS,
Lockstep.Atomics,
Lockstep.PersistentTerm
],
"Test ergonomics": [
Lockstep.Test,
Lockstep.Linter
],
"Compile-time rewriters": [
Lockstep.Rewriter,
Lockstep.ErlangRewriter,
Lockstep.MixCompiler
],
"Engine internals": [
Lockstep.Controller,
Lockstep.Runner,
Lockstep.Strategy
],
Strategies: [
Lockstep.Strategy.Random,
Lockstep.Strategy.PCT,
Lockstep.Strategy.FairPCT,
Lockstep.Strategy.POS,
Lockstep.Strategy.Replay
],
"Trace + replay + shrink": [
Lockstep.Trace,
Lockstep.Replay,
Lockstep.Shrink
],
Errors: [
Lockstep.BugFound,
Lockstep.ReplayDivergence
]
]
]
end
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
end