LemonCore. Events
(lemon_core v0.1.0)
View Source
The registry of typed LemonCore.Bus payloads — the platform's wire format.
Each entry maps a LemonCore.Event type atom to the module describing its payload.
Publishing a registered type with a payload that is neither the right struct nor a map
is a bug; LemonCore.Bus.broadcast_event/3 catches it in :dev and :test.
Full catalog, migration order and the versioning rules live in
docs/platform/bus-events.md in the Lemon repository.
Scope
Only platform contract topics are registered — those whose payload crosses an app
boundary or reaches the control plane and its clients: run:<id>, session:<key>,
exec_approvals, cron, system, goals, routing_feedback.
Topics whose publisher and every subscriber live in one app (nodes, presence,
run_graph:*, parent_question:*, and the sim/arena family) are deliberately absent.
Their shapes are documented in their owning app; giving them core structs would push
domain types back into lemon_core.
Compatibility
Every payload module accepts a legacy free-form map through from_map/1, and implements
Access so consumers written against maps keep working for one deprecation cycle.
Summary
Functions
Coerce a payload to its registered struct, reporting why if it cannot be.
Coerce a payload to its registered struct, leaving unregistered types untouched.
Every payload module, published or nested.
Payload modules that are only ever nested inside another payload, never published alone.
The payload module for an event type, or nil if the type is not part of the contract.
Whether an event type is part of the typed platform contract.
Event type atom to payload module.
Functions
Coerce a payload to its registered struct, reporting why if it cannot be.
The strict counterpart to coerce/2. Use it at trust boundaries — anywhere a payload
arrives from outside the process that will publish it — so a malformed payload is refused
with a reason rather than broadcast as-is. Unregistered types pass through unchanged: they
have no declared shape to validate against.
iex> LemonCore.Events.cast(:secret_changed, %{"owner" => "u", "name" => "k", "action" => "put"})
{:ok, %LemonCore.Events.SecretChanged{owner: "u", name: "k", action: "put"}}
iex> {:error, reason} = LemonCore.Events.cast(:secret_changed, %{"owner" => "u"})
iex> reason =~ "SecretChanged"
true
Coerce a payload to its registered struct, leaving unregistered types untouched.
Consumers use this to accept both the struct and the legacy map during the migration:
payload = LemonCore.Events.coerce(:run_completed, event.payload)
@spec modules() :: [module()]
Every payload module, published or nested.
@spec nested_modules() :: [module()]
Payload modules that are only ever nested inside another payload, never published alone.
The payload module for an event type, or nil if the type is not part of the contract.
Whether an event type is part of the typed platform contract.
Event type atom to payload module.