AshEx4pm

AshEx4pm is the Ash projection layer for ex4pm process evidence, admitted runtime capabilities, wasm4pm analysis, ferroplan planning, and receipted Ash actions.

The ownership boundary is deliberate:

Ash resource/domain
|
v
AshEx4pm
|
v
ex4pm
/ \
v v
wasm4pm ferroplan

wasm4pm and ferroplan own algorithms and planning semantics. ex4pm owns their runtime integration, admission, evidence, replay, and provider boundaries. AshEx4pm owns the Ash-facing projection. A capability being known or projected does not mean it is ALIVE, authorized, or allowed to perform DO.

Installation

def deps do
[
{:ash_ex4pm, "~> 26.10"}
]
end

AshEx4pm 26.10.2 continues to pin the published ex4pm 26.10.1 contract exactly:

{:ex4pm, "== 26.10.1"}

The patch component of ex4pm's CalVer is contract-bearing, so this project does not widen or invent compatibility with an unverified upstream release.

Documentation

The README is the entrypoint, not the full manual. Start with the Diátaxis index.

Canonical upstream documentation:

Minimal OCEL resource

Declare an ex4pm DSL block and explicitly register the notifier:

defmodule MyApp.Order do
use Ash.Resource,
domain: MyApp.Domain,
data_layer: Ash.DataLayer.Ets,
notifiers: [AshEx4pm.Notifier],
extensions: [AshEx4pm]
ex4pm do
activity(:order_created, on: :create)
end
actions do
defaults([:read, :destroy])
create :create do
primary?(true)
accept([:status])
end
end
attributes do
uuid_primary_key(:id)
attribute(:status, :atom, default: :pending, public?: true)
end
end

A matching post-commit notification builds an OCEL 2.0 envelope and delegates to Ex4pm.Stream.Ingest.ingest_envelope/1. A refused ingest does not roll back the already-committed Ash action.

Capability discovery

v26.10.2 adds a machine-readable projection registry:

AshEx4pm.capabilities()
AshEx4pm.capabilities(owner: :ferroplan)
AshEx4pm.capability(:ferroplan_plan)
AshEx4pm.capability_standing(:wasm_algorithms)

The important distinction is:

upstream capability
!= projected capability
!= admitted runtime capability
!= authorized consequence

The registry records the canonical owner, Ash projection, function/arity, boundary, authority semantics, DO authority, and documentation for each projected capability. See Capability reference.

wasm4pm through AshEx4pm.WasmRuntime

AshEx4pm.WasmRuntime delegates to ex4pm's canonical wasm runtime surface. It owns no wasm4pm semantics.

Representative calls:

AshEx4pm.WasmRuntime.available?()
AshEx4pm.WasmRuntime.standing()
AshEx4pm.WasmRuntime.algorithms()
AshEx4pm.WasmRuntime.statistics(:mean, [1, 2, 3])
AshEx4pm.WasmRuntime.forecast([1, 2, 3])

The wider wasm4pm substrate includes process mining, object-centric querying, statistics, forecasting, deterministic cognition and planning. Upstream existence does not imply that every capability is projected or ALIVE here; use the registry and live standing surfaces rather than README inference.

ferroplan through AshEx4pm

The stateless planning seam is AshEx4pm.FerroplanRuntime:

AshEx4pm.FerroplanRuntime.available?()
AshEx4pm.FerroplanRuntime.standing()
AshEx4pm.FerroplanRuntime.plan(domain, problem)
AshEx4pm.FerroplanRuntime.plan_production(domain, problem)

The stateful seam is AshEx4pm.FerroplanSessions:

{:ok, session} = AshEx4pm.FerroplanSessions.new(domain, problem)
AshEx4pm.FerroplanSessions.observe(session.id, observation)
AshEx4pm.FerroplanSessions.think(session.id)
AshEx4pm.FerroplanSessions.replan_following(session.id)
AshEx4pm.FerroplanSessions.repair(session.id)

Planning and session results are CONSTRUCT-side candidates. They do not mutate Ash business state and do not acquire DO authority by crossing the adapter.

BRCE: admission-only and receipted DO are separate

AshEx4pm exposes two intentionally different changes.

Admission-only: AshEx4pm.Changes.BrceGate

create :create do
change({AshEx4pm.Changes.BrceGate, operation: :create_order})
end

BrceGate performs pre-action admission with a pure placeholder callback. Its receipt proves admission, not the later Ash mutation. Use this when admission alone is the required boundary.

Receipted DO: AshEx4pm.Changes.ReceiptedAction

create :create do
change({AshEx4pm.Changes.ReceiptedAction, operation: :create_order})
end

ReceiptedAction installs an outermost around_action and runs the real Ash mutation inside Ex4pm.Evidence.BRCE.execute/5. The outcome receipt binds the real consequence digest, and the returned Ash record carries ash_ex4pm_receipt metadata. It also supports subject checks and idempotency.

The remaining boundary is narrower: the receipt is sealed inside the around_action transaction scope. A transactional commit failure after that hook returns is not yet captured and remains unverified for transactional data layers.

For update/destroy actions using ReceiptedAction, follow the module contract and set require_atomic? false.

Capability boundaries

The public capability graph currently includes:

No alternate wasm or planner semantics are implemented in AshEx4pm.

Non-goals

Verification

The repository CI runs mix verify: formatting, warnings-as-errors compilation, and the real test suite. v26.10.2 also tests the capability registry for unique IDs, real exported projection functions, documentation coverage, and the planner/DO separation.

License

MIT