Packages

Ash extension for automatic OCEL 2.0 event emission and an optional BRCE admission gate, built on ex4pm's real Ex4pm.Stream.Ingest.ingest_envelope/1 and Ex4pm.Evidence.BRCE.execute/4.

Current section

Files

Jump to
ash_ex4pm README.md
Raw

README.md

# 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:

~~~text
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

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

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

~~~elixir
{: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](docs/INDEX.md).

Canonical upstream documentation:

- [ex4pm Diátaxis reference](https://github.com/seanchatmangpt/ex4pm/blob/main/docs/diataxis/reference.md)
- [wasm4pm Diátaxis index](https://github.com/seanchatmangpt/wasm4pm/blob/main/docs/INDEX.md)
- [ferroplan planning types](https://github.com/seanchatmangpt/ferroplan/blob/main/docs/planning-types.md)
- [ferroplan FOND/HDDL semantics](https://github.com/seanchatmangpt/ferroplan/blob/main/docs/FOND-HTN.md)

## Minimal OCEL resource

Declare an ex4pm DSL block and explicitly register the notifier:

~~~elixir
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:

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

The important distinction is:

~~~text
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](docs/reference/capabilities.md).

## wasm4pm through AshEx4pm.WasmRuntime

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

Representative calls:

~~~elixir
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:

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

The stateful seam is AshEx4pm.FerroplanSessions:

~~~elixir
{: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

~~~elixir
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

~~~elixir
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:

- OCEL 2.0 event emission and object relationships;
- BRCE admission-only gating;
- BRCE-wrapped receipted Ash DO;
- wasm4pm algorithm discovery, statistics and forecasting through ex4pm;
- ferroplan stateless planning and production planning;
- stateful ferroplan sessions for think, repair, probe and replanning;
- Ex4pm.Engine.Result projection into Ash-friendly evidence;
- the canonical economic ISA adapter.

No alternate wasm or planner semantics are implemented in AshEx4pm.

## Non-goals

- Global notifier injection: add AshEx4pm.Notifier explicitly.
- Automatic Reactor middleware injection.
- Treating a plan, forecast, analysis result, or capability descriptor as
  execution authority.
- Claiming ALIVE solely because code or an upstream algorithm exists.
- Duplicating wasm4pm or ferroplan semantic registries.

## 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